frater |
05-29-2009 11:38 AM |
chkdns / Questions about bash and sharing a script I wrote....
I wrote this script to monitor some records from a few providers I'm depending on. I initially wrote it just to monitor my sip-provider, but in the process I wanted to make it as fancy as possible...
In short... It compares a DNS-lookup to a previous one and mails you if something has changed.
I'm using "host" to get the records and "sendEmail" to mail.
The script is intended to be run as a cronjob, but if you run it from the console it shows you the records...
I would like to have some comments on my script because I want it as neat as possible.
I had some problems finding out if the program ran from console or from the cronjob. I don't want any output if nothing is wrong when it's running headless (procmail). I couldn't find any other way than this:
Code:
FROMCONSOLE=0
[ ! -z ${HISTSIZE} ] || [ "$TERM" == "xterm" ] && FROMCONSOLE=1
Anyone knows something better?
When run from console, I raise the debug level which gives me better control of the output.
I also had some problems with "sort". Somehow it sorted in a different way during a cronjob than when run from the console. I solved it by using the option "sort -db". I still think it's strange, but now it's solved I prefer to leave it like that... It did give me some headaches.
Because I want the most current info I'm asking the primary authorative nameserver first. host gives you 5 extra lines of info when you pass it a nameserver. I thought "tail" or "head" could do this for me and on the web I even found someone suggesting "head -n+5" but this didn't work on my Fedora Core 9 machine. Another suggestion was "more +5" which looked the perfect thing until I noticed it didn't work during a cronjob. I finally ended up writing it myself and came up with this:
Code:
tail -n$((`cat "${FTMP1}" | wc -l` - 5)) "${FTMP1}"
Anyone knows something better?
Code:
#!/bin/sh
# Author: JP van Melis
#
# Check a domain and report if the record has changed since you last generated a checkpoint (-r)
# It will check the SOA-record if the domain is a toplevel-domain.
# If not it will check the A-record unless it starts with an underscore (SRV) or you defined a type with -t
#
# Examples:
# chkdns domain.com check soa-record
# chkdns www.domain.com check A-record
# chkdns _sip._udp.domain.com check SRV-record
# chkdns -t mx domain.com check MX-record
# chkdns -r -t mx domain.com check MX-record and make a checkpoint
#
# It needs sendEmail (perl-script) to write you an eMail
# You can run it as a cronjob and it is intended as such.
# Then it will only send output if the records have changed so you can safely use procmail.
#
# I wrote it to check if my provider's SRV-records have changed.
#
# In /etc/cron.hourly you can put a script with this content:
#
# #!/bin/sh
# chkdns $* domain.com
# chkdns $* -t mx domain.com
# chkdns $* _sip._udp.domain.com
#
# If you run that script with the -r parameter it will write all the referenc-files
#
#
WRITE_REF=0
while getopts rt: name
do
case $name in
r) WRITE_REF=1;;
t) TYPE="$OPTARG";;
?) printf "Usage: %s: [-r] [-t TYPE] domain\n" $0
exit 2;;
esac
done
shift $(($OPTIND - 1))
if [ -z "$1" ] ; then
NAME=`basename $0`
else
NAME="$1"
fi
debug ()
{
if [ ! $DEBUG = 0 ]; then
echo "$*"
fi
}
# I noticed that HISTSIZE is almost always set when you are running it from console
# Some small busybox systems don't have a history so I let it be triggered by the $TERM variable
# If someone knows a better way to determine if it's run from console, please let me know.
FROMCONSOLE=0
[ ! -z ${HISTSIZE} ] || [ "$TERM" == "xterm" ] && FROMCONSOLE=1
DEBUG=0
# Raise debuglevel by 1 if the script is invoked from the console
[ ${FROMCONSOLE} == 1 ] && let DEBUG+=1
NAME=`echo "${NAME}" | tr '[A-Z]' '[a-z]'`
DOTS=`echo "${NAME}" | grep -o "\." | wc -l`
TOPLEVEL=`echo "$NAME" | egrep -o "[a-z0-9-]*\.[a-z][a-z]*$"`
debug "Domain: ${NAME}"
debug "Toplevel: ${TOPLEVEL}"
if [ -z $TOPLEVEL ]; then
echo "Not a valid domain name given"
exit 1
fi
_sendmessage ()
{
if [ ${DEBUG} -ne 0 ] ; then
echo -e "\n${MESSAGE}\n"
cat "${MESSAGE_FILE}"
echo -en "\n"
fi
if [ ${HAS_MAILER} -ne 0 ] ; then
[ ${DEBUG} -gt 1 ] && echo -e "Mailing this change to ${MAILTO}"
sendEmail -f $MAILFROM -s $SMTPS -t $MAILTO -o tls=no -o message-file="${MESSAGE_FILE}" -u "${MESSAGE}" -q
fi
}
if [ -z "${TYPE}" ]; then
TYPE=A
[ "`echo ${NAME} | cut -b1`" = "_" ] && TYPE=SRV
[ ${DOTS} = 1 ] && TYPE=SOA
else
TYPE=`echo "${TYPE}" | tr '[a-z]' '[A-Z]' | egrep -o "^[A-Z]*$"`
if [ -z "${TYPE}" ]; then
echo "This is not a valid record-type"
exit 1
else
if [ -z "`echo ".A.AAAA.CERT.CNAME.DNAME.DNSKEY.IPSECKEY.LOC.MX.NAPTR.NS.PTR.SOA.SPF.SRV.SSHFP.TXT." | egrep -o "\.${TYPE}\."`" ]; then
echo "${TYPE} is not a known record-type"
exit 1
fi
fi
fi
debug "Type: $TYPE"
if [ "$TYPE" = "SRV" ]; then
if [ ! "`echo ${NAME} | egrep -o "_[a-z]*\._[tu][cd]p\." | wc -l`" = 1 ] || [ ! "`echo ${NAME} | egrep -o "_" | wc -l`" = 2 ]; then
echo "This is not a valid SRV-record, try this: $0 -t srv _sip._udp.$TOPLEVEL"
exit 1
fi
fi
DAILY_WARNING=1
SMTPS="192.168.10.210"
MAILFROM="${USER}@${HOSTNAME}"
MAILTO="yourname@yourdomain.com"
MESSAGE_FILE="/tmp/${NAME}.${TYPE}.msg"
HAS_MAILER=0
[ ! -z "`which sendEmail 2>/dev/null`" ] && HAS_MAILER=1
REF="/var/run/${NAME}.${TYPE}.ref"
CUR="/var/run/${NAME}.${TYPE}.cur"
FTMP1="/tmp/${NAME}.${TYPE}.1.tmp"
FTMP2="/tmp/${NAME}.${TYPE}.2.tmp"
FTMP3="/tmp/${NAME}.${TYPE}.3.tmp"
#
# Determine which DNS-server to use
# It will try nameservers until it gets a valid reply.
# It will start with the Authorative NS, to get the most reliable answer.
#
host -t soa ${TOPLEVEL} | grep "has SOA record" | awk '{print $5}' >$FTMP1
host -t ns ${TOPLEVEL} | grep "name server" | awk '{print $4}' | sort -dbu >>$FTMP1
nNS=`cat ${FTMP1} | wc -l`
echo -e "208\.67\.220\.220\n" >>$FTMP1
try=1
cat $FTMP1 | while read NAMESERVER
do
[ $DEBUG -gt 1 ] && echo "Probing $NAMESERVER"
echo -e "$NAMESERVER" > $FTMP3
host -t soa ${TOPLEVEL} ${NAMESERVER} > $FTMP2
grep -q "has SOA record" $FTMP2 && break
let try+=1
done
NAMESERVER=`cat "$FTMP3"`
rm -rf "$FTMP1"
rm -rf "$FTMP2"
rm -rf "$FTMP3"
if [ ${try} == 1 ]; then
NSTYPE=" (primary Authorative)"
elif [ ${try} -le ${nNS} ]; then
NSTYPE=" (Authorative)"
elif [ ${try} -eq $((${nNS} + 1 )) ]; then
NSTYPE=" (OpenDNS)"
else
NSTYPE="(system)"
fi
debug "Lookup ${TYPE}-record of ${NAME} using nameserver: ${NAMESERVER}${NSTYPE}"
if [ $WRITE_REF = 1 ]; then
if [ -z "${NAMESERVER}" ]; then
host -t ${TYPE} ${NAME} | sort -dbo "${REF}"
else
host -t ${TYPE} ${NAME} ${NAMESERVER} >"${FTMP1}"
tail -n$((`cat "${FTMP1}" | wc -l` - 5)) "${FTMP1}" | sort -dbo "${REF}"
fi
exit 0
fi
if [ -z "${NAMESERVER}" ]; then
host -t ${TYPE} ${NAME} | sort -dbo "${CUR}"
else
host -t ${TYPE} ${NAME} ${NAMESERVER} >"${FTMP1}"
tail -n$((`cat "${FTMP1}" | wc -l` - 5)) "${FTMP1}" | sort -dbo "${CUR}"
fi
[ ${DEBUG} -ne 0 ] && cat "${CUR}"
if [ ! -f "${REF}" ]; then
echo -e "\nReference file does NOT exist.. Execute \"${0} -r ${NAME}\""
exit 1
else
DIFF="`diff "${REF}" "${CUR}"`"
REFDATE=`date +"%d-%m %H:%M" -r "${REF}"`
if [ -n "${DIFF}" ]; then
echo -e "Currently (`date +"%d-%m %H:%M"`) the answer from ${NAMESERVER}${NSTYPE} is:" >"${MESSAGE_FILE}"
cat "${CUR}" >>"${MESSAGE_FILE}"
echo -e "\r\nThe reference file (${REFDATE}) has this:" >> "${MESSAGE_FILE}"
cat "${REF}" >> "${MESSAGE_FILE}"
echo -e "\r\nIf you run \"${0} -r\", you can rewrite a reference file to stop these messages" >> "${MESSAGE_FILE}"
MESSAGE="${TYPE}-record of $NAME has changed!!!"
_sendmessage
elif [ "`date +%H`" == "00" ] && [ "`date +%M | cut -b1`" == "0" ] ; then
if [ ${DAILY_WARNING} -ne 0 ] ; then
MESSAGE="${TYPE}-record of $NAME is still the same as on ${REFDATE}"
cat "${CUR}" >"${MESSAGE_FILE}"
_sendmessage
fi
fi
rm -f "${MESSAGE_FILE}"
rm -f "${CUR}"
fi
rm -rf "$FTMP1"
rm -rf "$FTMP2"
rm -rf "$FTMP3"
exit 0
|