-
Notifications
You must be signed in to change notification settings - Fork 0
/
mx
executable file
·94 lines (79 loc) · 2.91 KB
/
mx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#!/bin/sh
help() { cat <</help
Look up and parse MX record (or else A record; see RFC821) for given host(s)
Usge: mx [OPTIONS] host [host...]
-0, --as-is Do not clean up arguments. Assume hosts are valid.
-d, --dns=HOST Use HOST as the DNS server
Part of net-scripts: https://github.com/adamhotep/net-scripts
mx 0.6.20230923.1 Copyright 2010+ by Adam Katz, GPLv2+
/help
exit
}
# Defaults
as_is=
# in case column doesn't exist, create a dummy for it
if ! command -v column >/dev/null 2>&1; then column() { cat; }; fi
die() { echo "$*" >&2; exit 2; } # complain to STDERR and exit with error
needs_arg() { if [ -z "$OPTARG" ]; then die "No arg for --$OPT option"; fi; }
while getopts 0d:hvV-: OPT; do
if [ "$OPT" = - ]; then # long opt https://stackoverflow.com/a/28466267/519360
OPT="${OPTARG%%=*}" OPTARG="${OPTARG#$OPT}" OPTARG="${OPTARG#=}"
fi
case $OPT in
( 0 | as-is ) as_is="-0" ;;
( d | dns* ) needs_arg; dns="$OPTARG" ;;
( h* ) help ;;
( [Vv] | vers* ) help |tail -n2 ;;
( \? ) die "Try --help" >&2 ;;
( ??* ) die "Illegal option --$OPTARG ... Try --help" ;;
esac
done
shift $((OPTIND-1))
# very basic sanity check on the DNS server being legit (and okay to not quote)
case $dns in ( *[!A-Za-z0-9.-]* | [.-]* | *[.-][.-]* | *- )
die "Invalid DNS server '$dns'" ;;
esac
for host in "$@"; do
if [ "$host" != "$1" ]; then echo ""; fi # space betwen hosts
if [ $# -gt 1 ]; then echo "$host:"; fi # identify each host if 2+ hosts
if [ -z "$as_is" ]; then # cleanup
host="${host##*[<@]}" # remove username if present
while true; do # peel off bad chars from start
hh="${host#[!a-zA-Z0-9_.-]}" # [^...] now fails(!) using older [!...]
if [ "$hh" = "$host" ]; then break; fi
host="$hh"
done
host="${host%%[!a-zA-Z0-9_.-]*}" # remove trailing garbage
fi
host -t MX -- "$host" $dns |awk -v host="$host" -v dns="$dns" '
function dns_notes() {
return (NF==0 || /^(Using domain server|Name|Address|Aliases):/)
}
dns_notes() { next }
NF == 7 && $2$3$4$5 == "mailishandledby" {
pref[$NF] = $6
next
}
# RFC5321 5.1 says we fail over to the host itself if there is no MX:
# If an empty list of MXs is returned, the address is
# treated as if it was associated with an implicit MX RR,
# with a preference of 0, pointing to that host.
$3$4$5 == "noMXrecord" { pref[host] = 0 }
{ print > "/dev/stderr" }
#/\(NXDOMAIN\)/ { retval = 1 } # not usable thanks to sort filter
END {
for (mx in pref) {
cmd = "host -- " mx " " dns
while ( (cmd | getline) > 0) {
if (dns_notes() || $2 $3 $4 $5 == "mailishandledby") continue
if (index($NF,"(NXDOMAIN)")) {
$NF = "NXDOMAIN"
$1 = $2
}
printf "%4d %-15s %s\n", pref[mx], $NF, $1
}
close (cmd)
}
}
' |sort -k1n,1 -k3b,3 -k2n,2 |column -t
done