I'm a big fan of Net::Netmask. I maintain a simple database of my company's netblocks and which city they belong in by building an array of Net::Netmask/city combinations. Assuming the netblocks/cities are stored in a pipe-delimited text file like so:
12.34.56.78/16|City A
90.12.34.56/19|City B
etc
The code looks something like this:
# Build an array. Each element of the array is a reference
# to a two-element array consisting of a Net::Netmask object
# and a city name
my @blocks;
while (<FH>)
{
my ($block, $city) = split /\|/;
push @blocks, [Net::Netmask->new($block), $city];
}
Then to check which city an ip address belongs in, I just do a sequential search:
sub find_city
{
my $address = shift;
foreach my $arrayref (@blocks)
{
# Extra variables assigned for clarity
my $netblock = $arrayref->[0];
my $city = $arrayref->[1];
if ($netblock->match($address))
{
return $city;
}
}
}
The code could be written faster by using a better search algorithm [1], but a sequential search of my company's 2100+ netblocks takes negligible time so I haven't seen fit to recode it.
[1] We don't have anything larger than a /16, so hash buckets keyed on the first two octets could speed things up a bit. Something like this:
$blocks{10}{0} = [
[Net::Netmask->new("10.0.0.0/24"), "City A"],
[Net::Netmask->new("10.0.1.0/24"), "City B"]
];
$blocks{10}{1} = [
[Net::Netmask->new("10.1.0.0/24"), "City C"],
[Net::Netmask->new("10.1.1.0/24"), "City D"]
];
-Matt |