#!/usr/bin/perl
use strict;
use warnings;
my %dispatch = ( 'PIX-7-710005' => \&do_discarded, );
while (<>) {
if (/^(?:(.*?) )?%(PIX-\d-\d+): (.*)$/) {
# possibly extra fields default to ''
my %extra = ();
$extra{$_} = '' for qw/mm dd hms name/;
# handle $1 as date/hostname if available.
if ($1) {
@extra{qw/mm dd hms name/} = split /\s/, $1;
}
# try and find a parser for this type
my $handler = $dispatch{$2};
unless ($handler) {
#warn "No handler for message type $2\n";
next;
}
# call our handler
my $rec = $handler->($3);
# print our CSV line
print join( ",",
@extra{qw/mm dd hms name/},
@$rec{qw/action proto srcip srcport dstip dstport dstif/} ),
"\n";
}
else {
# not a PIX message
}
}
sub do_discarded {
my $line = shift;
my %f = ();
# rip out fields for 7-710005 message
@f{qw/proto request action from src to dst/} = split /\s/, $line;
# extract ip/port from src
@f{qw/srcip srcport/} = split /\//, delete $f{src};
# extract if:ip/port from dst
@f{qw/dstif dstip dstport/} = split /[\/:]/, delete $f{dst};
# delete static fields
delete @f{qw/from to request/};
return \%f;
}
__END__
$ perl foo.pl < foo.pix
Sep,7,06:25:17,PIXName,discarded,UDP,0.0.0.0,68,255.255.255.255,67,outside
Sep,7,06:25:23,PIXName,discarded,UDP,1.1.1.1,137,1.1.1.255,137,outside
Sep,7,06:25:23,PIXName,discarded,UDP,1.1.1.1,137,1.1.1.255,137,outside
Sep,7,06:25:23,PIXName,discarded,UDP,1.1.1.1,137,1.1.1.255,137,outside
Sep,7,06:25:24,PIXName,discarded,UDP,1.1.1.1,137,1.1.1.255,137,outside
Sep,7,06:25:24,PIXName,discarded,UDP,1.1.1.1,137,1.1.1.255,137,outside
Sep,7,06:25:24,PIXName,discarded,UDP,1.1.1.1,137,1.1.1.255,137,outside
Sep,7,06:25:25,PIXName,discarded,UDP,1.1.1.1,137,1.1.1.255,137,outside
Sep,7,06:25:25,PIXName,discarded,UDP,1.1.1.1,137,1.1.1.255,137,outside
Sep,7,06:25:25,PIXName,discarded,UDP,1.1.1.1,137,1.1.1.255,137,outside
,,,,discarded,UDP,192.168.2.190,137,192.168.2.255,netbios-ns,outside
>
while (<>) {
if (!/^(... \d+ [\d:]+) (\S+) %PIX-: /g) {
Whoa, this doesn't look like a logfile line.
Deal with it however you want.
next;
}
@csv = ( Parse $1 (the date) and $2 (PIXname) into @csv );
# One regexp for each line format
if (/\G5-304001: ([\d\.]+) Accessed URL (.*)$/c) {
push(@csv, 'accessed', Parse $1 (the IP address) and $2 (the URL) );
} elsif (/\G3-106011: Deny inbound \(No xlate\) (\S+) src (\S+):([\d\.]+)\/(\d+) dst (\S+):([\d\.]+)\/(\d+)$/c) {
# e.g., $1 = 'udp', $2 = 'outside', $3 = '192.168.2.1', $4 = '137', ...
push(@csv, stuff );
} else {
Unrecognized record type. Do whatever you want
}
print OUTFILE join(',', ...some function on @csv if comma-quoting is needed ...)."\n";
}
Note the use of /g, /c, \G to avoid string copies, and capture patterns designed to avoid backtracking. I'm assuming that the number of distinct record types isn't huge, otherwise, go with the hash-of-subs approach.
posted by I_pity_the_fool at 5:30 AM on December 16, 2010