#!/usr/bin/perl -w # perl script to monitor FIFO found at $fifo, recreating it if necessary, and outputting data from # FIFO that matches $key to $out # # Author: Robb Bromley # use stuffs use constant TRUE => 1; use constant FALSE => 0; use strict; # if you have to ask you dont need to know use Getopt::Std; # parse command line options use POSIX qw(setsid); # let the forking begin use Fcntl qw(:flock :mode); # file locking and permissions code use Sys::Syslog qw(:DEFAULT setlogsock); # syslog logging facility use IO::File; # forward declarations # sub chkfifo # var time/init shizzle our $prog = "iptlogd"; our $ver = "0.5"; our $SL = ""; our $OT = ""; our $pf = "/var/run/iptlogd.pid"; my $fifo = "/var/log/syslog_fifo"; my $key = "iptables"; my $out = "/var/log/firewall"; my %opts; getopts("k", \%opts); setlogsock("unix"); # at least on knight, the default of inet doesnt work # option handlers if ($opts{k}) { my $pidfile = new IO::File; $pidfile->open("< $pf") or diez0r("Could not open $pf: perhaps iptlogd is not running?\n"); my $pid = readline($pidfile); chomp $pid; if(system("kill", "-TERM", $pid) != 0) { diez0r("Could not kill iptlogd - $pid. Reason: $?"); } print("$prog version $ver brought down via SIGTERM.\n"); exit(); }; # shutdown signal handler sub shutoff { my($sig) = @_; our $SL; our $OT; our $pf; our $prog; our $ver; my $msg = "$prog version $ver brought down via SIG$sig"; if ($SL) { shut(bless $SL); } if ($OT) { shut(bless $OT); } unlink($pf); diez0r("$msg"); }; # spread our shutdown handler joyously throughout the system $SIG{TERM} = \&shutoff; $SIG{QUIT} = \&shutoff; $SIG{INT} = \&shutoff; $SIG{KILL} = \&shutoff; $SIG{ABRT} = \&shutoff; # am i already running? if (-e $pf) { # the pidfile exists if (-s $pf) { # and its not empty diez0r("Fatal- I am already running. (stale pid file?)"); } else { # pid file exists but it has no pid in it # erase, try to use kill and hunt my rogue self down # if the hunt fails, assume its safe to start up unlink($pf); system("killall", "-s KILL", $prog); } }; # we are authorized to be a daemon ya know initz0r(); slog("Version $ver started successfully"); while (TRUE) { chkfifo($fifo); $SL = new IO::File; $SL->open("< $fifo") or diez0r("Can't open fifo $fifo: $!\n"); # open that fifo sleep(1); # reinstate the alarm my $service = readline($SL); next unless defined $service; if ($service =~ /$key/) { $OT = new IO::File; $OT->autoflush(); $OT->open(">> $out") or diez0r("Can't open output $out: $!\n"); # open the iptables log file $OT->blocking(TRUE); # lock that damn log file print $OT "$service"; # write our line $OT->blocking(FALSE); # okay, unlock it $OT->close(); # close it up } } sub chkfifo { my $fifo = shift; if (-p $fifo) { # do nothing } else { slog("had to reconstruct $fifo FIFO"); if (system('mknod', $fifo, 'p') && system('mkfifo', $fifo)) { diez0r("Can't make fifo $fifo: $!"); } } return(1); } sub shut { my $file = shift; slog("closing file"); if ($file->IO::File::opened()) { $file->IO::File::close(); } return(0); } sub slog { my $msg = shift; openlog(our $prog, "pid", "daemon"); syslog("info", $msg); closelog(); return (1); } sub diez0r { my $err = shift; slog("Fatal- " . $err); die($err); } sub initz0r { our $pf; chdir("/") or diezor("Can't chdir to /: $!"); open(STDIN, "/dev/null") or diez0r("Can't open /dev/null"); open(STDOUT, "/dev/null"); open(STDERR, "/dev/null"); my $pid = fork(); if (defined($pid)) { exit if $pid; } else { diez0r("Can't fork: $!"); } setsid() or diez0r("Can't start a new session: $!"); umask(0); my $pidfile = new IO::File; $pidfile->open("> $pf"); print $pidfile "$$\n"; $pidfile->close(); return(0); }