##########################################################################
# $Id: iptables 175 2013-11-08 17:05:21Z opoplawski $
##########################################################################
# $Log: iptables,v $
# Revision 1.9  2009/06/05 14:06:07  mike
# Added IPF patch from Don Wilder/Mark Dalton -mgt
#
# Revision 1.8  2008/03/24 23:31:26  kirk
# added copyright/license notice to each script
#
# Revision 1.7  2007/02/16 03:27:05  bjorn
# Remove explicit invocation of perl executable, by Ivana Varekova.
#
# Revision 1.6  2007/01/29 18:40:29  bjorn
# Handle timestamp generated in Ubuntu, suggested by MrC.
#
# Revision 1.5  2006/08/23 22:47:29  bjorn
# Corrected icmp type reporting, by Allen Kistler.
#
# Revision 1.4  2006/07/11 15:59:56  bjorn
# Allow sorting by either source or target, by Michel Messerschmidt.
#
# Revision 1.3  2006/01/16 18:40:31  kirk
# fixed name to Logwatch (how I like it now)
#
# Revision 1.2  2005/12/06 02:35:43  bjorn
# Report icmp type properly, by Allen Kistler.
#
# Revision 1.1  2005/07/25 22:17:31  bjorn
# Moved iptables (and ipchains, ipfwadm) code to its own service (iptables).
#
##########################################################################
# iptables, ipchains, and ipfwadm script for Logwatch.
# Ipfwadm and ipchains are deprecated, but is included
# here for backwards compatibility.
#
# This script was extracted from the kernel script,
# which processed netfilter (iptables, ipchains, and
# ipfwadm) statements until kernel script Revision 1.29.
#
# Visit the Logwatch website at
#   http://www.logwatch.org
##########################################################################

#####################################################
## Copyright (c) 2008 Kirk Bauer
## Covered under the included MIT/X-Consortium License:
##    http://www.opensource.org/licenses/mit-license.php
## All modifications and contributions by other persons to
## this script are assumed to have been donated to the
## Logwatch project and thus assume the above copyright
## and licensing terms.  If you want to make contributions
## under your own copyright or a different license this
## must be explicitly stated in the contribution an the
## Logwatch project reserves the right to not accept such
## contributions.  If you have made significant
## contributions to this script and want to claim
## copyright please contact logwatch-devel@lists.sourceforge.net.
#########################################################

use Logwatch ':ip';

$Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0;
$MinFilter = $ENV{'iptables_host_min_count'} || 0;
$DoLookup = $ENV{'iptables_ip_lookup'}; $DoLookup = $DoLookup; # keep -w happy
$ListByHost = $ENV{'iptables_list_by_host'} || 0;
$ListByService = $ENV{'iptables_list_by_service'} || 0;
# Keep old behaviour if nothing is configured
$ListByHost = 1 unless ($ListByService);
$MaxFlood = 10;
$MaxNum =0;

sub lookupService {
   my ($port, $proto, $service);
   ($port, $proto) = ($_[0], $_[1]);
   if ($service = getservbyport ($port, $proto)) {
      return($service);
   } else {
      return($port);
   }
}

sub lookupProtocol {
   my ($proto, $name);
   $proto = $_[0];
   if ($name = getprotobynumber ($proto)) {
      return($name);
   } else {
      return($proto);
   }
}

sub lookupAction {
   my ($chain, $actionType);
   $chain = $_[0];

   # choose an action type
   if ( $chain =~ /reject/i ) {
      $actionType = "Rejected";
   } elsif ( $chain =~ /drop/i ) {
      $actionType = "Dropped";
   } elsif ( $chain =~ /deny/i ) {
      $actionType = "Denied";
   } elsif ( $chain =~ /denied/i ) {
      $actionType = "Denied";
   } elsif ( $chain =~ /accept/i ) {
      $actionType = "Accepted";
   } else {
      $actionType = "Logged";
   }

   return $actionType;
}

# SORT COMPARISONS
sub compStr {
   return $a cmp $b;
}

sub compNum {
   return $a <=> $b;
}

while (defined($ThisLine = <STDIN>)) {
   chomp($ThisLine);
   next if ($ThisLine eq '');

   # the format for ulogd/ulogd.syslogmenu and messages differ in that
   # the earlier has no service name after the date.  So RemoveHeaders
   # doesn't work.  Therefore, we extract it here:
   $ThisLine =~ s/^... .. ..:..:.. ([^ ]*) (kernel: )?(\[\s*\d+\.\d+\] )?//;

   # IPCHAINS
   if( ($TU,$from,$port,$on) = ( $ThisLine =~ /IP fw-in deny \w+ (\w+) ([^:]+):\d+ ([^:]+):(\d+) / ) ){
      if($MaxNum < ++$TCPscan{$TU}{$from}) {
         $MaxNum = $TCPscan{$TU}{$from}
      }
      $port=0;
   } elsif ( ($chain,$action,$if,$proto,$fromip,$toip,$toport) = ( $ThisLine =~ /^Packet log: ([^ ]+) (\w+) (\w+) PROTO=(\d+) ([\d|\.]+):\d+ ([\d|\.]+):(\d+)/ ) ) {
      $actionType = lookupAction($action);
      $ipt{$actionType}{$if}{$fromip}{$toip}{$toport}{$proto}{"$chain,$if"}++;
      $ipt2{$actionType}{$if}{$toport}{$proto}{$fromip}{$toip}{"$chain,$if"}++;
   }
   # IPTABLES
   elsif (($chain,$ifin,$ifout,$fromip,$toip,$proto,$rest) = ($ThisLine =~ /^(.*?)\s*IN=([\w\.\-]*).*?OUT=([\w\.\-]*).*?SRC=([\w\.:]+).*?DST=([\w\.:]+).*?PROTO=(\w+)(.*)/ )) {

      # get a destination port number  (or icmp type) if there is one
      if (! ( ($toport) = ( $rest =~ /TYPE=(\w+)/ ) ) ) {
         if (! ( ($toport) = ( $rest =~ /DPT=(\w+)/ ) ) ) {
            $toport = 0;
         }
      }

      # get the action type
      $actionType = lookupAction($chain);

      # determine the dominant interface
      if ($ifin  =~ /\w+/ && $ifout  =~ /\w+/) {
         $interface = $ifin;
      } elsif ($ifin =~ /\w+/) {
         $interface = $ifin;
         $ifout = "none";
      } else {
         $interface = $ifout;
         $ifin = "none";
      }

      if ($chain eq "") {
         $chain_info = "";
      } else {
         $chain_info = "(" . $chain . ") ";
      }

      # add the packet
#      $ipt{$actionType}{$interface}{$fromip}{$toip}{$toport}{$proto}{"$chain,$ifin,$ifout"}++;
      $ipt{$actionType}{$interface}{$fromip}{$toip}{$toport}{$proto}{$chain_info}++;
      $ipt2{$actionType}{$interface}{$toport}{$proto}{$fromip}{$toip}{$chain_info}++;
   }
   # IPF
   elsif (($repcnt,$if,$chain,$fromip,$fromport,$toip,$toport,$proto,$rest,$inout) = ($ThisLine =~ /^.*\d{2,2}:\d{2,2}:\d{2,2}\.\d{6,6}\s*(?:(\d{1,})x)*\s*(\w*)\s*@[-]*\d{1,}:[-]*\d{1,}\s*(\w*)\s*([\w\.:]+\w),*(\d*)\s*->\s*([\w\.:]+\w),*(\d*)\s*PR\s*(\w*)\s*(.*((IN|OUT)).*)/)) {
      if ($chain eq 'b') {
          $actionType = "drop";
      } elsif ($chain eq 'p') {
          $actionType = "accept";
      }
      if ($repcnt eq '') {
         $repcnt = 1;
      }
      while ($repcnt >= 1) {
        $ipt{$actionType}{$if}{$fromip}{$toip}{$toport}{$proto}{"$actionType,$if"}++;
        $ipt2{$actionType}{$if}{$toport}{$proto}{$fromip}{$toip}{"$actionType,$if"}++;
        $repcnt = $repcnt - 1;
      }
   }
}

# IPCHAINS
if (keys %TCPscan and $MaxNum>$MaxFlood) {
   print "\nWarning: ipfwadm scan detected on:\n";
   foreach $ThisOne (sort compStr keys %TCPscan) {
      print "   " . $ThisOne . " from:\n";
      foreach $Next (sort compStr keys %{$TCPscan{$ThisOne}}) {
         $TCPscan{$ThisOne}{$Next}>$MaxFlood &&
            print "      " . LookupIP($Next). ": $TCPscan{$ThisOne}{$Next} Time(s)\n";
      }
   }
}


if ((keys %ipt2) and $ListByService) {
   foreach my $actionType (sort compStr keys %ipt2) {
      foreach my $interface (sort compStr keys %{$ipt2{$actionType}}) {
         my $outputMain = '';
         my $interfaceCount = 0;
         foreach my $toport (sort compNum keys %{$ipt2{$actionType}{$interface}}) {
            foreach my $proto (sort compStr keys %{$ipt2{$actionType}{$interface}{$toport}}) {
               my $outputSection = '';
               my $portCount = 0;
               my $hostCount = 0;
               undef %hostList;
               my %host_list = ();
               my $protocol;
               # determine the protocol
               if ( $proto =~ /^\d+$/ ) {
                  $protocol = lookupProtocol($proto);
               } else {
                  $protocol = lc($proto);
               }

               # determine the name of the service
               my $service = lookupService($toport,$protocol);

               foreach my $fromip (sort SortIP keys %{$ipt2{$actionType}{$interface}{$toport}{$proto}}) {
                  my $fromHostCount = 0;
                  my $from = LookupIP($fromip);
                  my $outputDetails = "";
                  foreach my $toip (sort SortIP keys %{$ipt2{$actionType}{$interface}{$toport}{$proto}{$fromip}}) {
                     my $toHostCount = 0;
                     my $to = LookupIP($toip);

                     foreach my $details (sort keys %{$ipt2{$actionType}{$interface}{$toport}{$proto}{$fromip}{$toip}}) {
                        my $packetCount = $ipt2{$actionType}{$interface}{$toport}{$proto}{$fromip}{$toip}{$details};
                        $toHostCount += $packetCount;
                        if ( $Detail > 9 and ( $outputDetails !~ /\Q$details\E/ ) ) {
                           $outputDetails .= $details . ", ";
                        }
                     }
                     $fromHostCount += $toHostCount;
                  }
                     if ( $Detail > 9 ) {
                        chop $outputDetails;
                        chop $outputDetails;
                        push @{$hostList{"$fromHostCount"}}, $from .
                             " " . $outputDetails;
                     } else {
                        push @{$hostList{"$fromHostCount"}}, $from;
                     }
                  $portCount += $fromHostCount;
                  $hostCount++;
               }

               $interfaceCount += $portCount;
               if ($Detail > 5 ) {
                  $outputMain .= sprintf("   To port %d/%s (%s) - ".
                                         "%d packet%s from %d host%s\n",
                                   $toport, $protocol,
                                   ( $service =~ /^\d+$/ ) ? "?" : $service,
                                   $portCount, ( $portCount > 1 ) ? "s" : " ",
                                   $hostCount, ( $hostCount > 1 ) ? "s" : " "
                                 );
                  foreach my $hc (sort { $b <=> $a } keys %hostList) {
                     foreach my $h (@{$hostList{"$hc"}}) {
                        $outputMain .= sprintf("    %6d packet%s from %s\n",
                                       $hc, ( $hc > 1 ) ? "s" : " ", $h);
                     }
                  }
               } elsif ($Detail > 3 ) {
                  my $topHostCount;
                  ($topHostCount, undef) = sort { $b <=> $a } keys %hostList;
                  my $topHost = ${$hostList{"$topHostCount"}}[0];
                  $outputMain .= sprintf( "   To port %5d/%s - %5d packet%s ".
                                         "from %4d host%s (%d from %s)\n",
                                   $toport, $protocol, $portCount,
                                   ( $portCount > 1 ) ? "s" : " ", $hostCount,
                                   ( $hostCount > 1 ) ? "s" : " ",
                                   $topHostCount, $topHost
                                 );
               } else {
                  $outputMain .= sprintf("   To port %5d/%s - %5d packet%s ".
                                         "from %4d host%s\n",
                                   $toport, $protocol, $portCount,
                                   ( $portCount > 1 ) ? "s" : " ", $hostCount,
                                   ( $hostCount > 1 ) ? "s" : " "
                                 );
               }
            }
         }
         print "Listed by target ports:";
         print "\n$actionType $interfaceCount " .
               ( ( $interfaceCount > 1 ) ? "packets" : "packet" ) .
               " on interface $interface\n";
         print $outputMain;
      }
   }
}


# IPCHAINS / IPTABLES
if ((keys %ipt) and $ListByHost) {
   foreach $actionType (sort compStr keys %ipt) {
      foreach $interface (sort compStr keys %{$ipt{$actionType}}) {
         $outputMain = '';
         $interfaceCount = 0;
         foreach $fromip (sort SortIP keys %{$ipt{$actionType}{$interface}}) {
            $outputSection = '';
            $fromHostCount = 0;
            $from = LookupIP($fromip);
            undef %port_list;
            foreach $toip (sort SortIP keys %{$ipt{$actionType}{$interface}{$fromip}}) {
               $toHostCount = 0;
               $to = LookupIP($toip);
               $outputServices = '';
               foreach $toport (sort compNum keys %{$ipt{$actionType}{$interface}{$fromip}{$toip}}) {
                  foreach $proto (sort compStr keys %{$ipt{$actionType}{$interface}{$fromip}{$toip}{$toport}}) {
                     # determine the protocol
                     if ( $proto =~ /^\d+$/ ) {
                        $protocol = lookupProtocol($proto);
                     } else {
                        $protocol = lc($proto);
                     }

                     # determine the name of the service
                     $service = lookupService($toport,$protocol);

                     foreach $details (sort keys %{$ipt{$actionType}{$interface}{$fromip}{$toip}{$toport}{$proto}}) {
                        $packetCount = $ipt{$actionType}{$interface}{$fromip}{$toip}{$toport}{$proto}{$details};
                        $toHostCount += $packetCount;
                        if ( $Detail > 0 ) {
                           $outputServices .= "         Service: $service ($protocol/$toport) $details- $packetCount " . ( ( $packetCount > 1 ) ? "packets\n" : "packet\n" );
                        } else {
                           ${ $port_list{ $protocol } }{$toport}++;
                        }
                     }
                  }
               }
               $fromHostCount += $toHostCount;
               if ( $Detail > 0 ) { $outputSection .= "      To $to - $toHostCount " . ( ( $toHostCount > 1 ) ? "packets\n" : "packet\n" ); }
               $outputSection .= $outputServices;
            }
            $interfaceCount += $fromHostCount;
            if ($fromHostCount >= $MinFilter) {
               if ($Detail > 0 ) {
                  $outputMain .= "   From $from - $fromHostCount " . ( ( $fromHostCount > 1 ) ? "packets\n" : "packet\n" );
               } else {
                  $outputMain .= "  From $from - $fromHostCount " .  ( ($fromHostCount > 1) ? "packets" : "packet" ) .  " to " ;
                  foreach $protocol ( keys %port_list ) {
                     if ( $#{ keys %{$port_list { $protocol } } } > 10 ) {
                        $outputMain .= $#{ $port_list{ $protocol } } ." $protocol ports";
                     } else {
                        $outputMain .= "$protocol(" . join(",", sort compNum keys %{ $port_list{ $protocol } } ) . ") " ;
                     }
                  }
                  $outputMain .="\n";
               }
            }
            $outputMain .= $outputSection;
         }
         print "\nListed by source hosts:";
         print "\n$actionType $interfaceCount " . ( ( $interfaceCount > 1 ) ? "packets" : "packet" ) . " on interface $interface\n";
         print $outputMain;
      }
   }
}


exit(0);

# vi: shiftwidth=3 tabstop=3 syntax=perl et
# Local Variables:
# mode: perl
# perl-indent-level: 3
# indent-tabs-mode: nil
# End:
