chatchai_j icon

reconf-exim4andbind

chatchai_j | PRO | 12/14/12 06:28:39 AM UTC | 0 ⭐ | 326 👁️ | Never ⏰ | []
Perl |

8.27 KB

|

None

|

0 👍

/

0 👎

#!/usr/bin/perl -w-
 
# --------------------------------------------------------------------- #
# reconf-exim4andbind   - Modify named.conf.local and reconfig named    #
#                         when necessary. This is intended to allow     #
#                         lsa-svr to forward DNS request from outside   #
#                         to students' VM, by monitoring update request #
#                         that will generate 'no authoritative' message #
#                         in daemon.log file.                           #
#                       - Plus add exim4 relay_domains config.          #
#                                                                       #
## version 0.1  - cj (2012-11-28) init.                                 #
## version 0.2  - cj (2012-12-02) modified form gen-lsa-namedconflocal  #
## version 0.2a - cj (2012-12-11) some cosmetic added.                  #
# version 0.3   - cj (2012-12-13) change to reconf-exim4andbind         #
# --------------------------------------------------------------------- #
 
use strict;
 
my $exim4updateconf = "/var/cache/exim4/update-exim4.conf.conf";
my $namedconflocal = "/var/cache/bind/conf/named.conf.local";
my $daemonlogfile = "/var/log/daemon.log";
my $namedconfnewfile = "${namedconflocal}.new";
my $exim4confnewfile = "${exim4updateconf}.new";
my $logfile = "/var/log/named/reconf-dnsandmail.log";
 
my %zonelist = ();
my %tm = ();            # last seen for that specific zone
my $TOO_OLD = 600;      # Number of seconds since last seen
 
# Append log message to log file
sub     logappend() {
        my ($mesg) = @_;
        my $DATE  = `date "+%Y%m%d %H:%M:%S"`; chomp($DATE);
        open LOG, ">> $logfile" or die "Can't append to log file : $!\n";
        print LOG "$DATE\t$mesg\n";
        close LOG;
}
 
# Check whether that provide IP is alive by using icmp 'ping' check
sub     isAlive() {
        my ($ip) = @_;
 
        # Make sure that the IP is defined and actual ip number
        # before send it to fping command.
        return 0 unless defined($ip);
        return 0 unless $ip =~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/;
        my $cmd = "fping -a $ip 2> /dev/null";
 
        # then do it.
        open CMD, "$cmd |"
                or die "Can't execute command '$cmd'\n";
        my $ret = <CMD>;
        close CMD;
 
        # check the result.
        return 0 unless defined($ret);
        chomp($ret);
        return "$ip" eq "$ret";
}
 
# Generate new named.conf.local file, and run "rndc reconfig"
sub     newBindConf() {
        my $date = `date "+%Y-%m-%d %H:%M"`;
        chomp($date);
 
        if (-f $namedconfnewfile ) { unlink $namedconfnewfile; }
        die "Can't remove old '$namedconfnewfile', bail out!\n" if (-f $namedconfnewfile );
 
        my $zonecount = 0;
        open OUTPUT, "> $namedconfnewfile" or die "Can't create '$namedconfnewfile' : $!\n";
        for my $zone (keys %zonelist) {
                my $ip = $zonelist{$zone}->{'ip'};
                $zonecount ++;
                print OUTPUT << "EOT";
zone "$zone" { type forward; forward only; forwarders { $ip; }; };
EOT
        }
        close OUTPUT;
 
        $date =~ s/[-: ]//g;
 
        # New named.conf.local file
        rename $namedconflocal, "${namedconflocal}-${date}"
                or die "Can't backup original $namedconflocal file\n";
        rename $namedconfnewfile, $namedconflocal
                or die "Can't rename new $namedconflocal file\n";
        system("rndc reconfig");
        &logappend("Generate new Bind config with $zonecount zones ...");
}
 
# Generate new update-exim4.conf.conf file, and run "service exim4 reload"
sub     newExim4Conf() {
        my $date = `date "+%Y-%m-%d %H:%M"`;
        chomp($date);
 
        if (-f $exim4confnewfile ) { unlink $exim4confnewfile; }
        die "Can't remove old '$exim4confnewfile', bail out!\n" if (-f $exim4confnewfile );
 
        my $newrelaydomains = "";
        my $zonecount = 0;
        for my $zone (keys %zonelist) {
                $newrelaydomains .= "$zone;";
                $zonecount ++;
        }
        chop($newrelaydomains); # get rid of the last ';'
        $date =~ s/[-: ]//g;
 
        # New update-exim4.conf.conf file
        open CONF, "$exim4updateconf" or die "Can't open $exim4updateconf file : $!\n";
        open OUTPUT, "> $exim4confnewfile" or die "Can't create $exim4confnewfile : $!\n";
        while (<CONF>) {
                if (!/^dc_relay_domains/) {
                        print OUTPUT $_;
                        next;
                }
                print OUTPUT "dc_relay_domains='$newrelaydomains'\n";
        }
        close OUTPUT;
        close CONF;
 
        rename $exim4updateconf, "${exim4updateconf}-${date}"
                or die "Can't backup original $exim4updateconf file\n";
        rename $exim4confnewfile, $exim4updateconf
                or die "Can't rename new $exim4updateconf file\n";
        system("sudo service exim4 reload");
        &logappend("Generate new Exim4 config with $zonecount zones ...");
}
 
# Timeout Check for zonelist
sub     timeoutCheck() {
        my $now = time();
        my %newzonelist = ();
        my $ret = 0;
        for my $zone (keys %zonelist) {
                my $ip = $zonelist{$zone}->{'ip'};
                my $t = $zonelist{$zone}->{'time'};
                if (&isAlive($ip)) {
                        $newzonelist{$zone}->{'ip'} = $ip;
                        $newzonelist{$zone}->{'time'} = $now;
                } elsif (($now - $t) < $TOO_OLD) {
                        $newzonelist{$zone}->{'ip'} = $ip;
                        $newzonelist{$zone}->{'time'} = $t;
                } else {
                        $ret = 1;
                }
        }
        %zonelist = %newzonelist;
 
        return $ret;
}
 
# Regular expression for match 'not authoriative' line.
my $MSTR =      "(.{15}) lsa-svr named\[[0-9]+\]: " .
                "client ([\.0-9]+)#[0-9]+: received notify for zone " .
                "'([^']+)': not authoritative\$";
 
my ($lastsize, $thissize);
open INPUT, "$daemonlogfile" or die "Can't open '$daemonlogfile' : $!\n";
while (1) {
        my $newzone = 0;
        my $zonetimeout = 0;
        my %tmpzonelist = ();
 
        while (my $line = <INPUT>) {
                chomp($line);
                next unless $line =~ /received notify for zone/ ;
                my ($tstamp,$ip,$zone) = ($line =~ /$MSTR/);
 
                if (!defined($tstamp) or !defined($ip) or !defined($zone)) {
                        &logappend("ERROR:[$line]");
                        next;
                }
 
                $tmpzonelist{$zone}->{'ip'} = $ip;
                &logappend("$tstamp $ip $zone");
                print "LOG: $tstamp $ip $zone\n";
        }
 
        for my $zone (keys %tmpzonelist) {
                my $ip = $tmpzonelist{$zone}->{'ip'};
                if (&isAlive($ip)) {
                        $newzone++;
                        my $t = time();
                        $zonelist{$zone}->{'ip'} = $ip;
                        $zonelist{$zone}->{'time'} = $t;
                        print "ZONE: $t $ip $zone\n";
                }
        }
 
        $lastsize = (stat "$daemonlogfile")[7];
        do {
                # Generate new config file only when there are new zones
                # or host for that zone is not active for sometimes.
                if (&timeoutCheck() or $newzone) {
                        &newBindConf();
                        &newExim4Conf();
                        $newzone = 0;
                }
                sleep(10);
                $thissize = (stat "$daemonlogfile")[7];
        } while ($lastsize == $thissize);
 
        if ($thissize < $lastsize) {
                close INPUT;
                open INPUT, "$daemonlogfile" or
                        die "Can't open '$daemonlogfile' : $!\n";
                &logappend("[ --- Reopen new daemon.log file --- ]");
                print "LOG: --- new daemon.log ---\n";
        }
}
close INPUT;
 
# --------------------------------------------------------------------- #
# end of file.                                                          #
# --------------------------------------------------------------------- #

Comments