BSD DevCenter
oreilly.comSafari Books Online.Conferences.

advertisement


Securing Small Networks with OpenBSD Managing Advanced PF Logs

by Jacek Artymiak
08/22/2002

Welcome back.

In part 6 and part 7 we learned how to send logs over an ssh connection and how to make that connection more secure. We also did some math to find out how much storage space we'll need to keep old logs for analysis. Today we need to roll up our sleeves again, and do some coding in Perl, because the pflog fifo pipe created on the monitoring station's hard disk in part 6 is a bit like an oil well, gushing with black stuff that needs some additional piping to turn it into an orderly flow.

Catching and taming that wild stream of data is the job of the readpflog script. Written in Perl, it runs in the background and does three basic things: 1) reads pf logs from the pflog fifo pipe, 2) archives logs on the monitoring firewall, and 3) sends them to another fifo pipe so that log analysis software can pick them up for analysis.

#!/usr/bin/perl -W
#
#                                   Copyright 2002 Jacek Artymiak
#                                                License: XFree86
#----------------------------------------------------------------
# section  1: basic setup  

use Fcntl;
use POSIX qw(:errno_h);

$rdelay = 3600;  # log archiving delay (in seconds, 0 turns off); 

#----------------------------------------------------------------
# section  2: check if readpflog.pid exists

if (-e "/home/scooter/readpflog.pid") {

    print "Looks like readpflog is already running, if it is " . 
               "not running, delete /home/scooter/readpflog.pid";
    exit;
}

#----------------------------------------------------------------
# section  3: open readpflog.log --  the log used by readpflog to 
#                                              store its messages

open (LOG, ">> /home/scooter/readpflog.log"); 
select (LOG);
$|=1;

#----------------------------------------------------------------
# section  4: define the logme function used to write messages to 
#                                                   readpflog.log

sub logme {

 $datetime = `date`;
 chop $datetime;

 $logentry = $datetime . ": readpflog[$$]: $_[0]" . "\n";

 print LOG $logentry;
}

#----------------------------------------------------------------
# section  5: define the loganddie function used to clean up 
#                                           before readpflog dies 
 
sub loganddie {

 $datetime = `date`;
 chop $datetime;

 $logentry = $datetime
                      . ": readpflog[$$]: Fatal error: $_[0]" 
        . ": Exiting ...\n";

 print LOG $logentry;

 $logentry = $datetime 
                      . ": readpflog[$$]: Closing pflog ...\n";

 print LOG $logentry;

 close (INFILE);

 $logentry = $datetime 
              . ": readpflog[$$]: Closing pflog-current ...\n";

 print LOG $logentry;

 close (OUTFILE);

 $logentry = $datetime 
              . ": readpflog[$$]: Removing readpflog.pid ...\n";

 print LOG $logentry;

 `rm ~/readpflog.pid`;

 $logentry = $datetime 
              . ": readpflog[$$]: Exiting.\n";

 print LOG $logentry;

 die ($logentry);
}

#----------------------------------------------------------------
# section  6: define the rotatelogs function, which closes and
#                                         reopens ~/readpflog.log
 
sub rotatelogs() {

 logme ("Closing readpflog.log.");

 close (LOG);

 open (LOG, ">> /home/scooter/readpflog.log");
 select (LOG);
 $|=1;

 logme ("readpflog.log rotated.");
}

#----------------------------------------------------------------
# section  7: we're waking up 

logme ("Starting readpflog ...");

#----------------------------------------------------------------
# section  8: write the current process ID (PID) to 
#                                                 ~/readpflog.pid

logme ("Creating readpflog.pid ...");

open (PIDFILE, "> /home/scooter/readpflog.pid") or 
       loganddie ("Unable to create readpflog.pid: " . $! . '.');

logme ("Writing PID to readpflog.pid ...");

syswrite PIDFILE, $$;

logme ("Closing readpflog.pid");

close PIDFILE;

#----------------------------------------------------------------
# section  9: open ~/pflog for reading

sub opensource {

    logme ("Trying to open pflog ...");

    open (INFILE, "< /home/scooter/pflog") or 
                 loganddie ("Unable to open pflog: " . $! . '.');

    logme ("pflog opened successfully.");

    select (INFILE);
    $|=1;
}

#----------------------------------------------------------------
# section 10: open ~/pflog-current for writing

sub opentarget {

    logme ("Trying to open pflog-current ...");

    open (OUTFILE, ">> /home/scooter/pflog-current") or 
         loganddie ("Unable to open pflog-current: " . $! . '.');

    logme ("pflog-current opened successfully.");

    select (OUTFILE);
    $|=1;

    alarm $rdelay;
}

#----------------------------------------------------------------
# section 11: rotate ~/pflog-* archive

sub rotatetarget {

    close (OUTFILE);

    $d_t = `date "+%Y-%m-%d-%H-%M-%S"`; 

    unless (fork) {
        system ("mv /home/scooter/pflog-current /home/scooter/pflog-" . $d_t);
        system ("gzip -9 /home/scooter/pflog-" . $d_t);
        exit;
    }

    opentarget();
}

#----------------------------------------------------------------
# section  12: opens ~/pflog-pipe fifo pipe for writing 
#

sub openpipe {

    sysopen(LPIPE, "/home/scooter/pflog-pipe", O_NONBLOCK|O_RDWR)
                                  or die "Can't open pipe: $!\n";

    select (LPIPE);
    $|=1;
}

#----------------------------------------------------------------
# section  13: set signal handlers

$SIG{HUP}  = 'rotatelogs';
$SIG{INT}  = 'loganddie';
$SIG{QUIT} = 'loganddie';
$SIG{KILL} = 'loganddie';
$SIG{TERM} = 'loganddie';
$SIG{STOP} = 'loganddie';
$SIG{TSTP} = 'loganddie';
$SIG{PIPE} = 'IGNORE';
$SIG{ALRM} = 'rotatetarget';

#----------------------------------------------------------------
# section  14: open input and output files

opensource();
opentarget();
openpipe();

#----------------------------------------------------------------
# section  15: read ~/pflog, write it to ~/pflog-current, and 
#                                                    ~/pflog-pipe

for (;;) {

    while (<INFILE>) {

        if (length ($_) != 0) {

            $buf = $_;

            if (!(syswrite OUTFILE, $buf)) {

                close (OUTFILE);
                opentarget();
            }

            if (!(syswrite LPIPE, $buf)) {

               close (LPIPE);
               openpipe();
            }
        }

    }

    sleep 1;
    seek (INFILE, 0, 1);
}

Pages: 1, 2

Next Pagearrow





Sponsored by: