Copyright 2024 - CSIM - Asian Institute of Technology

Based upon DNS graph by Nathan Campi

In his scripts for graphing DNS activity, Nathan is proposing a workaround for Bind 9.The need for a workaround arises because with Bind 8 the statistics kept by named used to include the number of queries received by the server for each type of query, it was easy to retreive the data from the statistics of named to draw the graph; whileBind 9 do not collect such data anymore, they should be collected by logging all the queries and calculating statistics.

Nathan proposes to log the queries to stderr and run named though a shell script; the script will read from stderr.

I don't like that solution because:

  • named is not started in the regular fashion, that could cause incompatibilities when system is upgraded (many system upgrade cause named upgrade);
  • named would fail in case the sheel script fails;

While at same time, named knows how to log the queries to a separate file and it includes builtin a mechanism to rotate the file when it reaches a certain size a Perl module like File::Tail knows how to read from a file that get rotated like syslog files or this named quey log file.

The solution I propose decribed bellow.

Log the queries to a file

Configure Bind 9 to log all the queries to a file. In the example bellow, the file is called query-log, it rotates everytime the file grows over 1 MB and named keeps up to three backup versions of the file.

 

logging {
        channel query-log {
                          file "query-log" versions 3 size 1m;
        };
        category queries {
                         query-log;
                         };
        ... rest of named logging configuration
};
options {
        querylog yes;
        ... rest of named options

 
Example of named.conf configuration file for Bind 9

There will be up to four files created in named default directory, query-logquery-log.0query-log.1 and query-log.2. The file that contains the most recent queries is query-log.

Examine the log file and collect statistics

The following Perl script uses the module File::Tail to read the file event when it rotates, it computes the number of queries by type.

The script saves its own PID in the file $pidfile. Upon receiving a hang-up signal, it writes the statistics in the file $dumpfile. The $log_wait_interval is used by File::Tail to set the tick clock when the Perl script should become active and try to read new entries in the log file.

This script should loop indefinitely, it should be launch at boot time (use your prefered method to launch that script).

  #!/usr/local/bin/perl
$logfile = "/var/chroot/named/etc/named/query-log"; # where to read the queries
$dumpfile="/var/run/bind9_stats_count.dump"; # where to write the statistics
$pidfile="/var/run/bind9_stats_count.pid"; # where to write the PID
$log_wait_interval=1; # tick clock for reading the query log file

use File::Tail;

$SIG{'HUP'}='dump';
open OUT, ">$pidfile";
print OUT $$;
close OUT;
@query_list=("A", "PTR", "ANY", "MX", "NS", "CNAME", "SOA", "SRV", "AAAA");


sub init{
    foreach $i (@query_list) {
        $query{$i}=0;
    }
}

sub dump {
    # dump the statistics when receiving a HUP signal
    my $total=0;
    open OUT, ">$dumpfile";
    flock OUT, 2;
    foreach $i (@query_list) {
        print OUT "$query{$i} ";
        $total+=$query{$i};
    }

    print OUT "$total\n";
    flock OUT, 8;
    close OUT;
    init();
}

sub getlogline {
    # The first time we're called; open the logfile, skip to the end,
    # and remember the inode we opened.
    if (!defined($lffd)) {
        $lffd = File::Tail->new(name=>$logfile, maxinterval=>5,
        interval=>$log_wait_interval);
        if (!defined($lffd)) {
            die "Can't open $logfile\n";
        }
    }
    return $lffd->read;
}

init();
while ($line=getlogline) {
    # regexpr to read a query from the log file
    next unless $line=~
        /^client\s+\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\#\d+:\s+query:\s+.*\s+IN\s+([A-Z]+)\s+/;
    $query{$1}++;
}
 
The script count_stat should be started at boot time

The display-bindstats.pl script

It corresponds to the script use for Bind 8 on Nathan's page. But to collect the statistics, it only has to send an hang-up signal to the script above and read the data from the file as designed in $dumpfile.

#!/bin/sh
kill -1 `/bin/cat /var/run/bind9_stats_count.pid`
/bin/sleep 2
/bin/cat /var/run/bind9_stats_count.dump
The script /usr/local/sbin/display-bindstats.pl

This script is called by SNMP in the exact way defined on Nathan's page for Bind 8.

Integration with SMF under Solaris

The following modification has been suggested to me by Robert Jansen from Brussels University:

  To have this e.g. integrated under SMF under Solaris, one can define the
start method in the xml. manifest as follows:

snip....
<exec_method
        type='method'
        name='start'
        exec='/usr/local/packages/bindstats/count_stat &'

.....

snip......

but,... the "count_stat" script returns a value where the Solaris SMF
facility isn't to happy about,... namely "256" and thinks the script is
"offline".

By adding "return 0;" at the end of your script, Solaris's SMF will think
this service is online.
It's a workaround.

snip.....

init();
while ($line=getlogline) {
    # regexpr to read a query from the log file
    next unless $line=~
        /^client\s+\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\#\d+:\s+query:\s+.*\s+IN\s+([A-Z]+)\s+/;
    $query{}++;
}
return 0;
 
Integration in SMF under Solaris

Login Form

Search

School of Engineering and technologies     Asian Institute of Technology