package Lire::Firewall::IptablesDlfConverter;

use strict;

use Lire::DlfConverter;
use Lire::Firewall qw/firewall_number2names/;
use Lire::Syslog;
use Carp;

use base qw/Lire::DlfConverter/;

sub new {
    my $proto = shift;
    bless {}, (ref $proto || $proto);
}

sub name { 'iptables' }
sub title { 'Iptables firewall log' }
sub description { '<para>Iptables firewall log</para>' }
sub schemas { qw/firewall/ }

sub handle_log_lines { 1 }

sub init_dlf_converter {
    my ($self, $process) = @_;

    $self->{'parser'} = new Lire::Syslog;

    # wether or not to try to resolve IP addresses to hostnames
    ## $self->{'resolve'} = Lire::Config->get( 'resolve_ips' );
    $self->{'resolve'} = 0;
}

my %ipt2dlf = (
               IN       => "rcv_intf",
               OUT      => "snt_intf",
               SRC      => "from_ip",
               DST      => "to_ip",
               SPT      => "from_port",
               DPT      => "to_port",
               TYPE     => "from_port",
               CODE     => "to_port",
               LEN      => "length",
               PROTO    => "protocol",
              );

my $denied_re = qr/deny|denied|drop|reject|unallowed/i;
my $permit_re = qr/accept|permit/i;

my %field_re = ();
foreach my $k ( keys %ipt2dlf ) {
    $field_re{$k} = qr/\b$k=(\S*)/;
}


sub process_log_line {
    my ($self, $process, $line) = @_;

    eval {
        my $log = $self->{'parser'}->parse($line);
        local $_ = $log->{'content'};

        # Skip non-iptables records
        #
        # The starts of the line is set by the user.
        #
        # We cannot rely on the process name (usually kernel) since
        # this is added by klogd and not by the iptables logging code.
        return $process->ignore_log_line($line)
          unless $log->{content} =~ /IN=\w* OUT=\w*/;

        my %dlf = (
          time => $log->{timestamp},
          count => 1,
        );

        # There is a problem with the IPTable log, there is no real
        # informations on how to determine the reason the packet was
        # logged, i.e. denied or permitted. The user must specify
        # a custom label, we set the action to denied if we find common
        # string in the label.
        ($dlf{rule}) = $log->{content} =~ /^(.*?)IN=/;
        $dlf{action} = "denied" if $dlf{rule} =~ /$denied_re/;
        $dlf{action} = "permitted" if $dlf{rule} =~ /$permit_re/;
        while ( my ( $field, $re ) = each %field_re ) {
            my ( $value ) = $log->{content} =~ /$re/;
            ( $dlf{$ipt2dlf{$field}} ) = $value if defined $value;
        }

        # IPTables will log the following on all packet
        die "iptables lexer failed\n"
          unless exists $dlf{from_ip} &&
                 exists $dlf{to_ip} &&
                 exists $dlf{length} &&
                 exists $dlf{protocol};

        firewall_number2names( \%dlf );

        # fill in $dlf{from_host} and $dlf{to_host}
        ## $self->{'resolve'} && firewall_resolve ( \%dlf );

        $process->write_dlf('firewall', \%dlf);
    };

    if($@) {
        $process->error($line, $@);
    }
}


sub finish_conversion {
    delete $_[0]->{'parser'};
}

1; # nag nag.

__END__

=pod

=head1 NAME

IptablesDlfConverter - convert netfilter/iptables syslog logs to firewall DLF

=head1 DESCRIPTION

B<IptablesDlfConverter> converts Linux 2.4 iptables packet log into firewall DLF format.

=head1 LIMITATIONS

The netfilter logging modules don't log the status of the packet
(drop, accept, reject) like the ipchains logging code. You can specify
a prefix that will be used in the log. This converter will mark the
packet as 'denied' whenever that prefix matches (case insensitive) the
following regex: 'denied|deny|drop|reject|unallowed', it will mark the
packet as 'permitted' whenever that prefix matches (case insensitive)
the following regex: 'accept|permit', and all other packets will have
'-' as the value of the 'action' field.

So in order for this converter to detect 'denied' packets, you should use a
prefix containing one of those substrings.

For example:

 iptables -N lodrop
 iptables -A logdrop -j LOG --log-prefix "Packet-DENY: "
 iptables -A logdrop -j DROP

or other similar prefixes: 'denied: ', 'Packet-REJECT: ', ...

The prefix used will end up in the 'rule' field of the DLF record.

=head1 EXAMPLES

IptablesDlfConvertor will be rarely used on its own, but is more likely
called by lr_log2report:

 $ lr_log2report iptables < /var/log/iptables.log > report

=head1 SEE ALSO

The Netfilter webpage at http://netfilter.samba.org/ .

=head1 AUTHORS

Francis J. Lacoste <flacoste@logreport.org>

=head1 VERSION

$Id: IptablesDlfConverter.pm,v 1.12 2006/07/23 13:16:35 vanbaal Exp $

=head1 COPYRIGHT

Copyright (C) 2001, 2002, 2003, 2004 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:
