Script to monitor DNS logs

Below is a perl script written to monitor DNS log files for three events

  1. SERVFAIL Messages: If a zone's data is stale, you could see this type of error
  2. REFUSED Messages: Could refer to failed zone transfers
  3. Zone Transfers: Will match on successful zone transfers from our master dns server

The script runs daily via cron, after the daily rotating of dns log files.

The following variables/arguments/regex will need to be defined with real informaiton:

  • Line 18: Location of logfile to parse
  • LInes 41 & 45: IP address of the Master DNS server

  • Line 58: Location of output file to write information gathered from log
  • Lines 104 & 105, 107 & 108: Email recipients

  • Lines 111, 112, 115, 118: smtp server, name of server sending email, sender of email and recipient that will show up in the To: field.

Perl Script

  1 #!/usr/bin/perl -w
  2 
  3 ##
  4 ## May 27, 2008
  5 ## [email protected] 
  6 ##
  7 
  8 use strict;
  9 use Net::SMTP;
 10 use Date::Simple ('date', 'today');
 11 use vars qw(@lines @lines_email $file $file2 $a $b $c $i @mesg1 @mesg2 @mesg3 $index $size $size1 $size2 $size3 $smtp $body $today $date $recipient1 $recipient2);
 12 
 13 #Retrieve Current Date for use in email subject
 14 my $today = today();
 15 $date =  (('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday')[$today->day_of_week]);
 16 
 17 ##Define and open log file
 18 $file = "<LOGFILE_LOCATION>";
 19 open (FH, $file) or die "Error cannot open file: $!\n";
 20 
 21 ##Initialize variables
 22 @lines = <FH>;
 23 $size1 = @lines;
 24 $a = 0;
 25 $b = 0;
 26 $c = 0;
 27 my @mesg1= ();
 28 my @mesg2= ();
 29 my @mesg3= ();
 30 
 31 ##Parse log file and extract lines which match one of three conditions
 32 foreach $index (@lines) {
 33     if ( $index =~ /(SERVFAIL)/ ) {
 34         $mesg1[$a] = " SERVFAIL detected:\t$index\n";
 35         $a++;
 36     }
 37     if ( $index =~ /(REFUSED)/ ) {
 38         $mesg2[$b] = " REFUSED from master detected:\t$index\n";
 39         $b++;
 40     }
 41     if ( ($index =~ /end of transfer/)  && ($index =~ /MASTER_DNS/) ) {
 42         $mesg3[$c] = " Zone transfer detected:\t$index\n";
 43         $c++;
 44     }
 45     elsif ( ($index =~ /failed while receiving responses/) && ($index =~ /MASTER_DNS/) ) {
 46         $mesg3[$c] = " Zone XFER failed:\t$index\n";
 47         $c++;
 48     }
 49 }
 50 ## Finished reading in logs, close file
 51 close FH;
 52 reset $size1;
 53 $size1 = @mesg1;
 54 $size2 = @mesg2;
 55 $size3 = @mesg3;
 56 
 57 ##Make sure that a previous run of this script txt file is deleted before we start writing to it
 58 $file2 = "<LOGFILE_LOCATION>";
 59 unlink($file2);
 60 ##Open File which we will write the body of the email to
 61 open (writeEmail, '>>' .  $file2) or die "Error cannot open file: $!\n"; 
 62 ##Print Heading for servfail, then messages.
 63 print writeEmail "There were $size1 SERVFAIL messages:\n";
 64 $i = 1;
 65 if ( $size1 != 0 ) {
 66     for $index (@mesg1) {
 67         print writeEmail $i . ". " . $index;
 68         $i++;
 69     }
 70 } else {
 71     print writeEmail "No SERVFAIL matches found\n";
 72 }
 73 ##Print Heading for refused, then messages.
 74 print writeEmail "\nThere were $size2 REFUSED messages:\n";
 75 $i = 1;
 76 if ( $size2 != 0 ) {
 77     for $index (@mesg2) {
 78         print writeEmail $i . ". " . $index;
 79         $i++;
 80     }
 81 } else {
 82     print writeEmail "No REFUSED matches found";
 83 }
 84 ##Print Heading for xfer, then messages.
 85 print writeEmail "\nThere were $size3 XFER messages:\n";
 86 $i = 1;
 87 if ( $size3 != 0 ) {
 88     for $index (@mesg3) {
 89         print writeEmail $i . ". " . $index;
 90         $i++;
 91     }
 92 } else {
 93     print writeEmail "No XFER matches found\n";
 94 }
 95 ##Grab the number of lines written before file is closed
 96 @lines_email = <writeEmail>;
 97 $size = @lines_email;
 98 print "$size\n";
 99 ##Close mesage file for writing
100 close (writeEmail);
101 #Open email message for reading, determine to whom message should be sent 
102 open(emailMsg, $file2) or die "Cannot open email.txt for reading";
103 if ($size == 0 ) {
104     $recipient1 = "SOMEONE\@SOMEWHERE.edu";
105     $recipient2 = "SOMEONE\@SOMEWHERE.edu";
106 } else {
107     $recipient1 = "SOMEONE\@SOMEWHERE.edu";
108     $recipient2 = "SOMEONE\@SOMEWHERE.edu";
109 }
110 ##Send Email if # of lines is not greater than 250
111 $smtp = Net::SMTP->new('YOURSMTP.SOMEWHERE.EDU',
112                         Hello => 'YOUSERVER.SOMEWHERE.EDU',
113                         Timeout => 30,
114                         Debug => 1,) or die "Error creating SMTP obj: $!\n";
115 $smtp->mail('[email protected]');
116 $smtp->to($recipient1, $recipient2);
117 $smtp->data();
118 $smtp->datasend("To: FROM\n");
119 $smtp->datasend("Subject: DNS Report for $date\n");
120 $smtp->datasend("\n");
121 if ($size > 310) {
122     $smtp->datasend("Too many lines returned, see dns logs immediately");
123 } else {
124     $smtp->datasend(<emailMsg>);
125 }
126 $smtp->dataend();
127 $smtp->quit;
128 
129 #Close email message, done reading
130 close (emailMsg);