#!/usr/bin/perl use strict; use Data::Dumper; use Getopt::Long; my @field_names = ( 'logfield', 'displayname', 'show', 'width' ); my @fields = ( # logfield displayname show width [ 'device_id', 'Device', 1, 12 ], [ 'vsys', 'vSys', 1, 8 ], [ 'start_time', 'sTime', 1, 14 ], [ 'policy_id', 'PolId', 1, 6 ], [ 'service', 'Svc', 0, 10 ], [ 'src_zone', 'sZone', 1, 8 ], [ 'src', 'sAddr', 1, 15 ], [ 'dst_zone', 'dZone', 1, 8 ], [ 'dst', 'dAddr', 1, 15 ], [ 'proto', 'Proto', 1, 3 ], [ 'src_port', 'sPort', 1, 5 ], [ 'dst_port', 'dPort', 1, 5 ], [ 'action', 'Action', 1, 7 ], [ 'sent', 'bSent', 0, 6 ], [ 'rcvd', 'bRecv', 0, 6 ], [ 'duration', 'Elap', 1, 6 ], [ 'src-xlated-ip', 'sXAddr', 0, 15 ], [ 'src-xlated-port', 'sXPort', 0, 5 ], [ 'dst-xlated-ip', 'dXAddr', 0, 15 ], [ 'dst-xlated-port', 'dXPort', 0, 5 ], ); my %fields_by_log = map { $_->[0], $_ } @fields; my %fields_by_title = map { $_->[1], $_ } @fields; # output formatting my @fmt_fields = (); my $fmt_str = undef; my $fmt_len = undef; sub format_line { my ($val_h) = @_; sub calc_fmt { $fmt_str = undef; $fmt_len = undef; @fmt_fields = grep { $_->[2] } @fields; foreach ( @fmt_fields ) { $fmt_str .= '%'.$_->[3].'s '; $fmt_len += $_->[3] + 1; } chop $fmt_str; $fmt_len--; } calc_fmt() if (! defined $fmt_str); my $out = sprintf $fmt_str, map { $val_h->{$_->[0]} ? $val_h->{$_->[0]} : '-' } @fmt_fields; if (length $out ne $fmt_len) { foreach my $cf (@fmt_fields) { if ($cf->[3] < length $val_h->{$cf->[0]}) { $cf->[3] = length $val_h->{$cf->[0]}; } } calc_fmt(); $out = sprintf $fmt_str, map { defined $val_h->{$_->[0]} ? $val_h->{$_->[0]} : '-' } @fmt_fields; } return $out; } # input editing sub edit_time { my $s = shift @_; $s =~ tr/[\- :"]//d; return $s; } sub edit_service { my $s = shift @_; $s =~ tr/ //d; $s =~ s/proto=/ proto=/; return $s; } # log filtering functions sub in_net { my ($addr,$cidr) = @_; my ($o1,$o2,$o3,$o4,$b); ($o1,$o2,$o3,$o4,$b) = split /[\.\/]/, $cidr; $cidr = ((((($o1<<8)+$o2)<<8)+$o3)<<8)+$o4; ($o1,$o2,$o3,$o4) = split /\./, $addr; $addr = ((((($o1<<8)+$o2)<<8)+$o3)<<8)+$o4; $b = 32 - $b; $cidr = $cidr>>$b; $addr = $addr>>$b; $cidr eq $addr } sub main { my $opt_help; Getopt::Long::Configure('bundling'); Getopt::Long::GetOptions( 'help|h' => \$opt_help, map { $_->[1].'!', \$_->[2] } @fields, ) || ( usage() && exit 1 ); if ($opt_help) { usage(); exit; } my $filter; if (@ARGV) { $filter = join ' ', @ARGV; foreach my $t ( keys %fields_by_title ) { my $f = $fields_by_title{$t}->[0]; $filter =~ s/$t/\$_->\{$f\}/g; } $filter =~ s/(\S+)\s+net\s+['"]?(\d+\.\d+.\d+\.\d+\/\d+)['"]?/in_net($1,'$2')/g; $filter =~ s/\s+(ne|eq|=|!=)\s+([^'"\s]\S+[^'"\s])/ $1 '$2'/g; } else { $filter = 1; } # header my %hv = map { $_->[0], $_->[1] } grep { $_->[2] } @fields; print format_line(\%hv),"\n"; my $code_loop = ' while () { chomp; if (/ device_id=(\S+) \[([^\]]+)\]system-notification-00257\(traffic\): (.*)$/) { my %log_v; $log_v{device_id} = $1; $log_v{vsys} = $2; my $log_s = $3; $log_s =~ s/(src|dst) zone/$1_zone/go; $log_s =~ s/service=([^=]+) proto=/edit_service($&)/e; $log_s =~ s/start_time=("[^"]+")/edit_time($&)/eo; $log_s =~ s/(src|dst)-xlated (\S+) (\S+)/$1-xlated-$2 $1-xlated-$3/go; my %v = split /[ =]/,$log_s; @log_v{keys %v} = values %v; $_ = \%log_v; next unless ; print format_line(\%log_v), "\n"; } } '; $code_loop =~ s//$filter/; if (! defined eval $code_loop) { die "failed with filter ", Dumper($filter),"\n"; } } main(); =head1 NAME nstf - Netscreen Traffic Log Reformatter & Filter =head1 SYNOPSIS nstf 'dPort eq 2048 && dZone eq PUBLIC' < ScreenOS.syslog nstf --noDevice 'Device eq nsfw1' < ScreenOS.syslog nstf --noDevice 'dAddr net 192.168.1.0/24' < ScreenOS.syslog =head1 DESCRIPTION C is a simple tool for reformatting Netscreen syslog traffic logs into columns and showing only entries of interest. Columns can be shown or hidden using command line options and trival or complex filters can be specified using a simplified PERL syntax. C reads input from stdin and does NOT accept named files on the command line. =head1 FIELDS The following fields are selectable from the logs; Device vSys sTime PolId Svc sZone sAddr dZone dAddr Proto sPort dPort Action bSent bRecv Elap sXAddr sXPort dXAddr dXPort By default all except the following fields are shown; Svc bSent bRecv sXAddr sXPort dXAddr dXPort Any field can be shown or hidden using long format options; nstf --noDevice --dXAddr --dXPort Which would hide C but show C and C. =head1 FILTERS Filters can be applied to any of the fields, whether they are shown or not. The filter is implemented using PERL eval so can be quite complicated. Following are some examples; nstf 'sPort eq 2048' nstf 'sPort > 2048' nstf '( sPort > 2048 && dPort < 1024 ) || dPort > 32000' Note it is generally recommended that you quote the parameters you pass to nstf as they often will be confused with shell meta-characters, however quoting is not always necessary. One special purpose match function has been defined for matching IP addresses to networks. nstf 'sAddr net 172.17.0.0/16' The net operator matches when the LHS is within the RHS network. For speed the net test does not do much error checking so if you incorrectly specify a network address the result will be probably meaningless. =head1 BUGS The filter parsing is not particularly good and does not do much error checking. If you for instance specify a non-existant field (ie C) the filter will not complain but will never match. This code is not particulary fast - much slower than grep for instance. =head1 AUTHOR This tool is provided by Optek Pty Ltd =head1 COPYRIGHT & DISCLAIMER This code is copyright by Optek Pty Ltd with all rights reserved. Any entity ("you") may use this code under the conditions set out in the following paragraph. The copyright holders and/or other parties provide this file and related files as is" without warranty of any kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose and the accuracy of the information contained within it. The entire risk as to the quality and performance of the file and related files is with you. Should the file and/or related files fail to work on your system, you assume the cost of all necessary servicing, repair or correction =cut