package Net::Subnets;
use strict;
use vars qw($VERSION);
$VERSION = '0.21';
sub new {
my $self = shift;
return bless( {}, ( ref($self) || $self ) );
}
sub subnets {
my ( $self, $subnets ) = @_;
my %masks;
foreach (@$subnets) {
/^(.+?)\/(.+)$/o;
my $revmask = 32 - ( $2 || 32 );
$self->{subnets}{$revmask}
{ unpack( "N", pack( "C4", split( /\./, $1 ) ) ) >> $revmask } = $_;
$masks{$revmask}++;
}
@{ $self->{masks} } =
sort( { $masks{$a} <=> $masks{$b} } keys(%masks) );
}
sub check {
my ( $self, $address ) = @_;
foreach ( @{ $self->{masks} } ) {
my $option =
unpack( "N", pack( "C4", split( /\./, $$address ) ) ) >> $_;
if ( $self->{subnets}{$_}{$option} ) {
return \( $self->{subnets}{$_}{$option} );
}
}
return 0;
}
sub range {
my ( $self, $subnet ) = @_;
$$subnet =~ /^(.+?)\/(.+)$/o;
my $net =
pack( 'C4', split( /\./, $1 ) ) &
pack( 'B*', ( 1 x $2 ) . ( 0 x ( 32 - ( $2 || 32 ) ) ) );
my $lowip =
join( '.', unpack( 'C4', pack( 'B*', ( 0 x 31 ) . 1 ) | $net ) );
my $highip = join(
'.',
unpack(
'C4', pack( 'B*', ( 0 x $2 ) . ( 1 x ( 31 - $2 ) ) . 0 ) | $net
)
);
if ( $2 == 32 ) {
return ( \$highip, \$highip );
}
return ( \$lowip, \$highip );
}
sub list {
my ( $self, $lowip, $highip ) = @_;
my $lowint = unpack( "N", pack( "C4", split( /\./, $$lowip ) ) );
my $highint = unpack( "N", pack( "C4", split( /\./, $$highip ) ) );
my @list = ( join( '.', unpack( 'C4', pack( 'N', $lowint ) ) ) );
while ( $lowint lt $highint ) {
push( @list, join( '.', unpack( 'C4', pack( 'N', ++$lowint ) ) ) );
}
return \@list;
}
1;
__END__
=head1 NAME
Net::Subnets - Computing subnets in large scale networks
=head1 SYNOPSIS
use Net::Subnets;
my $sn = Net::Subnets->new;
$sn->subnets( \@subnets );
if ( my $subnetref = $sn->check( \$address ) ) {
...
}
my ( $lowipref, highipref ) = $sn->range( \$subnet );
my $listref = $sn->list( \( $lowipref, $highipref ) );
=head1 DESCRIPTION
Very fast matches large lists of IP addresses against many CIDR subnets and
calculates IP address ranges.
The following functions are provided by this module:
new()
Creates an "Net::Subnets" object.
It takes no arguments.
subnets( \@subnets )
The subnets() function lets you prepare a list of CIDR subnets.
It takes an array reference.
check( \$address )
The check() function lets you check an IP address against the
previously prepared subnets.
It takes a scalar reference and returns a scalar reference to
the first matching CIDR subnet.
range( \$subnet )
The range() function lets you calculate the IP address range
of a subnet.
It takes a scalar reference and returns two scalar references to
the lowest and highest IP address.
list( \$lowip, \$highip )
The list() function lets you calculate a list containing all IP
addresses in a given range.
It takes two scalar references and returns a reference to a list
containing the IP addresses.
This is a simple and efficient example for subnet matching:
use Net::Subnets;
my @subnets = qw(10.0.0.0/24 10.0.1.0/24);
my @addresses = qw(10.0.0.1 10.0.1.2 10.0.3.1);
my $sn = Net::Subnets->new;
$sn->subnets( \@subnets );
my $results;
foreach my $address ( @addresses ) {
if ( my $subnetref = $sn->check( \$address ) ) {
$results .= "$address: $$subnetref\n";
}
else {
$results .= "$address: not found\n";
}
}
print( $results );
This is a simple example for range calculation:
use Net::Subnets;
my @subnets = qw(10.0.0.0/24 10.0.1.0/24);
my $sn = Net::Subnets->new;
my $results;
foreach my $subnet ( @subnets ) {
my ( $lowipref, $highipref ) = $sn->range( \$subnet );
$results .= "$subnet: $$lowipref - $$highipref\n";
}
print( $results );
This is a simple example for list generation:
use Net::Subnets;
my $lowip = '192.168.0.1';
my $highip = '192.168.0.100';
my $sn = Net::Subnets->new;
my $listref = $sn->list( \( $lowip, $highip ) );
foreach my $address ( @{ $listref } ) {
# do something cool
}
=head1 AUTHOR
Sebastian Riedel (sri@cpan.org),
Juergen Peters (juergen.peters@taulmarill.de)
=head1 COPYRIGHT
Copyright 2003 Sebastian Riedel & Juergen Peters. All rights reserved.
This library is free software. You can redistribute it and/or
modify it under the same terms
as perl itself.
=cut
syntax highlighted by Code2HTML, v. 0.9.1