mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
150 lines
3.5 KiB
Perl
150 lines
3.5 KiB
Perl
package IP4;
|
|
|
|
use Exporter;
|
|
@ISA = ('Exporter');
|
|
@EXPORT = ( 'getIPFromString',
|
|
'getStringFromIP',
|
|
'getMaskFromPrefix',
|
|
'getPrefixFromMask',
|
|
'isPartOf',
|
|
'aggregateSinglesTo'
|
|
);
|
|
|
|
use strict;
|
|
my $DEBUG = 0;
|
|
|
|
sub getIPFromString{
|
|
my ($net) = @_;
|
|
my @octets = split (/\./, $net);
|
|
|
|
#check ip!
|
|
foreach my $oct (@octets){
|
|
if ($oct!~/\d+/ || $oct<0 || $oct > 255){return 0;}
|
|
}
|
|
|
|
my $ip=0;
|
|
for (my $i = 0; $i < 4; $i++){
|
|
$ip |= $octets[$i] << ((3-$i)*8);
|
|
}
|
|
return $ip;
|
|
}
|
|
|
|
sub getStringFromIP{
|
|
my ($net) = @_;
|
|
my @octets;
|
|
my $bitmask=0xff;
|
|
for (my $i = 0; $i<4; $i++){
|
|
$octets[$i] = ($net & $bitmask);
|
|
$net >>= 8;
|
|
}
|
|
return "$octets[3].$octets[2].$octets[1].$octets[0]";
|
|
}
|
|
|
|
sub getMaskFromPrefix{
|
|
my ($pre) = @_;
|
|
|
|
#check prefix!
|
|
if ($pre!~/\d+/ || $pre < 0 || $pre > 32){return 0;}
|
|
|
|
my $mask=0;
|
|
for (my $i = 0; $i < $pre; $i++){
|
|
$mask |= 1 << (31-$i);
|
|
}
|
|
return $mask;
|
|
}
|
|
|
|
sub getPrefixFromMask{
|
|
my ($mask) = @_;
|
|
if ($mask == 0){return 0}; #special case, we would loop forever with this:
|
|
my $prefix;
|
|
for ($prefix = 32; !($mask & 1); $prefix--){
|
|
$mask >>= 1;
|
|
}
|
|
return $prefix;
|
|
}
|
|
|
|
sub isPartOf{
|
|
my ($iip, $imask, $oip, $omask) = @_;
|
|
if ($omask > $imask){return 0;}
|
|
#if the net which should contain the other is
|
|
#smaller we did something wrong!
|
|
|
|
return ( (($oip ^ $iip) & $omask) == 0 );
|
|
}
|
|
|
|
sub aggregateSinglesTo{
|
|
#paramters:
|
|
#1. reference to array of addresses (will be changed!)
|
|
#2. refernce to array of masks (will be deleted and changed)
|
|
#3. max Bits to aggregate to.
|
|
|
|
my ($addr, $masks, $bitlimit) = @_;
|
|
$bitlimit = 32-$bitlimit; #the way it will be used we'll need the inverse
|
|
@$addr = sort{$a<=>$b}(@$addr) or return 0;
|
|
@$masks = ();
|
|
my $fullmask = getMaskFromPrefix(32);
|
|
foreach my $dummy (@$addr){push(@$masks, $fullmask);}
|
|
if ($DEBUG){
|
|
print STDERR "sorted list before aggregating\n";
|
|
print STDERR join(" ", map(getStringFromIP($_), @$addr));
|
|
print STDERR "\n";
|
|
}
|
|
|
|
for (my $i = 0;
|
|
$i < (scalar(@$addr) - 1);
|
|
$i ++)
|
|
{
|
|
my $lip = $addr->[$i];
|
|
my $lmask = $masks->[$i];
|
|
my $hip = $addr->[$i + 1];
|
|
my $hmask = $masks->[$i + 1];
|
|
|
|
if (isPartOf($hip, $hmask, $lip, $lmask)) { #parameter: (inner, outer)
|
|
if ($DEBUG){
|
|
printf STDERR ("removing %s/%s since it is contained in %s/%s ",
|
|
getStringFromIP($hip), getPrefixFromMask($hmask),
|
|
getStringFromIP($lip), getPrefixFromMask($lmask) );
|
|
}
|
|
splice(@$addr, $i + 1, 1);
|
|
splice(@$masks, $i + 1, 1);
|
|
-- $i;
|
|
}else{
|
|
my $nb = $lip;
|
|
|
|
$nb ^= $hip; #look for first non-matching bit!
|
|
my $firstdiff=0;
|
|
while ($nb > 0){
|
|
$firstdiff++;
|
|
$nb >>= 1;
|
|
}
|
|
if ($firstdiff <= $bitlimit){
|
|
if ($DEBUG){print STDERR "$firstdiff : ";}
|
|
while($firstdiff>0){
|
|
$firstdiff--;
|
|
$nb <<= 1;
|
|
$nb += 1;
|
|
}
|
|
|
|
my $nm = ~$nb; #negate to get the new (joint) mask
|
|
my $na = $lip & $nm;
|
|
$addr->[$i] = $na;
|
|
$masks->[$i] = $nm;
|
|
if ($DEBUG){
|
|
printf STDERR ("%s to %s/%s (aggregating %s)\n",
|
|
getStringFromIP($lip), getStringFromIP($addr->[$i]),
|
|
getPrefixFromMask($masks->[$i]), getStringFromIP($hip));
|
|
}
|
|
splice(@$addr, $i + 1, 1);
|
|
$i--; #do with the same address again. perhaps it collects even more
|
|
}
|
|
}
|
|
}
|
|
if ($DEBUG){
|
|
print STDERR "sorted list after aggregation\n";
|
|
print STDERR join(" ", map(getStringFromIP($_), @$addr));
|
|
print STDERR "\n";
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
1;
|