postfix-users October 2010 archive
Main Archive Page > Month Archives  > postfix-users archives
postfix-users: Re: Log reporting by cidr

Re: Log reporting by cidr

From: Michael Orlitzky <michael_at_nospam>
Date: Mon Oct 04 2010 - 23:22:02 GMT
To: postfix-users@postfix.org

On 10/04/2010 06:25 PM, pf at alt-ctrl-del.org wrote:
>
>> On 10/04/2010 02:48 PM, pf at alt-ctrl-del.org wrote:
>>> Are there any existing scripts out there, that report connection counts by cidr network?
>>>
>>> Input:?
>>> parse.pl /var/log/mail cidr_list.zone
>>>
>>> Output:?
>>> network count
>>> 10.10.128.0/19 983
>>> 10.144.48.0/20 121
>>>
>>
> On 10/04/2010 4:52 PM, Michael Orlitzky wrote:
>> What's in that cidr_list.zone file?
>
> Simple list of cidr format networks, one per line.
> Either a hand crafted list, or a full country .zone file from http://ipdeny.com/ipblocks/
>
>

This should work, although the standard disclaimers apply:

1. There's no error checking.
2. The regular expression for connections might not be correct.
3. It's slow.
4. I don't actually know Perl.

You'll also need Net::CIDR::Lite. It currently prints out a full tally
including ranges which had zero matches. That's bad for e.g. China with
1822 CIDRs, most of which are zero for me.

#!/usr/bin/perl
use strict;
use warnings;

use Net::CIDR::Lite;

if ($#ARGV < 1) {
  print("Usage: parse.pl <logfile> <cidrfile>\n");
  exit
}

my $logfile = $ARGV[0];
my $cidrfile = $ARGV[1];

open(my $cidrh, '<', $cidrfile) or die "Can't open $cidrfile: $!";

# The list of CIDR objects.
my @cidrs = ();

# A hash, of CIDR => <number of IP addresses seen belonging to it>
my %counts = ();

while (my $line = <$cidrh>) {
  # Add each line in the CIDR file to the hash, with a default
  # count of zero.
  my $cidr = Net::CIDR::Lite->new;
  $cidr->add($line);
  push(@cidrs, $cidr);
  $counts{$cidr} = 0;
}

close($cidrh);
open(my $logh, '<', $logfile) or die "Can't open $logfile: $!";

# Loop through the log file, looking for connections. When one is
# found, we go through the list of CIDRs to see if the IP address
# belongs to any. If it does, increase the count for that CIDR.
while (my $line = <$logh>) {
  # The leading space rules out "DISconnect from..."
  if ($line =~ ' connect from .*\[([\d\.]+?)\]') {
    my $ip = $1;
    foreach my $cidr (@cidrs) {
      if ($cidr->find($ip)) {
       $counts{$cidr} += 1;
      }
    }
  }
}

close($cidrh);

# And finally, print the tally.
foreach my $cidr (@cidrs) {
  my @list = $cidr->list();
  print("@list: $counts{$cidr}\n");
}