This program will be very useful to you if you run Linux
and an ipchains firewall. Look at the start of the program
or run it with the -h option to get some more information
about it.
#!/usr/bin/perl -w
# firewall-log.pl by Nick Craig-Wood <ncw@axis.demon.co.uk>
use strict;
use Socket;
# User configurable constants
my $LOG = "/var/log/messages";
my $TAIL = "tail -n 1000 -fname $LOG --retry";
############################################################
my $USAGE = << "EOF";
This looks through the system log and translates any messages from the
firewall into coloured human readable format, rather than a whole
string of numbers intermixed with a lot of non-firewall information.
It can also look at the output of dmesg which is useful if your klogd
blows up or you want to look at it not as root.
Useful if you run Linux + an ipchains based firewall.
Syntax: $0 [-t] [file]
Use it like this :-
$0 $LOG
Or
dmesg | $0
Or
tail -f $LOG | $0
Or
$TAIL | $0
Since the last of these is so useful (open a window and tail the
firewall attempts for ever), it can be run like this :-
$0 -t
EOF
############################################################
# Process the arguments
if (@ARGV > 0 && $ARGV[0] =~ /^-/)
{
my $switch = shift;
if ($switch eq '-t')
{
unshift @ARGV, "$TAIL |";
}
else
{
die $USAGE;
}
}
# use ANSI colours if we are attached to a terminal - could use
# Term::ANSIColors here but I decided not to to make the script as
# portable as possible.
my ( $RED, $GREEN, $BLUE, $NORMAL ) = -t STDOUT ?
( "\033[31m", "\033[32m", "\033[34m", "\033[0m" ) :
( "", "", "", "" ) ;
# Grep all the relevant lines out of the incoming stream
while (<>)
{
chomp;
# We need to match in dmesg or syslog format. Syslog is the same
# as dmesg with a few extra fields on the front
#
# Dmesg format :-
# Packet log: input DENY eth1 PROTO=1 1.2.3.4:8 255.255.255.255:0
+L=92 S=0x00 I=1936 F=0x0000 T=245 (#5)
#
# Syslog format :-
# Oct 5 11:58:42 yourmachine kernel: Packet log: ...
if (my @arg = /^(?:(.*) (\S+) kernel: )?Packet log: (\S+) (\S+) (\
+S+) PROTO=(\S+) ([0-9.]+):(\d+) ([0-9.]+):(\d+) L=(\S+) S=(\S+) I=(\S
++) F=(\S+) T=(\S+)(.*)( \(.*\))? .*$/)
{
my ($when, $who, $chain, $status, $interface, $protocol,
$source_ip, $source_port, $dest_ip, $dest_port, $length,
$service, $id, $fragment, $ttl, $special, $count) = @arg;
$when ||= "?"; # these aren't defined in the dmesg form
+at log
$who ||= "?";
# Prettify some inscrutable numbers
$protocol = pretty_protocol($protocol);
$source_ip = pretty_ip($source_ip);
$dest_ip = pretty_ip($dest_ip);
$source_port = pretty_port($source_port, $protocol);
$dest_port = pretty_port($dest_port, $protocol);
# Colour some important bits
my $colour = $NORMAL;
$colour = $RED if $status eq "REJECT";
$colour = $RED if $status eq "DENY";
$colour = $GREEN if $status eq "ACCEPT";
$special =~ s/SYN/${BLUE}SYN${NORMAL}/;
# Report what we have found
print "$when $chain $colour$status$NORMAL $interface $protocol
+ $source_ip $source_port $dest_ip $dest_port $special\n";
#print " length = $length, service = $service, id = $id, frag
+ment = $fragment, ttl = $ttl, remainder= $remainder\n";
}
}
exit;
############################################################
# Prettify a raw IP address
#
# Look up the name attached to the IP address and return that with
# the IP address in brackets if possible. Cache the values returned.
############################################################
my %reverse_dns = (); # ip address cache
sub pretty_ip
{
my ($ip) = @_;
if (!defined $reverse_dns{$ip})
{
my ($name) = gethostbyaddr(inet_aton($ip), AF_INET);
$reverse_dns{$ip} = $name ? "$name [$ip]" : $ip;
}
return $reverse_dns{$ip}
}
############################################################
# Prettify a raw port
#
# Look up the name attached to the port/protocol pair and return that
# with the port in brackets if possible. Cache the values returned.
############################################################
my %reverse_port = (); # port cache
sub pretty_port
{
my ($port, $proto) = @_;
if (!defined $reverse_port{$proto}{$port})
{
my ($name) = getservbyport($port, $proto);
$reverse_port{$proto}{$port} = $name ? "$name [$port]" : $port
+;;
}
return $reverse_port{$proto}{$port}
}
############################################################
# Prettify a raw protocol
#
# Look up the name attached to the protocol and return that name or
# the number if not found. Cache the values returned
############################################################
my %reverse_protocol = (); # protocol cache
sub pretty_protocol
{
my ($protocol) = @_;
if (!defined $reverse_protocol{$protocol})
{
$reverse_protocol{$protocol} = getprotobynumber($protocol) ||
+$protocol;
}
return $reverse_protocol{$protocol}
}