#!/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 '' $addr done record-success dns return ;; [123]) local emsg read <$td/dns emsg record-tempfail dns "dns $emsg" ;; *) local emsg read <$td/dns emsg record-permfail dns "dns $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" "$@"