Archive-name: logaxfr.sh-2013-is
Submitted-by:
onei...@gmail.com
Last-modified: 2013-04-27 19:14:11 +00:00
Copyright-Notice: Both the README and the code are under the
CC0 Public Domain Dedication.
[Followup-To: set to news:alt.sources.d, as per the
news:alt.sources' charter, and also news:comp.protocols.tcp-ip,
news:comp.unix.shell.]
Synopsis
$ [DIG=/where/is/dig] logaxfr PREFIX [LOGFILE]
Summary
This simplistic Bash script monitors the log file specified (or
/var/log/daemon.log by default) and executes dig(1) to perform
an AXFR query, saving its results under the prefix specified.
The initial part of the command to be executed can be passed via
the DIG environment variable, and defaults to "dig".
The log file's inode is periodically checked to remain the same.
Once it's changed, the log file is re-opened, so that this
script doesn't need to be restarted when the logs are rotated.
Please note that should the prefix given designate a directory,
a trailing slash (/) will be appended to it automatically.
(No such change is done otherwise.)
Assuming a prefix of "hist/axfr/" (or "hist/axfr"), the
resulting filename for the
example.org zone could be like:
hist/axfr/example.org-1368701214.axfr
Bugs
The AXFR query is sent to ::1 (the IPv6 localhost address)
irrespective of the actual log file data. The latter may
indicate a different host, should the host the script is run on
be collecting syslog data from other hosts as well.
The log entry parsers are rather crude.
It should be possible to specify the filename suffix, too.
Please also check the FIXME: comments within the code.
README.ykjymdfg98oh6fgsknarsdffon ends here
#!/bin/bash
### ykjymdfg98oh6fgsknarsdffon.sh -*- Sh -*-
### Ivan Shmakov, 2013
## To the extent possible under law, the author(s) have dedicated all
## copyright and related and neighboring rights to this software to the
## public domain worldwide. This software is distributed without any
## warranty.
## You should have received a copy of the CC0 Public Domain Dedication
## along with this software. If not, see
## <
http://creativecommons.org/publicdomain/zero/1.0/>.
### Code:
progname=${0##*/}
if [ $# -lt 1 -o $# -gt 2 ] ; then
printf 'Usage:\n %s PREFIX [LOGFILE]' >&2
exit 1
fi
p=${1}
s=.axfr
in=${2-/var/log/daemon.log}
: "${DIG:=dig}"
## FIXME: allow user to set these via CLI?
dig_options='@::1'
exec < "$in"
ino=$(stat -L -c %i -- -)
## NB: check if a directory is to be used
if test -d "$p" -a "$p" = "${p%/}" ; then
p=${p}/
fi
try_bind9 () {
## try_bind9 ${log-line} => [ sets ${zone} ${serial} ] matches?
local x="$1" se1 z1
## FIXME: too ad-hoc-ish an approach
case "$x" in
## BIND9 log message
(*/IN*serial*) ;;
(*) return 1 ;;
esac
## .
se1=${x##*serial } \
&& serial=${se1%%[^0-9]*} \
&& z1=${x%/IN*} \
&& zone=${z1##* } \
&& test -n "$zone" -a "$zone" != "$x" -a "$zone" != "$z1"
}
try_nsd3 () {
## try_nsd3 ${log-line} => [ sets ${zone} ${serial} ] matches?
local x="$1" se1 z1
## FIXME: too ad-hoc-ish an approach
case "$x" in
## NSD3 log message
(*Zone*serial*updated*to*) ;;
(*) return 1 ;;
esac
## .
se1=${x##*serial*updated*to } \
&& serial=${se1%%[^0-9]*} \
&& test "$serial". = "$se1" \
&& z1=${x% serial*} \
&& zone=${z1##* } \
&& test -n "$zone" -a "$zone" != "$x" -a "$zone" != "$z1"
}
declare -A -- zs ss
while : ; do
if ! read -r -t 5 -- x ; then
## check any of the zones are to be AXFR'ed
if [ "${#zs[@]}" -gt 0 ] ; then
date --rfc-3339=seconds >&2
for z in "${!zs[@]}" ; do
printf ' %-15s (%s)\n' "$z" "${ss[$z]}"
done >&2
for n in "${!zs[@]}" ; do
## FIXME: the output grep'ed may be unwanted
${DIG} ${dig_options} axfr "$n" \
| tee -- "${p}${n}-$(date +%s)${s}" \
| grep -F -- SOA
done
zs=()
fi
sleep 7s
## check if the log file needs to be reopened
## FIXME: better error detection?
inew=$(stat -L -c %i -- - < "$in") \
|| continue
if [ "$inew" != "$ino" ] ; then
## NB: inew may change here; avoid TOCTTOU
exec < "$in"
inew=$(stat -L -c %i -- -)
date --rfc-3339=seconds >&2
printf ' reopen %s (%s; was: %s)\n' \
"$in" "$inew" "$ino" >&2
ino=${inew}
fi
continue
fi
if try_bind9 "$x" \
|| try_nsd3 "$x" ; then
if [ "$serial" != "${ss[$zone]}" ] ; then
zs[$zone]=1
fi
ss[$zone]=${serial}
fi
done
### Emacs trailer
## Local variables:
## coding: us-ascii
## fill-column: 72
## indent-tabs-mode: nil
## ispell-local-dictionary: "american"
## End:
### ykjymdfg98oh6fgsknarsdffon.sh ends here
--
FSF associate member #7257