+#!/bin/bash
+
+set -e
+
+id=$(date +%s)_$$
+
+fail () {
+ printf >&2 "%s\n" "modrelays-probe: error: $1"
+ exit 16
+}
+
+record-probing () {
+ # implicitly uses newsgroup, id, domain
+ # prints working dir filename
+ local probeid=$1
+
+ probeid=${probeid//[^=-.,_0-9A-Za-z]/%/}
+ case $probeid in
+ .*|*/*) fail "yikes, sanitisation bug!" ;;
+ esac
+
+ local newtd="monitoring/modrelays.probes/$probeid"
+ mkdir -p $newtd
+ printf "%s" $newtd
+}
+
+record-outcome () {
+ local probeid=$1
+ local outcome=$2
+ local message=$3
+ local td=`record-probing "$probeid"`
+ printf "%s\n" >"$td"/"$outcome"
+}
+
+record-success () { record-outcome "$1" ok '' }
+record-tempfail () { record-outcome "$1" tempfail "$2" }
+record-permfail () { record-outcome "$1" permfail "$2" }
+
+probe-addr () {
+ local mx=$1
+ local addr=$2
+
+ local td=`record-probing "mx=$mx,addr=$addr"`
+
+ set +e
+ swaks --to "${GROUP//./-/}@$domain" \
+ --server $addr \
+ --tls-optional-strict \
+ --header 'Subject: test modrelays probe test' \
+ --header \
+ "X-WebSTUMP-Relay-Probe: $GROUP $id $domain $mx $addr" \
+ -n >$td/swaks.log 2>$td/swaks.err
+ rc=$?
+ set -e
+
+ case $rc in
+ 0) return ;; # record-success done by receiver
+ esac
+ local permfail=''
+
+ local rhs
+ local prefix
+ local expect_no_5xx='initial connection'
+ while read <$td/swaks.log prefix rhs; do
+ case "$prefix" in
+ '<'*)
+ case "$rhs" in
+ 5*)
+ if [ "x$expect_no_5xx" != x ] && \
+ [ "x$permfail" = x ]; then
+ permfail="$rhs ($expect_no_5xx)" ;;
+ fi
+ ;;
+ esac
+ ;;
+ *'>')
+ case "$rhs" in
+ EHLO*|STARTTLS*) expect_no_5xx='' ;;
+ *) expect_no_5xx="after $rhs" ;;
+ esac
+ ;;
+ *)
+ done
+
+ if [ "x$permfail" = x ]; then
+ record-tempfail "mx=$mx,addr=$addr" "see swaks.log / swaks.err"
+ else
+ record-permfail "mx=$mx,addr=$addr" "$permfail"
+ fi
+}
+
+probe-domain () {
+ local domain=$1
+ local td=`record-probing dns`
+
+ set +e
+ adnshost -Fi -Tn +Do +Dt -t mx $domain >$td/dns
+ rc=$?
+ set -e
+
+ case $rc in
+ 0)
+ # have a list of MX's
+ exec <$td/dns
+ local pref
+ local mx
+ local statustype
+ local rhs
+ while read pref mx statustype rhs; do
+ case $statustype in
+ 0)
+ # have a list of relays
+ case $rhs in
+ *" ( "*")") ;;
+ *)
+ record-permfail "mx=$mx" \
+ "dns format $rhs"
+ continue
+ ;;
+ rhs=${rhs%%* (}
+ rhs=${rhs# )}
+ local addr
+ for addr in $rhs; do
+ case $addr in
+ INET|INET6) continue ;;
+ esac
+ probe-addr $mx $addr
+ done
+ ;;
+ [123])
+ # temporary errors
+ record-tempfail "mx=$mx" "dns $rc $rhs"
+ ;;
+ *)
+ # yikes
+ record-permfail "mx=$mx" "dns $rc $rhs"
+ ;;
+ esac
+ done
+ record-success dns
+ return
+ ;;
+ 6)
+ permfail, try A
+ set +e
+ adnshost -Fi -Tn +Do +Dt -t a $domain >$td
+ rc=$?
+ set -e
+ ;;
+ esac
+
+ case $rc in
+ 0)
+ # have a list of A's (dealt with MXs above)
+ exec <$td/dns
+ local addr
+ while read addr; do
+ probe-addr '<no-mx>' $addr
+ done
+ record-success dns
+ return
+ ;;
+ [123])
+ local emsg
+ read <$td/dns emsg
+ record-tempfail dns "dns <no-mx> $emsg"
+ ;;
+ *)
+ local emsg
+ read <$td/dns emsg
+ record-permfail dns "dns <no-mx> $emsg"
+ ;;
+ esac
+}
+
+no_args () {
+ case $1 in
+ 0) return ;;
+ *) fail
+
+mode_all () {
+ no_args $#
+ for domain in $MODRELAYS; do
+ probe $domain
+ done
+}
+
+mode_auto () {
+ no_args $#
+ xxx do something to cause sleeping
+ mode_all
+}
+
+mode_relay () {
+ relay="$1"
+ probe "$relay"
+}
+
+mode=$1; shift||:
+
+"mode_$mode" "$@"