LinuxQuestions.org
Visit Jeremy's Blog.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 05-29-2009, 11:38 AM   #1
frater
Member
 
Registered: Jul 2008
Posts: 121

Rep: Reputation: 23
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
 
Old 05-29-2009, 01:20 PM   #2
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,774

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
Quote:
When run from console, I raise the debug level which gives me better control of the output.
From the bash manual:
Code:
INVOCATION
...
       An  interactive  shell is one started without non-option arguments and without the -c
       option whose standard input and error are both connected to terminals (as  determined
       by  isatty(3)),  or  one started with the -i option.  PS1 is set and $- includes i if
       bash is interactive, allowing a shell script or a startup file to test this state.
Or you could use tty which tells you if standard in is connected to a terminal.

However, I would suggest controlling debug level with an option: you've seen that it's annoying when commands act differently depending on context, so you should avoid doing this when writing your own commands.

Also you should probably echo debug output to standard error.

Quote:
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.
"tail -n+5" should give everything from line 5 and onward.


Code:
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
Because you used "|" this command actually runs in a new subshell, so the try variable in the main script doesn't get incremented. You can use redirection instead:

Code:
while read NAMESERVER
do
...
done < $FTMP1
Code:
FTMP1="/tmp/${NAME}.${TYPE}.1.tmp"
If more than one instance of this script is run, they will overwrite these temp files. The classic solution is to use $$ in the filename. $$ expands to the process id of the shell which is unique for every run.
 
1 members found this post helpful.
Old 05-29-2009, 02:09 PM   #3
jan61
Member
 
Registered: Jun 2008
Posts: 235

Rep: Reputation: 47
Moin,

Quote:
Originally Posted by ntubski View Post
...
Code:
FTMP1="/tmp/${NAME}.${TYPE}.1.tmp"
If more than one instance of this script is run, they will overwrite these temp files. The classic solution is to use $$ in the filename. $$ expands to the process id of the shell which is unique for every run.
I'd prefer mktemp instead of using the process id to avoid race conditions.

Jan
 
1 members found this post helpful.
Old 05-30-2009, 02:06 AM   #4
frater
Member
 
Registered: Jul 2008
Posts: 121

Original Poster
Rep: Reputation: 23
At first I thought it was a bit strange to let my code get examined in this way, but I'm glad I did as it was quite educational. I can only hope there was something in it for you as well.

Quote:
"tail -n+5" should give everything from line 5 and onward.
As I wrote, I tested this, but.....
I'm a believer so I tested it again. It DOES work.
I don't really understand what happened when I tried it before...
Must have been too tired..
changed....
Code:
host -t ${TYPE} ${NAME} ${NAMESERVER} | tail -n+6 | sort -dbo "${REF}"
PS I think I know why I thought it didn't work. I probably tried "tail -n+1" and expected it to skip the first line, which it didn't.


Quote:
However, I would suggest controlling debug level with an option:
Code:
DEBUG=0
while getopts rvt: name
do
  case $name in
    r)   WRITE_REF=1;;
    t)   TYPE="$OPTARG";;
    v)   let DEBUG+=1;;
    ?)   printf "Usage: %s: [-r] [-t TYPE] [-v] domain\n" $0
    exit 2;;
  esac
done
shift $(($OPTIND - 1))
Quote:
you've seen that it's annoying when commands act differently depending on context, so you should avoid doing this when writing your own commands.
I'm gonna pass on this advice for this script, although I think you're right. In this script I'm combining "verbosity" with "debuginfo" which is not good a thing. I Will think of a better structure in my next script.

Quote:
Also you should probably echo debug output to standard error.
Code:
verbose ()
{
if [ ! $VERBOSE = 0  ]; then
  echo "$*"
fi
}
debug ()
{
if [ ! $DEBUG = 0  ]; then
  echo "$*" >&2
fi
}
Quote:
Or you could use tty which tells you if standard in is connected to a terminal.
Code:
HEADLESS=0
! tty | grep -q pts && HEADLESS=1

# Raise debuglevel by 1 if the script is invoked from the console
[ ${HEADLESS} == 0 ] && let DEBUG+=1

Quote:
Because you used "|" this command actually runs in a new subshell, so the try variable in the main script doesn't get incremented. You can use redirection instead:
I already noticed that behaviour, but didn't know the exact reason. I thought it had to do with the while loop. Because of that I already saved $NAMESERVER to a file... I casually added $try later on (forgot this behaviour) and never noticed it wasn't working because it's quite exceptional the loop runs more than 1 time.
big THANKS!

Changed
Code:
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"`
into
Code:
try=1
while read NAMESERVER
do
  [ $DEBUG -gt 1 ] && echo "Probing $NAMESERVER" >&2
  host -t soa ${TOPLEVEL} ${NAMESERVER} > $FTMP2
  grep -q "has SOA record" $FTMP2 && break
  let try+=1
done <$FTMP1
Quote:
I'd prefer mktemp instead of using the process id to avoid race conditions.
Looks better, yes...
Code:
FTMP1=`mktemp`
FTMP2=`mktemp`
FTMP3=`mktemp`
Current code:

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
#
#
DEBUG=0
VERBOSE=0
WRITE_REF=0
while getopts rvt: name
do
  case $name in
    r)   WRITE_REF=1;;
    t)   TYPE="$OPTARG";;
    v)   let DEBUG+=1
         VERBOSE=1
         ;;
    ?)   printf "Usage: %s: [-r] [-t TYPE] [-v] domain\n" $0
         exit 2
         ;;
  esac
done
shift $(($OPTIND - 1))

if [ -z "$1" ] ; then
  NAME=`basename $0`
else
  NAME="$1"
fi

verbose ()
{
if [ ! $VERBOSE = 0  ]; then
  echo "$*"
fi
}
debug ()
{
if [ ! $DEBUG = 0  ]; then
  echo "$*" >&2
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.
HEADLESS=0
! tty | grep -q pts && HEADLESS=1

# Raise debuglevel by 1 if the script is invoked from the console
[ ${HEADLESS} == 0 ] && 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.25"
MAILFROM="${USER}@${HOSTNAME}"
MAILTO="yourmail@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=`mktemp`
FTMP2=`mktemp`
FTMP3=`mktemp`
#
# 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
while read NAMESERVER
do
  [ $DEBUG -gt 1 ] && echo "Probing $NAMESERVER"
  host -t soa ${TOPLEVEL} ${NAMESERVER} > $FTMP2
  grep -q "has SOA record" $FTMP2 && break
  let try+=1
done <$FTMP1

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

verbose "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} | tail -n+6 | sort -dbo "${REF}"  fi
  exit 0
fi

if [ -z "${NAMESERVER}" ]; then
  host -t ${TYPE} ${NAME} | sort -dbo "${CUR}"
else
  host -t ${TYPE} ${NAME} ${NAMESERVER} | tail -n+6 | 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

Last edited by frater; 05-30-2009 at 03:34 AM. Reason: changed lines with host
 
Old 05-31-2009, 01:46 PM   #5
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,774

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
Quote:
Originally Posted by frater View Post
Quote:
"tail -n+5" should give everything from line 5 and onward.
As I wrote, I tested this, but.....
I'm a believer so I tested it again. It DOES work.
I don't really understand what happened when I tried it before...
Must have been too tired..
Well in your post you wrote "head -n+5" which would give only the first 5 lines...

Code:
HEADLESS=0
! tty | grep -q pts && HEADLESS=1
You don't need grep (and grep'ing for pts only works on terminal emulators):
Code:
tty -s || HEADLESS=1
 
1 members found this post helpful.
Old 06-08-2009, 02:56 PM   #6
frater
Member
 
Registered: Jul 2008
Posts: 121

Original Poster
Rep: Reputation: 23
Thanks...

I did change it into
Code:
HEADLESS=0
tty >/dev/null || HEADLESS=1
as "-s" isn't always supported....

Only now I fully realize the trick with && and ||

If && is used and the expression is non-zero it needs to execute the next command. If || is used it already is satisfied and skips it....

No need to use the "NOT" statement

Thanks

Nunca a tu cama iras sin saber una cosa más
 
Old 03-20-2010, 10:47 AM   #7
frater
Member
 
Registered: Jul 2008
Posts: 121

Original Poster
Rep: Reputation: 23
Over time I changed a bit of the code.
If anyone is using it they can take this as the latest code.

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
#
#
DEBUG=0
VERBOSE=0
WRITE_REF=0
while getopts rvt: name
do
  case $name in
    r)   WRITE_REF=1;;
    t)   TYPE="$OPTARG";;
    v)   let DEBUG+=1
         let VERBOSE+=1
         ;;
    ?)   printf "Usage: %s: [-r] [-t TYPE] [-v] domain\n" $0
         exit 2
         ;;
  esac
done
shift $(($OPTIND - 1))

if [ -z "$1" ] ; then
  NAME=`basename $0`
else
  NAME="$1"
fi

verbose ()
{
if [ ! $VERBOSE = 0  ]; then
  echo "$*"
fi
}
debug ()
{
if [ ! $DEBUG = 0  ]; then
  echo "$*" >&2
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.
HEADLESS=0
# ! tty | grep -q pts && HEADLESS=1
tty >/dev/null || HEADLESS=1

# Raise debuglevel by 1 if the script is invoked from the console
[ ${HEADLESS} == 0 ] && let DEBUG+=1
NAME=`echo "${NAME}" | tr '[A-Z]' '[a-z]'`
! echo "${NAME}" | grep -q ".*\.$" && NAME="${NAME}."
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}"

    SMTP_LISTENS=1
    if [ ! -z "`which nmap`" ] ; then
      SMTP_LISTENS=`nmap -P0 -n -p ${PORT} ${SMTPS} 2>/dev/null | grep -c open`
    fi
    if [ ${SMTP_LISTENS} -eq 0 ] ; then
      echo "Port ${PORT} of SMTP-server ${SMTPS} is not open... I can NOT send an email" >&2
    else
      sendEmail -f $MAILFROM -s $SMTPS:$PORT -t $MAILTO -o tls=no -o message-file="${MESSAGE_FILE}" -u "${MESSAGE}" -q
    fi
  else
    echo "I have no mailer!"
  fi
}

if [ -z "${TYPE}" ]; then
  TYPE=A
  [ "`echo ${NAME} | cut -b1`" = "_" ] && TYPE=SRV
  [ ${DOTS} -le 2 ] && 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.25"
MAILFROM="${USER}@${HOSTNAME}"
MAILTO="yourmail@yourdomain.com"
PORT=25
MESSAGE_FILE="/tmp/${NAME}${TYPE}.msg"
HAS_MAILER=0
[ ! -z "`which sendEmail 2>/dev/null`" ] && HAS_MAILER=1

REF="/var/log/${NAME}${TYPE}.ref"
CUR="/var/log/${NAME}${TYPE}.cur"
FTMP1=`mktemp`
FTMP2=`mktemp`
FTMP3=`mktemp`
#
# 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.
#
# First ask system to get a list of nameservers (NOTE: it may ask several nameservers itself)
#
SOA=`host -t soa ${TOPLEVEL} | grep -i "has SOA record" | head -n1 | awk '{print $5}'`
host -t  ns ${TOPLEVEL} | grep "name server" | awk '{print $4}' | sort -uo $FTMP1
if [ ! -z "${SOA}" ] ; then
  echo "${SOA}" >$FTMP3
  grep -v "${SOA}" "${FTMP1}" >>$FTMP3
  echo "${SOA}" >>$FTMP3
fi
nNS=`cat ${FTMP3} | wc -l`              # Amount of native NS's
echo -en "208.67.220.220\n\n" >>$FTMP3  # Add the OpenDNS IP and a newline (for system) as an alternative

if [ $DEBUG -gt 1 ] ; then
  echo "List of nameservers to probe"
  n=1
  while read NAMESERVER
  do
    echo -n "${n}. ${NAMESERVER}"
    [ $n -le $nNS ] && echo -n " (Authorative)"
    echo ""
    let n+=1
  done<$FTMP3
fi

try=1
while read NAMESERVER
do
  [ $DEBUG -gt 1 ] && echo "Probing $NAMESERVER"
  # host -t soa ${TOPLEVEL} ${NAMESERVER} > $FTMP2
  # grep -iq "has SOA record" $FTMP2 && break # Found a nameserver
  host -t ns ${TOPLEVEL} ${NAMESERVER} > $FTMP2
  grep -iq " name server " $FTMP2 && break # Found a nameserver
  let try+=1
  sleep 1
done <$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

verbose "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} | tail -n+6 | sort -dbo "${REF}"
  fi
  exit 0
fi

if [ -z "${NAMESERVER}" ]; then
  host -t ${TYPE} ${NAME} | sort -dbo "${CUR}"
else
  host -t ${TYPE} ${NAME} ${NAMESERVER} | tail -n+6 | 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="Host \"${HOSTNAME}\" reports: ${TYPE}-record of $NAME has changed!!!"
    _sendmessage
  elif [ "`date +%H`" == "00" ] && [ "`date +%M | cut -b1`" == "0" ] ; then
    if [ ${DAILY_WARNING} -ne 0 ] ; then
      MESSAGE="Host \"${HOSTNAME}\" reports: ${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
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Need help debugging a script I wrote kaplan71 Linux - Software 6 06-27-2007 02:28 PM
Bash script questions. ArthurHuang Programming 6 03-20-2007 10:59 PM
Just a little backup script I wrote which does what I want it to pwc101 LinuxQuestions.org Member Success Stories 5 09-29-2006 08:11 AM
Bash script programming questions dianea Linux - Newbie 4 03-03-2004 12:17 AM
not that anyone cares but... here's a free decompression script i wrote versaulis Linux - Software 8 11-23-2003 02:21 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 02:21 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration