#! @PERL@ -w # vim:syntax=perl use strict; use lib '@LR_PERL5LIBDIR@'; use Lire::DlfSchema; use Lire::Program qw( :msg :dlf ); use Lire::Firewall qw/ firewall_number2names /; use Lire::WELF; init_dlf_converter( "firewall" ); my $schema = Lire::DlfSchema::load_schema( "firewall" ); my $dlf_maker = $schema->make_hashref2asciidlf_func( qw/time rule action protocol rcv_intf from_ip from_port to_ip to_port snt_intf length count msg/); my %wtproto2proto = ( http => [ "tcp", 80 ], https => [ "tcp", 443 ], dns => [ "udp", 53 ], ftp => [ "tcp", 80 ], telnet => [ "tcp", 23 ], smtp => [ "tcp", 25 ], pop3 => [ "tcp", 110 ], realaudio => [ "udp", "Real" ], # FIXME: Does this makes sense ); my $lines = 0; my $dlflines = 0; my $errorlines = 0; my $parser = new Lire::WELF; while (<>) { lire_chomp(); $lines++; # Skip empty lines next if /^\s*$/; eval { my $welf = $parser->parse( $_ ); die "not a firewall WELF record: id=", $welf->{id}, "\n" unless $welf->{id} eq 'firewall'; # Skip messages without src or dst. return unless $welf->{src} && $welf->{dst}; my %dlf = ( time => $welf->{time}, action => "permitted", count => 1, rule => $welf->{rule}, msg => $welf->{msg}, from_ip => $welf->{src}, from_port => $welf->{src_port}, rcv_intf => $welf->{src_if}, to_ip => $welf->{dst}, to_port => $welf->{dst_port}, snt_intf => $welf->{dst_if}, ); # When there is a proto, it is usually an accepted packet flow if ( $welf->{proto}) { my $proto = lc $welf->{proto}; # Guess destination port based on that value if ( exists $wtproto2proto{$proto}) { $dlf{protocol} = $wtproto2proto{$proto}[0]; $dlf{to_port} ||= $wtproto2proto{$proto}[1]; } elsif ( $proto =~ m,(.*)/(.*),) { $dlf{protocol} = $1; $dlf{to_port} ||= $2; } else { # Try some sane(?) defaults $dlf{protocol} = "tcp"; $dlf{to_port} ||= $proto; } # Netscreen ScreenOS 3.0.1. WELF logs features stuff like # Jul 18 19:02:49 10.0.0.1 id=firewall time="2002-07-18 19:01:06" # fw=17010041 pri=7 rule=320001 proto=udp/port:1900 # src=10.0.0.2 dst=10.0.0.1 sent=0 rcvd=161 duration=0 # msg="Action:Deny" module=system level=information type=08668 # ; this breaks heuristic. fix it here. if ( defined $welf->{msg} ) { if ( $welf->{msg} eq 'Action:Deny' ) { $dlf{action} = "denied"; } elsif ( $welf->{msg} eq 'Action:Permit' ) { $dlf{action} = "permitted"; } } # fyi: accepted packets have Action:Permit # normal Netscreen logs sent via syslog look different (and more # useful), btw. } elsif ( exists $welf->{msg} ) { # Dropped packet usually don't contains a # proto= field and the msg will contains dropped # with the protocol $dlf{action} = "denied" if $welf->{msg} =~ /dropped|rejected|blocked|attack/i; if ( $welf->{msg} =~ /^(tcp|udp|icmp)/i ) { $dlf{protocol} = lc $1; } } # Length should be computed from rcvd and sent, will be 0 on dropped # packet :( if ( $welf->{rcvd} || $welf->{sent}) { $dlf{length} = 0; $dlf{length} += $welf->{rcvd} if $welf->{rcvd}; $dlf{length} += $welf->{sent} if $welf->{sent}; } firewall_number2names( \%dlf ); my $dlf = $dlf_maker->( \%dlf ); print join( " ", @$dlf), "\n"; $dlflines++; }; if ($@) { lr_warn( $@ ); lr_notice( qq{cannot convert line $. "$_" to firewall dlf, skipping} ); $errorlines++; } } end_dlf_converter( $lines, $dlflines, $errorlines ); __END__ =pod =head1 NAME welf2dlf - convert firewall logs in WebTrends Enhanced Log Format to DLF =head1 SYNOPSIS B I =head1 DESCRIPTION B converts firewall logs in the WebTrends Enhanced Log Format into the firewall DLF. That format is defined at the following URL: http://www.netiq.com/partners/technology/welf.asp This converter also supports the SonicWall extensions. A list of firewall products that supports that format can be found at the following URL: http://www.netiq.com/products/fwr/compatible.asp =head1 IMPLEMENTATION NOTES Since the firewall DLF only supports packet filters, not all records will be mapped to DLF. Dropped packets messages (those with a field msg="XXX packet dropped") will be mapped to denied DLF packet. (As well as all msg="TCP connection dropped" records). Those packets will have a length of 0 (that's a limitation of the format which don't log that information on dropped packet). Messages with a proto= field set will be interpretted as "permitted" "packet". That's not exactly "right" because this message really represent a "packets flow" and not a single packet. Other records will be ignored. You may use the welf_proxy service in the proxy superservice to extract proxy level information from WELF logs. =head1 EXAMPLES To process a log as produced by WebTrends: $ welf2dlf < welf.log welf2dlf will be rarely used on its own, but is more likely called by lr_log2report: $ lr_log2report welf < /var/log/welf.log =head1 THANKS Mark D. Nagel, for giving feedback and supplying patches. =head1 SEE ALSO Lire::WELF(3) welf_proxy2dlf(1) =head1 AUTHORS Francis J. Lacoste =head1 VERSION $Id: welf2dlf.in,v 1.14 2006/07/23 13:16:35 vanbaal Exp $ =head1 COPYRIGHT Copyright (C) 2001 Stichting LogReport Foundation LogReport@LogReport.org This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see COPYING); if not, check with http://www.gnu.org/copyleft/gpl.html. =cut # Local Variables: # mode: cperl # End: