chatchai_j icon

reconf-exim4andbind

chatchai_j | PRO | 12/13/12 08:36:46 AM UTC | 0 ⭐ | 337 👁️ | Never ⏰ | []
Perl |

6.26 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 -q -A $ip";
 
    # then do it.
    open CMD, "$cmd |"
        or die "Can't execute command '$cmd'\n";
    my $ret = <CMD>;
    close CMD;
 
    # check the result.
    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;
            $ret = 1;
        } 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;
    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;
        }
 
        if (defined($zonelist{$zone}->{'ip'}) and 
            ($zonelist{$zone}->{'ip'} eq "$ip")) {
            $zonelist{$zone}->{'time'} = time();
            next;
        }
 
        $newzone++;
        $zonelist{$zone}->{'ip'} = $ip;
        $zonelist{$zone}->{'time'} = time();
        &logappend("$tstamp $ip $zone");
    }
 
    # Generate new config file only when there are new zone
    if ($newzone) {
        &newBindConf();
        &newExim4Conf();
    }
 
    $lastsize = (stat "$daemonlogfile")[7];
    do {
        sleep(10);
 
        if (&timeoutCheck()) {
            &newBindConf();
            &newExim4Conf();
        }
        $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 --- ]");
    }
}
close INPUT;
 
# --------------------------------------------------------------------- #
# end of file.                              #
# --------------------------------------------------------------------- #

Comments