#! /usr/bin/perl -w
use strict;
use Socket;

use Data::Dumper;

# Copyright Ton Hospel. 
# This code can be used under GPL or the perl artistic license. your choice.

my $VERSION = "0.07";

my $file = "01-10-2002.log";

my ($src_mapper, $dst_mapper, %src_pool, %dst_pool);
my @mask = map pack("N", 2**32-2**(32-$_)), 0..32;

my %raw_src = 
    ('212.126.224.0/19', 'decode',
     '193.4.0.0/16', 'isnet',
     '194.144.0.0/16', 'isnet',
     '213.176.128.0/19', 'isnet',
     '213.213.128.0/19', 'isnet',
     '217.9.128.0/20', 'isnet',
     '193.4.58.0/23', 'isnic',
     '213.220.64.0/18', 'linanet',
     '62.145.128.0/19', 'linanet',
     '81.15.0.0/17', 'linanet',
     '217.151.160.0/19', 'minet',
     '130.208.0.0/16', 'rhnet',
     '157.157.0.0/16', 'simnet',
     '192.147.34.0/24', 'simnet',
     '194.105.224.0/19', 'simnet',
     '212.30.192.0/19', 'simnet',
     '213.167.128.0/19', 'simnet',
     '10.0.0.0/8', 'snerpa',
     '172.16.0.0/12', 'snerpa',
     '172.24.10.0/23', 'snerpa',
     '192.168.0.0/16', 'snerpa',
     '193.109.16.0/20', 'snerpa',
     '193.109.16.0/26', 'snerpa',
     '193.109.24.0/24', 'snerpa',
     '193.109.24.10/32', 'snerpa',
     '193.109.24.12/32', 'snerpa',
     '194.144.168.0/24', 'snerpa',
     '194.144.237.0/24', 'snerpa',
     );
my %raw_dst = 
    ('193.109.17.48/32', '1',
     '193.109.17.32/32', '2',
     '193.109.17.2/32',  '3',
     '193.109.17.45/32', '47',
     '193.109.17.1/32', '6',
     '193.109.17.3/32', '7',
     '193.109.17.4/32', '8',
     '193.109.17.5/32', '9',
     '193.109.17.6/32', '10',
     '193.109.17.236/32', '11',
     '193.109.17.201/32', '12',
     '193.109.17.9/32', '13',
     '193.109.17.207/32', '14',
     '193.109.17.192/32', '15',
     '193.109.17.12/32', '16',
     '193.109.17.13/32', '17',
     '193.109.17.14/32', '18',
     '193.109.17.15/32', '19',
     '193.109.17.16/32', '20',
     '193.109.17.17/32', '21',
     '193.109.17.18/32', '22',
     '193.109.17.19/32', '23',
     '193.109.17.20/32', '24',
     '193.109.17.22/32', '25',
     '193.109.17.23/32', '26',
     '193.109.17.223/32', '27',
     '193.109.17.25/32', '28',
     '193.109.17.26/32', '29',
     '193.109.17.27/32', '30',
     '193.109.17.28/32', '31',
     '193.109.17.29/32', '32',
     '193.109.17.193/32', '33',
     '193.109.17.31/32', '34',
     '193.109.17.33/32', '35',
     '193.109.17.216/32', '36',
     '193.109.17.208/32', '37',
     '193.109.17.36/32', '38',
     '193.109.17.37/32', '39',
     '193.109.17.38/32', '40',
     '193.109.17.39/32', '41',
     '193.109.17.40/32', '42',
     );

sub make_pool_mapper {
    my $raw = shift;
    my (%bits, @lookup);
    while (my ($net, $name) = each %$raw) {
        my ($base, $bits) = $net =~ m!^(\d+\.\d+\.\d+\.\d+)/(\d+)$! or
            die "net '$net' does not parse in the form ipv4/bits\n";
        die "'$bits' bits > 32. Too weird\n" if $bits > 32;
        my $bin_base = inet_aton($base);
        die "Ip address $base is not valid for netmask /$bits\n" if 
            ($bin_base & $mask[$bits]) ne $bin_base;
        die "Multiple entries for $base/$bits\n" if 
            exists $lookup[$bits]{$bin_base};
        $lookup[$bits]{$bin_base} = $name;
        $bits{$bits} ||= 1;
    }
    # prefer most specific match
    my @bits = sort {$b <=> $a} keys %bits;
    return [\@bits, \@lookup];
}

sub lookup {
    my ($ip, $lookup) = @_;
    my $pools = $lookup->[1];
    
    my $bin_ip = inet_aton($ip);
    for (@{$lookup->[0]}) {
        return $pools->[$_]{$bin_ip & $mask[$_]} if exists 
            $pools->[$_]{$bin_ip & $mask[$_]}
    }
    return "unknown";
}

sub account {
    open(my $fh, "<", $file) || die "Could not open $file: $!\n";
    local $_;
    my %count;
    while (<$fh>) {
        my ($src, $dst, $count) = /^\s*(\d+\.\d+\.\d+\.\d+)\s+(\d+\.\d+\.\d+\.\d+)\s+(\d+)\s*$/ or
            die "Could not parse line $. of $file\n";
        my $src_pool = $src_pool{$src} ||= lookup($src, $src_mapper);
        my $dst_pool = $dst_pool{$dst} ||= lookup($dst, $dst_mapper);
        $count{$src_pool}{$dst_pool} += $count;
    }
    return \%count;
}

$src_mapper = make_pool_mapper(\%raw_src);
$dst_mapper = make_pool_mapper(\%raw_dst);

# print Dumper($src_mapper);
my $count = account($file);
print Dumper($count);
