diff --git a/Changes b/Changes index 66135cd..309f239 100644 --- a/Changes +++ b/Changes @@ -1,56 +1,53 @@ -Revision history for Perl extension IP::Address. - -0.01 Sun Jul 11 13:26:27 1999 - - original version; Basic testing and release to CPAN as - version 0.01. This is considered beta software. - -0.02 Mon Jul 12 - - Multiple changes to fix endiannes issues. This code is now - moderately tested on Wintel and Sun/Solaris boxes. - -0.03 Wed Jul 14 - - Added ->first and ->last methods. Version changed to 0.03. - -1.00 Wed Dec 05 2000 - - Implemented ->new_subnet. Version changed to 1.00. - - less croak()ing when improper input is fed to the - module. A more consistent 'undef' is returned now - instead to allow the user to better handle the error. - - Released - -1.10 Wed May 02 2000 - - As per MARNIX A. VAN AMMERS [mav6@ns02.comp.pge.com] - suggestion, changed the syntax of the loop in host_enum - to be the same of the enum method. - - Fixed the MS-DOS ^M at the end-of-line problem. This - should make the module easier to use for *nix users. - - Released - -1.20 Sun Jun 25 2000 - - Implemented ->compact and ->expand methods. - - Applying for official name - - Released - -1.21 Mon Jun 26 2000 - - Added ->addr_number and ->mask_bits. Currently we return - normal numbers (not BigInts). Please test this in your - platform and report any problems! - -2.00 Wed Jun 28 2000 - - Released under the new *official* name of NetAddr::IP - -2.10 Thu Oct 12 2000 - - Added support for ->new($min, $max, $bits) form - - Added ->to_numeric. This helps serializing objects - -2.11 Fri Oct 13 2000 - - Fixed ->to_numeric to output plain numbers - - Removed leftover debug statements - -2.12 Fri Oct 13 2000 - - Fixed spurious warnings in some platforms - - - - - +Revision history for Perl extension IP::Address. + +0.01 Sun Jul 11 13:26:27 1999 + - original version; Basic testing and release to CPAN as + version 0.01. This is considered beta software. + +0.02 Mon Jul 12 + - Multiple changes to fix endiannes issues. This code is now + moderately tested on Wintel and Sun/Solaris boxes. + +0.03 Wed Jul 14 + - Added ->first and ->last methods. Version changed to 0.03. + +1.00 Wed Dec 05 2000 + - Implemented ->new_subnet. Version changed to 1.00. + - less croak()ing when improper input is fed to the + module. A more consistent 'undef' is returned now + instead to allow the user to better handle the error. + - Released + +1.10 Wed May 02 2000 + - As per MARNIX A. VAN AMMERS [mav6@ns02.comp.pge.com] + suggestion, changed the syntax of the loop in host_enum + to be the same of the enum method. + - Fixed the MS-DOS ^M at the end-of-line problem. This + should make the module easier to use for *nix users. + - Released + +1.20 Sun Jun 25 2000 + - Implemented ->compact and ->expand methods. + - Applying for official name + - Released + +1.21 Mon Jun 26 2000 + - Added ->addr_number and ->mask_bits. Currently we return + normal numbers (not BigInts). Please test this in your + platform and report any problems! + +2.00 Wed Jun 28 2000 + - Released under the new *official* name of NetAddr::IP + +2.10 Thu Oct 12 2000 + - Added support for ->new($min, $max, $bits) form + - Added ->to_numeric. This helps serializing objects + +2.20 Mon Jan 1 2001 + - Chris Dowling reported that the sort method introduced in 1.20 for + ->expand and ->compact doesn't always return a number under perl + versions < 5.6.0. His fix was applied and redistributed. Thanks Chris! + - This module is hopefully released with no CR-LF issues! + - Fixed a warning about uninitialized values during make test + + diff --git a/IP.pm b/IP.pm index b12bc3d..813279f 100644 --- a/IP.pm +++ b/IP.pm @@ -1,685 +1,686 @@ -## -## IP::Address - Help to work with IP addresses and masks -## -## lem@cantv.net - 19990712 -## -## NAME CHANGE to NetAddr::IP (20000628 - lem@cantv.net) -## -############## -############## - -package NetAddr::IP; - -use strict; -use integer; -use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $Use_CIDR_Notation - $Always_Display_Mask); -use Carp; - -use Math::BigInt; - -require Exporter; - -@ISA = qw(Exporter); -# Items to export into callers namespace by default. Note: do not export -# names by default without a very good reason. Use EXPORT_OK instead. -# Do not simply export all your public functions/methods/constants. -@EXPORT_OK = qw( $Use_CIDR_Notation $Always_Display_Mask - -); - -$VERSION = '2.12'; - - -# Preloaded methods go here. - -$Use_CIDR_Notation = 1; # What notation is used to convert - # addresses to their string representation - # 1 means use CIDR notation (10.0.0.0/24) - # 0 means use more traditional notation - # like in 10.0.0.0/255.255.255.0 -$Always_Display_Mask = 1; # Wether to display redundant mask information - # or not -sub _valid_address { - my $ip = shift; - ($ip =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/ - and $1 >= 0 and $1 <= 255 - and $2 >= 0 and $2 <= 255 - and $3 >= 0 and $3 <= 255 - and $4 >= 0 and $4 <= 255); -} - -sub _pack_address { - my $ip = shift; - croak "attempt to pack invalid address $ip" - unless _valid_address $ip; - my @octet = split(/\./, $ip, 4); - my $result = ''; - my $octet = ''; - my $i; - my $j; - foreach $j (0..3) { - vec($octet, 0, 8) = $octet[$j]; - foreach $i (0 .. 7) { - vec($result, $i + 8 * $j, 1) = vec($octet, $i, 1); - } - } - $result; -} - -sub _unpack_address { - my $pack = shift; - my $i; - my $j; - my $result = ''; - foreach $j (0..3) { - my $octet = ''; - foreach $i (0..7) { - vec($octet, $i, 1) = vec($pack, $i + 8 * $j, 1); - } - $result .= '.' if length $result; - $result .= vec($octet, 0, 8); - } - $result; -} - -sub _bits_to_mask { - my $bits = shift; -# croak "Invalid mask len $bits" if $bits < 0 or $bits > 32; - my $i; - my $j; - my $count = 0; - my $result = ''; - foreach $i (0..3) { - foreach $j (reverse 0..7) { - vec($result, $i * 8 + $j, 1) = ($count++ < $bits); - } - } - $result; -} - -sub _addr_to_number { - my $addr = shift; - my @o = split(/\./, $addr, 4); - - $o[0] = new Math::BigInt $o[0]; - $o[1] = new Math::BigInt $o[1]; - $o[2] = new Math::BigInt $o[2]; - $o[3] = new Math::BigInt $o[3]; - - my $o = ($o[0] * 2 ** 24 + - $o[1] * 2 ** 16 + - $o[2] * 2 ** 8 + - $o[3]); - - $o =~ s/[-+]//g; - - return $o; -} - -sub _number_to_addr { - my $number = new Math::BigInt shift; - my @o; - - $o[0] = new Math::BigInt($number->bdiv(2**24)); - $o[1] = new Math::BigInt($number->bdiv(2**16))-$o[0]*2**8; - $o[2] = new Math::BigInt($number->bdiv(2**8))-$o[0]*2**16-$o[1]*2**8; - $o[3] = new Math::BigInt($number)-$o[0]*2**24-$o[1]*2**16-$o[2]*2**8; - - foreach (@o) { s/[-+]//g; } - - return join('.', @o); - -} - -sub _mask_to_bits { - my $mask = shift; - my $i; - my $result = 0; - foreach $i (0..31) { - my $bit = vec($mask, $i, 1); -# croak "non-contiguous mask" if !$bit and $result; - $result += $bit; - } - $result; -} - -sub mask_bits { - my $self = shift; - return _mask_to_bits $self->{'mask'}; -} - -sub _negated_mask { - my $mask = shift; - my $nmask = ''; - my $i; - my $pack = shift; - foreach $i (0..31) { - vec($nmask, $i, 1) = !vec($mask, $i, 1); - } - $nmask; -} - -sub new { - my $type = shift; - my $class = ref($type) || $type || "NetAddr::IP"; - my $ip = shift; - my $mask = shift; - my $bits = shift; - - if (defined($bits) and length($bits)) { - my $min = $ip; - $ip = _number_to_addr($min); - $mask = $bits; - } - - $ip = "0.0.0.0" unless defined $ip; - if ($ip =~ /\/([\d\.]+)$/) { -# croak "inconsistent mask. Use only one form of netmask" - return undef if defined $mask; - my $m = $1; - $ip =~ s/\/\d+$//; - $mask = $m; - } - $mask = "32" unless defined $mask; # Assume a host mask if none is given - if ($mask =~ /\./) { - $mask = _pack_address $mask; - } - else { - return undef if ($mask < 0 or $mask > 32); - $mask = _bits_to_mask $mask; - } - if (not _valid_address $ip) { - return undef; -# croak "invalid IP address"; - } - my $self = { 'addr' => _pack_address($ip), - 'mask' => $mask - }; - - bless $self, $class; -} - -sub to_numeric { - my $self = shift; - if (wantarray) { - return (_addr_to_number(_unpack_address($self->{'addr'})), - _addr_to_number(_unpack_address($self->broadcast->{'addr'})), - _mask_to_bits $self->{'mask'}); - } - else { - return _addr_to_number _unpack_address $self->network->{'addr'}; - } -} - -sub new_subnet { - my $ip = new @_; - return undef unless $ip; - my $subnet = $ip->network; - if ($ip->addr_to_string eq $subnet->addr_to_string) { - return $ip; - } - else { - return undef; - } -} - -sub to_string { - my $self = shift; - my $addr = _unpack_address($self->{'addr'}); - my $mask = $Use_CIDR_Notation ? - _mask_to_bits($self->{'mask'}) - : _unpack_address($self->{'mask'}); - my $wmask = _mask_to_bits($self->{'mask'}); - if (!$Always_Display_Mask and $wmask > 0 and - (($wmask == 24 and $addr =~ /\.0$/ and $addr !~ /\.0\.0$/) - or ($wmask == 16 and $addr =~ /\.0\.0$/ and $addr !~ /\.0\.0\.0$/) - or ($wmask == 8 and $addr =~ /\.0\.0\.0$/ and - $addr !~ /\.0\.0\.0\.0$/) - or ($wmask == 32 and $addr !~ /\.0$/))) { - $addr; - } - else { - $addr . "/" . $mask; - } -} - -sub mask_to_string { - my $self = shift; - $Use_CIDR_Notation ? - _mask_to_bits($self->{'mask'}) - : _unpack_address($self->{'mask'}); -} - -sub addr_to_string { - my $self = shift; - _unpack_address($self->{'addr'}); -} - -sub host_enum { - my $self = shift; - my $first = vec($self->network->{'addr'}, 0, 32); - my $last = vec($self->broadcast->{'addr'}, 0, 32); - my $i; - my @result; - for($i = $first; $i <= $last; ++$i) { - my $addr = ''; - vec($addr, 0, 32) = $i; - push @result, $self->new(_unpack_address($addr), "32"); - } - @result; -} - -### XXX - We might need to return BigInts... Let's wait for testing in -### more platforms. - -sub addr_number { - my $self = shift; -# return new Math::BigInt(vec($self->{'addr'}, 0, 32)); - return vec($self->{'addr'}, 0, 32); -} - -sub _arrange_compact_list { - my @addr = @_; - @addr = sort { - new Math::BigInt(vec($a->{'mask'}, 0, 32)) - <=> new Math::BigInt(vec($b->{'mask'}, 0, 32)) - } @addr; - my @result; - - PROSPECT: - foreach my $prospect (@addr) { - foreach my $cur (@result) { - if ($cur->contains($prospect)) { - next PROSPECT; - } - } - push @result, $prospect; - } - - sort { - new Math::BigInt(vec($a->{'addr'}, 0, 32)) - <=> new Math::BigInt(vec($b->{'addr'}, 0, 32)) - } @result; -} - -sub _can_split { - my $a = shift; - my $bits = shift; - - return () # $bits must make sense - unless $bits > 0 and $bits < 31; - - my $m_len = _mask_to_bits($a->{'mask'}); - - return () # Mask length must be < $bits - unless $m_len < $bits; - - $m_len ++; - - my $a1 = new NetAddr::IP(_unpack_address($a->network->{'addr'}) - . "/" . $m_len); - - my $a2 = new NetAddr::IP(_unpack_address($a->broadcast->{'addr'}) - . "/" . $m_len)->network; - - if ($m_len == $bits) { - return ($a1, $a2); - } - - return (_can_split($a1, $bits), _can_split($a2, $bits)); - -} - -sub _can_merge { - my $a = shift; - my $b = shift; - my $bits = shift; - - return 0 # Masks must be equal - unless vec($a->{'mask'}, 0, 32) == vec($b->{'mask'}, 0, 32); - - return 0 # Mask lenght must be > 0 - if _mask_to_bits($a->{'mask'}) == 0; - - return 0 # Mask length must be >= $bits - if _mask_to_bits($a->{'mask'}) < $bits; - - my $masklen = _mask_to_bits($a->{'mask'}) - 1; - my $container = new NetAddr::IP - _unpack_address($a->{'addr'}) . "/" - . $masklen; - - return 0 # Both must be contained in the same - # supernet - unless $container->contains($a) - and $container->contains($b); - - $container; -} - -sub expand { - my $bits = shift; - my @addr = @_; - - if (@addr == 1 and scalar $addr[0]) { - my $b = $bits; - $bits = $addr[0]; - $addr[0] = $b; - } - - @addr = _arrange_compact_list(@addr); - my $changes = 1; - - if (_valid_address $bits) { - $bits = _mask_to_bits _pack_address $bits; - } - - croak "Invalid bit length ($bits)" if $bits < 0 or $bits > 32; - - my $a; - my $b; - - while ($changes) { - $changes = 0; - - for (my $i = 0; $i <= $#addr; $i++) { - $a = $addr[$i]; - - if (my @subnets = _can_split $a, $bits) { - - @addr = (@addr[0 .. $i - 1], - @subnets, - @addr[$i + 1 .. $#addr]); - - $i += $#subnets; - next; - } - - $b = $addr[$i + 1]; - if (my $container = _can_merge $a, $b, $bits) { - $addr[$i] = $container; - $changes = 1; - next; - } - } - @addr = _arrange_compact_list(@addr) if $changes; - } - return @addr; - -} - -sub compact { - my @addr = _arrange_compact_list(@_); - my $changes = 1; - - my $a; - my $b; - - while ($changes) { - $changes = 0; - for (my $i = 0; $i < $#addr; $i++) { - $a = $addr[$i]; - $b = $addr[$i + 1]; - if (my $container = _can_merge $a, $b, 0) { - $addr[$i] = $container; - $changes = 1; - next; - } - } - @addr = _arrange_compact_list(@addr) if $changes; - } - return @addr; -} - -sub enum { - my $self = shift; - my $first = vec($self->network->{'addr'}, 0, 32); - my $last = vec($self->broadcast->{'addr'}, 0, 32); - my $i; - my @result; - for($i = $first; $i <= $last; ++$i) { - my $addr = ''; - vec($addr, 0, 32) = $i; - push @result, $self->new(_unpack_address($addr), - _unpack_address($self->{'mask'})); - } - @result; -} - -sub network { - my $self = shift; - $self->new (_unpack_address($self->{'addr'} & $self->{'mask'}), - _unpack_address($self->{'mask'})); -} - -sub first { - my $self = shift; - my $addr = ''; - return $self if (_mask_to_bits($self->{'mask'}) == 32); - my $subnet = $self->new (_unpack_address($self->{'addr'} - & $self->{'mask'}), - _unpack_address($self->{'mask'})); - vec($addr, 0, 32) = vec($subnet->{'addr'}, 0, 32) + 1; - $self->new (_unpack_address($addr), - _unpack_address($self->{'mask'})); -} - -sub broadcast { - my $self = shift; - $self->new (_unpack_address($self->{'addr'} - | _negated_mask $self->{'mask'}), - _unpack_address($self->{'mask'})); -} - -sub last { - my $self = shift; - my $addr = ''; - return $self if (_mask_to_bits($self->{'mask'}) == 32); - my $subnet = $self->new (_unpack_address($self->{'addr'} - | _negated_mask $self->{'mask'}), - _unpack_address($self->{'mask'})); - vec($addr, 0, 32) = vec($subnet->{'addr'}, 0, 32) - 1; - $self->new (_unpack_address($addr), - _unpack_address($self->{'mask'})); -} - -sub range { - my $self = $_[0]; - my $ip; - my $min = $self->new("255.255.255.255"); - my $max = $self->new("0.0.0.0"); - $max->set_addr($self); - - foreach $ip (@_) { - - # This comparison is very tricky in some - # architectures, so we might make it in - # BigInts to be safe. - XXXX - - my $bi_ipn = new Math::BigInt vec($ip->network->{'addr'}, 0, 32); - my $bi_ipb = new Math::BigInt vec($ip->broadcast->{'addr'}, 0, 32); - my $bi_min = new Math::BigInt vec($min->{'addr'}, 0, 32); - my $bi_max = new Math::BigInt vec($max->{'addr'}, 0, 32); - - if ($bi_ipn - $bi_min < 0) { - $min->set_addr($ip->network); - } - if ($bi_ipb - $bi_max > 0) { - $max->set_addr($ip->broadcast); - } - } - - my @result; - for($ip = vec($min->{'addr'}, 0, 32); - $ip <= vec($max->{'addr'}, 0, 32); - ++$ip) { - my $addr = ''; - vec($addr, 0, 32) = $ip; - push @result, $self->new(_unpack_address($addr), "32"); - } - @result; -} - -sub set_mask { - my $self = shift; - my $other = shift; - $self->{'mask'} = $other->{'mask'}; - $self; -} - -sub set_addr { - my $self = shift; - my $other = shift; - $self->{'addr'} = $other->{'addr'}; - $self; -} - -sub how_many { - my $self = shift; - vec($self->broadcast->{'addr'}, 0, 32) - - vec($self->network->{'addr'}, 0, 32) + 1; -} - -sub contains { - my $self = shift; - my $other = shift; - my $self_min = new Math::BigInt vec($self->network->{'addr'}, 0, 32); - my $self_max = new Math::BigInt vec($self->broadcast->{'addr'}, 0, 32); - my $other_min = new Math::BigInt vec($other->network->{'addr'}, 0, 32); - my $other_max = new Math::BigInt vec($other->broadcast->{'addr'}, 0, 32); - $other_min >= $self_min and $other_min <= $self_max - and $other_max >= $self_min and $other_max <= $self_max; -} - -1; -__END__ - -=head1 NAME - -NetAddr::IP - Manipulate IP Addresses easily - -=head1 SYNOPSIS - - use NetAddr::IP qw($Use_CIDR_Notation $Always_Display_Mask); - - # Initialization of NetAddr::IP objects - my $ip = new NetAddr::IP "10.0.0.1"; - my $subnet = new NetAddr::IP("10.0.0.0", "255.255.255.0"); - my $othersubnet = new NetAddr::IP("10.0.0.0", "24"); - my $yetanothersubnet = new NetAddr::IP "10.0.0.0/24"; - my $serialsubnet = new NetAddr::IP($min, $max, $bits); - - # A proper subnet (or undef if any host but is set) - my $subnet_ok = new_subnet NetAddr::IP("10.0.0.0", "24"); - my $subnet_undef = new_subnet NetAddr::IP("10.0.0.1", "24"); - - # A numeric representation of a subnet/host address - my $address = $ip->to_numeric(); - my ($min, $max, $bits) = $ip->to_numeric(); - - # A string representation of an address or subnet - print "My ip address is ", $ip->to_string, "\n"; - - # Just the string or the mask part... - print "My ip address alone is ", $ip->addr_to_string, "\n"; - print "and my netmask is ", $ip->mask_to_string, "\n"; - - # Enumeration of all the addresses within a given subnet, keeping - # the original mask - my @hosts = $subnet->enum; - for $i (@hosts) { - print "address ", $i->to_string, - " belongs to subnet ", $subnet->to_string, "\n"; - } - - # You can also produce the list of host addresses in a given subnet - my @hosts = $subnet->host_enum; - for $i (@hosts) { - print "Host ", $i->to_string, - " is in subnet ", $subnet->to_string, "\n"; - } - - # This calculates network and broadcast addresses for a subnet - my $network = $subnet->network; - my $broadcast = $subnet->broadcast; - print "Subnet ", $subnet->to_string, " has broadcast address ", - $broadcast->to_string, " and network number ", $network->to_string, - "\n"; - - # Checks to see if a host address or subnet is contained within another - # subnet - if ($subnet->contains $ip) { - print "Host ", $ip->to_string, " is contained in ", - $subnet->to_string, "\n"; - } - - # Masks and address components can be copied from object to object - $ip1->set_addr($ip2); - $ip1->set_mask($subnet); - - # Ammount of hosts in a subnet can also be easily calculated - $max_hosts_in_subnet = $subnet->how_many - 2; - - # A range of IP Addresses - @range = $ip->range($final_ip); # From $ip to $final_ip - @range = $ip->range(@dont_know_which_is_larger); - # From the smallest on the list + $ip to - # the largest - - # Usable addresses in a subnet - $first_address = $subnet->first; - $last_address = $subnet->last; - - # Compact subnets or addresses into the largest possible CIDR block - @compact_block = NetAddr::IP::compact(@many_small_ip_address_blocks); - - # Split a set of blocks into smaller subnets - @small_subnets = NetAddr::IP::expand(@ip_address_blocks); - - # Obtain a numeric representation of an IP address - my $number = $ip->addr_number; - - # How many bits are there in the mask? - my $masklen = $ip->mask_bits; - -=head1 DESCRIPTION - -This module provides a simple interface to the tedious bit manipulation -involved when handling IP address calculations. It also helps by performing -range comparisons between subnets as well as other frequently used functions. - -Most of the primitive functions return a NetAddr::IP object. - -The variables -B<$Use_CIDR_Notation> - and -B<$Always_Display_Mask> - affect how the -->to_string function will present its result. The names are hopefully -intuitive enough. Note that IP addresses are not properly compacted -(ie, 200.44.0/18 is written as 200.44.0.0/18) because this adapts to -the widely adopted but incorrect notation. Perhaps a later version will -include a variable to change this. - -This code has not been widely tested yet. Endianness problems might very -well exist. Please email the author if such problems are found. - -This software is (c) Luis E. Munoz. It can be used under the terms of the -perl artistic license provided that proper credit is preserved and that -the original documentation is not removed. - -This software comes with the same warranty as perl itself (ie, none), so -by using it you accept any and all the liability. - -=head1 AUTHOR - -Luis E. Munoz - -=head1 SEE ALSO - -perl(1). - -=cut - - 1; +## +## IP::Address - Help to work with IP addresses and masks +## +## lem@cantv.net - 19990712 +## +## NAME CHANGE to NetAddr::IP (20000628 - lem@cantv.net) +## +############## +############## + +package NetAddr::IP; + +use strict; +use integer; +use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $Use_CIDR_Notation + $Always_Display_Mask); +use Carp; + +use Math::BigInt; + +require Exporter; + +@ISA = qw(Exporter); +# Items to export into callers namespace by default. Note: do not export +# names by default without a very good reason. Use EXPORT_OK instead. +# Do not simply export all your public functions/methods/constants. +@EXPORT_OK = qw( $Use_CIDR_Notation $Always_Display_Mask + +); + +$VERSION = '2.20'; + + +# Preloaded methods go here. + +$Use_CIDR_Notation = 1; # What notation is used to convert + # addresses to their string representation + # 1 means use CIDR notation (10.0.0.0/24) + # 0 means use more traditional notation + # like in 10.0.0.0/255.255.255.0 +$Always_Display_Mask = 1; # Wether to display redundant mask information + # or not +sub _valid_address { + my $ip = shift; + ($ip =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/ + and $1 >= 0 and $1 <= 255 + and $2 >= 0 and $2 <= 255 + and $3 >= 0 and $3 <= 255 + and $4 >= 0 and $4 <= 255); +} + +sub _pack_address { + my $ip = shift; + croak "attempt to pack invalid address $ip" + unless _valid_address $ip; + my @octet = split(/\./, $ip, 4); + my $result = ''; + my $octet = ''; + my $i; + my $j; + foreach $j (0..3) { + vec($octet, 0, 8) = $octet[$j]; + foreach $i (0 .. 7) { + vec($result, $i + 8 * $j, 1) = vec($octet, $i, 1); + } + } + $result; +} + +sub _unpack_address { + my $pack = shift; + my $i; + my $j; + my $result = ''; + foreach $j (0..3) { + my $octet = ''; + foreach $i (0..7) { + vec($octet, $i, 1) = vec($pack, $i + 8 * $j, 1); + } + $result .= '.' if length $result; + $result .= vec($octet, 0, 8); + } + $result; +} + +sub _bits_to_mask { + my $bits = shift; +# croak "Invalid mask len $bits" if $bits < 0 or $bits > 32; + my $i; + my $j; + my $count = 0; + my $result = ''; + foreach $i (0..3) { + foreach $j (reverse 0..7) { + vec($result, $i * 8 + $j, 1) = ($count++ < $bits); + } + } + $result; +} + +sub _addr_to_number { + my $addr = shift; + my @o = split(/\./, $addr, 4); + + $o[0] = new Math::BigInt $o[0]; + $o[1] = new Math::BigInt $o[1]; + $o[2] = new Math::BigInt $o[2]; + $o[3] = new Math::BigInt $o[3]; + + return ($o[0] * 2 ** 24 + + $o[1] * 2 ** 16 + + $o[2] * 2 ** 8 + + $o[3]); +} + +sub _number_to_addr { + my $number = new Math::BigInt shift; + my @o; + + $o[0] = new Math::BigInt($number->bdiv(2**24)); + $o[1] = new Math::BigInt($number->bdiv(2**16))-$o[0]*2**8; + $o[2] = new Math::BigInt($number->bdiv(2**8))-$o[0]*2**16-$o[1]*2**8; + $o[3] = new Math::BigInt($number)-$o[0]*2**24-$o[1]*2**16-$o[2]*2**8; + + foreach (@o) { s/[-+]//g; } + + print "_number_to_addr $number is ", join('.', @o), "\n"; + return join('.', @o); + +} + +sub _mask_to_bits { + my $mask = shift; + my $i; + my $result = 0; + foreach $i (0..31) { + my $bit = vec($mask, $i, 1); +# croak "non-contiguous mask" if !$bit and $result; + $result += $bit; + } + $result; +} + +sub mask_bits { + my $self = shift; + return _mask_to_bits $self->{'mask'}; +} + +sub _negated_mask { + my $mask = shift; + my $nmask = ''; + my $i; + my $pack = shift; + foreach $i (0..31) { + vec($nmask, $i, 1) = !vec($mask, $i, 1); + } + $nmask; +} + +sub new { + my $type = shift; + my $class = ref($type) || $type || "NetAddr::IP"; + my $ip = shift; + my $mask = shift; + my $bits = shift; + + if (defined $bits and length $bits) { + my $min = $ip; + $ip = _number_to_addr($min); + $mask = $bits; + } + + $ip = "0.0.0.0" unless defined $ip; + if ($ip =~ /\/([\d\.]+)$/) { +# croak "inconsistent mask. Use only one form of netmask" + return undef if defined $mask; + my $m = $1; + $ip =~ s/\/\d+$//; + $mask = $m; + } + $mask = "32" unless defined $mask; # Assume a host mask if none is given + if ($mask =~ /\./) { + $mask = _pack_address $mask; + } + else { + return undef if ($mask < 0 or $mask > 32); + $mask = _bits_to_mask $mask; + } + if (not _valid_address $ip) { + return undef; +# croak "invalid IP address"; + } + my $self = { 'addr' => _pack_address($ip), + 'mask' => $mask + }; + + bless $self, $class; +} + +sub to_numeric { + my $self = shift; + if (wantarray) { + return (_addr_to_number(_unpack_address($self->{'addr'})), + _addr_to_number(_unpack_address($self->broadcast->{'addr'})), + _mask_to_bits $self->{'mask'}); + } + else { + return _addr_to_number _unpack_address $self->network->{'addr'}; + } +} + +sub new_subnet { + my $ip = new @_; + return undef unless $ip; + my $subnet = $ip->network; + if ($ip->addr_to_string eq $subnet->addr_to_string) { + return $ip; + } + else { + return undef; + } +} + +sub to_string { + my $self = shift; + my $addr = _unpack_address($self->{'addr'}); + my $mask = $Use_CIDR_Notation ? + _mask_to_bits($self->{'mask'}) + : _unpack_address($self->{'mask'}); + my $wmask = _mask_to_bits($self->{'mask'}); + if (!$Always_Display_Mask and $wmask > 0 and + (($wmask == 24 and $addr =~ /\.0$/ and $addr !~ /\.0\.0$/) + or ($wmask == 16 and $addr =~ /\.0\.0$/ and $addr !~ /\.0\.0\.0$/) + or ($wmask == 8 and $addr =~ /\.0\.0\.0$/ and + $addr !~ /\.0\.0\.0\.0$/) + or ($wmask == 32 and $addr !~ /\.0$/))) { + $addr; + } + else { + $addr . "/" . $mask; + } +} + +sub mask_to_string { + my $self = shift; + $Use_CIDR_Notation ? + _mask_to_bits($self->{'mask'}) + : _unpack_address($self->{'mask'}); +} + +sub addr_to_string { + my $self = shift; + _unpack_address($self->{'addr'}); +} + +sub host_enum { + my $self = shift; + my $first = vec($self->network->{'addr'}, 0, 32); + my $last = vec($self->broadcast->{'addr'}, 0, 32); + my $i; + my @result; + for($i = $first; $i <= $last; ++$i) { + my $addr = ''; + vec($addr, 0, 32) = $i; + push @result, $self->new(_unpack_address($addr), "32"); + } + @result; +} + +### XXX - We might need to return BigInts... Let's wait for testing in +### more platforms. + +sub addr_number { + my $self = shift; +# return new Math::BigInt(vec($self->{'addr'}, 0, 32)); + return vec($self->{'addr'}, 0, 32); +} + +sub _arrange_compact_list { + my @addr = @_; + @addr = sort { new Math::BigInt(vec($a->{'mask'}, + 0, + 32))->bcmp(new Math::BigInt(vec($b->{'mask'}, + 0, 32))) + } @addr; + my @result; + + PROSPECT: + foreach my $prospect (@addr) { + foreach my $cur (@result) { + if ($cur->contains($prospect)) { + next PROSPECT; + } + } + push @result, $prospect; + } + + sort { + new Math::BigInt(vec($a->{'addr'}, + 0, + 32))->bcmp(new Math::BigInt(vec($b->{'addr'}, + 0, + 32))) + } @result; +} + +sub _can_split { + my $a = shift; + my $bits = shift; + + return () # $bits must make sense + unless $bits > 0 and $bits < 31; + + my $m_len = _mask_to_bits($a->{'mask'}); + + return () # Mask length must be < $bits + unless $m_len < $bits; + + $m_len ++; + + my $a1 = new NetAddr::IP(_unpack_address($a->network->{'addr'}) + . "/" . $m_len); + + my $a2 = new NetAddr::IP(_unpack_address($a->broadcast->{'addr'}) + . "/" . $m_len)->network; + + if ($m_len == $bits) { + return ($a1, $a2); + } + + return (_can_split($a1, $bits), _can_split($a2, $bits)); + +} + +sub _can_merge { + my $a = shift; + my $b = shift; + my $bits = shift; + + return 0 # Masks must be equal + unless vec($a->{'mask'}, 0, 32) == vec($b->{'mask'}, 0, 32); + + return 0 # Mask lenght must be > 0 + if _mask_to_bits($a->{'mask'}) == 0; + + return 0 # Mask length must be >= $bits + if _mask_to_bits($a->{'mask'}) < $bits; + + my $masklen = _mask_to_bits($a->{'mask'}) - 1; + my $container = new NetAddr::IP + _unpack_address($a->{'addr'}) . "/" + . $masklen; + + return 0 # Both must be contained in the same + # supernet + unless $container->contains($a) + and $container->contains($b); + + $container; +} + +sub expand { + my $bits = shift; + my @addr = @_; + + if (@addr == 1 and scalar $addr[0]) { + my $b = $bits; + $bits = $addr[0]; + $addr[0] = $b; + } + + @addr = _arrange_compact_list(@addr); + my $changes = 1; + + if (_valid_address $bits) { + $bits = _mask_to_bits _pack_address $bits; + } + + croak "Invalid bit length ($bits)" if $bits < 0 or $bits > 32; + + my $a; + my $b; + + while ($changes) { + $changes = 0; + + for (my $i = 0; $i <= $#addr; $i++) { + $a = $addr[$i]; + + if (my @subnets = _can_split $a, $bits) { + + @addr = (@addr[0 .. $i - 1], + @subnets, + @addr[$i + 1 .. $#addr]); + + $i += $#subnets; + next; + } + + $b = $addr[$i + 1]; + if (my $container = _can_merge $a, $b, $bits) { + $addr[$i] = $container; + $changes = 1; + next; + } + } + @addr = _arrange_compact_list(@addr) if $changes; + } + return @addr; + +} + +sub compact { + my @addr = _arrange_compact_list(@_); + my $changes = 1; + + my $a; + my $b; + + while ($changes) { + $changes = 0; + for (my $i = 0; $i < $#addr; $i++) { + $a = $addr[$i]; + $b = $addr[$i + 1]; + if (my $container = _can_merge $a, $b, 0) { + $addr[$i] = $container; + $changes = 1; + next; + } + } + @addr = _arrange_compact_list(@addr) if $changes; + } + return @addr; +} + +sub enum { + my $self = shift; + my $first = vec($self->network->{'addr'}, 0, 32); + my $last = vec($self->broadcast->{'addr'}, 0, 32); + my $i; + my @result; + for($i = $first; $i <= $last; ++$i) { + my $addr = ''; + vec($addr, 0, 32) = $i; + push @result, $self->new(_unpack_address($addr), + _unpack_address($self->{'mask'})); + } + @result; +} + +sub network { + my $self = shift; + $self->new (_unpack_address($self->{'addr'} & $self->{'mask'}), + _unpack_address($self->{'mask'})); +} + +sub first { + my $self = shift; + my $addr = ''; + return $self if (_mask_to_bits($self->{'mask'}) == 32); + my $subnet = $self->new (_unpack_address($self->{'addr'} + & $self->{'mask'}), + _unpack_address($self->{'mask'})); + vec($addr, 0, 32) = vec($subnet->{'addr'}, 0, 32) + 1; + $self->new (_unpack_address($addr), + _unpack_address($self->{'mask'})); +} + +sub broadcast { + my $self = shift; + $self->new (_unpack_address($self->{'addr'} + | _negated_mask $self->{'mask'}), + _unpack_address($self->{'mask'})); +} + +sub last { + my $self = shift; + my $addr = ''; + return $self if (_mask_to_bits($self->{'mask'}) == 32); + my $subnet = $self->new (_unpack_address($self->{'addr'} + | _negated_mask $self->{'mask'}), + _unpack_address($self->{'mask'})); + vec($addr, 0, 32) = vec($subnet->{'addr'}, 0, 32) - 1; + $self->new (_unpack_address($addr), + _unpack_address($self->{'mask'})); +} + +sub range { + my $self = $_[0]; + my $ip; + my $min = $self->new("255.255.255.255"); + my $max = $self->new("0.0.0.0"); + $max->set_addr($self); + + foreach $ip (@_) { + + # This comparison is very tricky in some + # architectures, so we might make it in + # BigInts to be safe. - XXXX + + my $bi_ipn = new Math::BigInt vec($ip->network->{'addr'}, 0, 32); + my $bi_ipb = new Math::BigInt vec($ip->broadcast->{'addr'}, 0, 32); + my $bi_min = new Math::BigInt vec($min->{'addr'}, 0, 32); + my $bi_max = new Math::BigInt vec($max->{'addr'}, 0, 32); + + if ($bi_ipn - $bi_min < 0) { + $min->set_addr($ip->network); + } + if ($bi_ipb - $bi_max > 0) { + $max->set_addr($ip->broadcast); + } + } + + my @result; + for($ip = vec($min->{'addr'}, 0, 32); + $ip <= vec($max->{'addr'}, 0, 32); + ++$ip) { + my $addr = ''; + vec($addr, 0, 32) = $ip; + push @result, $self->new(_unpack_address($addr), "32"); + } + @result; +} + +sub set_mask { + my $self = shift; + my $other = shift; + $self->{'mask'} = $other->{'mask'}; + $self; +} + +sub set_addr { + my $self = shift; + my $other = shift; + $self->{'addr'} = $other->{'addr'}; + $self; +} + +sub how_many { + my $self = shift; + vec($self->broadcast->{'addr'}, 0, 32) - + vec($self->network->{'addr'}, 0, 32) + 1; +} + +sub contains { + my $self = shift; + my $other = shift; + my $self_min = new Math::BigInt vec($self->network->{'addr'}, 0, 32); + my $self_max = new Math::BigInt vec($self->broadcast->{'addr'}, 0, 32); + my $other_min = new Math::BigInt vec($other->network->{'addr'}, 0, 32); + my $other_max = new Math::BigInt vec($other->broadcast->{'addr'}, 0, 32); + $other_min >= $self_min and $other_min <= $self_max + and $other_max >= $self_min and $other_max <= $self_max; +} + +1; +__END__ + +=head1 NAME + +NetAddr::IP - Manipulate IP Addresses easily + +=head1 SYNOPSIS + + use NetAddr::IP qw($Use_CIDR_Notation $Always_Display_Mask); + + # Initialization of NetAddr::IP objects + my $ip = new NetAddr::IP "10.0.0.1"; + my $subnet = new NetAddr::IP("10.0.0.0", "255.255.255.0"); + my $othersubnet = new NetAddr::IP("10.0.0.0", "24"); + my $yetanothersubnet = new NetAddr::IP "10.0.0.0/24"; + my $serialsubnet = new NetAddr::IP($min, $max, $bits); + + # A proper subnet (or undef if any host but is set) + my $subnet_ok = new_subnet NetAddr::IP("10.0.0.0", "24"); + my $subnet_undef = new_subnet NetAddr::IP("10.0.0.1", "24"); + + # A numeric representation of a subnet/host address + my $address = $ip->to_numeric(); + my ($min, $max, $bits) = $ip->to_numeric(); + + # A string representation of an address or subnet + print "My ip address is ", $ip->to_string, "\n"; + + # Just the string or the mask part... + print "My ip address alone is ", $ip->addr_to_string, "\n"; + print "and my netmask is ", $ip->mask_to_string, "\n"; + + # Enumeration of all the addresses within a given subnet, keeping + # the original mask + my @hosts = $subnet->enum; + for $i (@hosts) { + print "address ", $i->to_string, + " belongs to subnet ", $subnet->to_string, "\n"; + } + + # You can also produce the list of host addresses in a given subnet + my @hosts = $subnet->host_enum; + for $i (@hosts) { + print "Host ", $i->to_string, + " is in subnet ", $subnet->to_string, "\n"; + } + + # This calculates network and broadcast addresses for a subnet + my $network = $subnet->network; + my $broadcast = $subnet->broadcast; + print "Subnet ", $subnet->to_string, " has broadcast address ", + $broadcast->to_string, " and network number ", $network->to_string, + "\n"; + + # Checks to see if a host address or subnet is contained within another + # subnet + if ($subnet->contains $ip) { + print "Host ", $ip->to_string, " is contained in ", + $subnet->to_string, "\n"; + } + + # Masks and address components can be copied from object to object + $ip1->set_addr($ip2); + $ip1->set_mask($subnet); + + # Ammount of hosts in a subnet can also be easily calculated + $max_hosts_in_subnet = $subnet->how_many - 2; + + # A range of IP Addresses + @range = $ip->range($final_ip); # From $ip to $final_ip + @range = $ip->range(@dont_know_which_is_larger); + # From the smallest on the list + $ip to + # the largest + + # Usable addresses in a subnet + $first_address = $subnet->first; + $last_address = $subnet->last; + + # Compact subnets or addresses into the largest possible CIDR block + @compact_block = NetAddr::IP::compact(@many_small_ip_address_blocks); + + # Split a set of blocks into smaller subnets + @small_subnets = NetAddr::IP::expand(@ip_address_blocks); + + # Obtain a numeric representation of an IP address + my $number = $ip->addr_number; + + # How many bits are there in the mask? + my $masklen = $ip->mask_bits; + +=head1 DESCRIPTION + +This module provides a simple interface to the tedious bit manipulation +involved when handling IP address calculations. It also helps by performing +range comparisons between subnets as well as other frequently used functions. + +Most of the primitive functions return a NetAddr::IP object. + +The variables +B<$Use_CIDR_Notation> + and +B<$Always_Display_Mask> + affect how the +->to_string function will present its result. The names are hopefully +intuitive enough. Note that IP addresses are not properly compacted +(ie, 200.44.0/18 is written as 200.44.0.0/18) because this adapts to +the widely adopted but incorrect notation. Perhaps a later version will +include a variable to change this. + +This code has not been widely tested yet. Endianness problems might very +well exist. Please email the author if such problems are found. + +This software is (c) Luis E. Munoz. It can be used under the terms of the +perl artistic license provided that proper credit is preserved and that +the original documentation is not removed. + +This software comes with the same warranty as perl itself (ie, none), so +by using it you accept any and all the liability. + +=head1 AUTHOR + +Luis E. Munoz + +=head1 SEE ALSO + +perl(1). + +=cut + + 1; diff --git a/MANIFEST b/MANIFEST index 1d2f003..cb31ecf 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,10 +1,10 @@ -IP.pm -Changes -MANIFEST -Makefile.PL -README -examples/example.pl -examples/expand.pl -examples/simple.pl -examples/serial.pl -t/1.t +IP.pm +Changes +MANIFEST +Makefile.PL +README +examples/example.pl +examples/expand.pl +examples/simple.pl +examples/serial.pl +t/1.t diff --git a/Makefile.PL b/Makefile.PL index 2dc9f33..e444df8 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -1,8 +1,8 @@ -use ExtUtils::MakeMaker; -# See lib/ExtUtils/MakeMaker.pm for details of how to influence -# the contents of the Makefile that is written. -WriteMakefile( - 'NAME' => 'NetAddr::IP', - 'VERSION_FROM' => 'IP.pm', # finds $VERSION - 'PREREQ_PM' => { 'Math::BigInt' => 0, }, -); +use ExtUtils::MakeMaker; +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. +WriteMakefile( + 'NAME' => 'NetAddr::IP', + 'VERSION_FROM' => 'IP.pm', # finds $VERSION + 'PREREQ_PM' => { 'Math::BigInt' => 0, }, +); diff --git a/README b/README index 8445247..c1fa9e5 100644 --- a/README +++ b/README @@ -1,49 +1,49 @@ - -NetAddr::IP - Make it easier to manipulate IP addresses. - -This module implements a simple class that allows for quite powerful -manipulation of IP Addresses in commonly used notations. - -In order to install do - -$ perl Makefile.PL -$ make -$ make test -$ make install - -As usual with most free software, this module is not covered by any -kind of warranty. You can use at your own risk for anything you wish. -If included or used in other products, proper credit must be maintained. - -Module documentation can be found by using the following command - -$ perldoc NetAddr::IP - -The Changes file inside the distribution includes details about the -different revisions of this module. - -If you find bugs/problems with this release, please let me know so -that I can fix it. You can reach me at lem@cantv.net. - - - - - - - - - - - - - - - - - - - - - - - + +NetAddr::IP - Make it easier to manipulate IP addresses. + +This module implements a simple class that allows for quite powerful +manipulation of IP Addresses in commonly used notations. + +In order to install do + +$ perl Makefile.PL +$ make +$ make test +$ make install + +As usual with most free software, this module is not covered by any +kind of warranty. You can use at your own risk for anything you wish. +If included or used in other products, proper credit must be maintained. + +Module documentation can be found by using the following command + +$ perldoc NetAddr::IP + +The Changes file inside the distribution includes details about the +different revisions of this module. + +If you find bugs/problems with this release, please let me know so +that I can fix it. You can reach me at lem@cantv.net. + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/example.pl b/examples/example.pl index 297a0d4..9744f8b 100644 --- a/examples/example.pl +++ b/examples/example.pl @@ -1,79 +1,79 @@ -## -## These are some sample incantations. Hope they help! -## -## lem@cantv.net - 19990712 -## -############# -############# - - -use NetAddr::IP qw($Always_Display_Mask $Use_CIDR_Notation); - -$NetAddr::IP::Always_Display_Mask = 0; -# $NetAddr::IP::Use_CIDR_Notation = 0; - -my $range = new NetAddr::IP "161.196.0.0/17"; -my $other = new NetAddr::IP "200.44.0.0/30"; -print "Subnet ", $range->to_string, " contains ", $range->how_many, - " addresses\n"; -print "Subnet ", $other->to_string, " contains ", $other->how_many, - " addresses\n"; - -$range->set_mask($other); -$range->set_addr($other); -foreach $i ($range->enum) { - print $i->to_string, " is part of ", $range->to_string, " with mask ", - $i->mask_to_string, "\n"; -} - -my $first = new NetAddr::IP "161.196.0.0/30"; -my $middle = new NetAddr::IP "161.196.0.4/30"; -my $last = new NetAddr::IP "161.196.0.8/30"; -foreach $i ($first->range($middle, $last)) { - print $i->to_string, " is between ", $first->to_string, " and ", - $last->to_string, "\n"; -} - -my $big_ip = new NetAddr::IP "200.44.0.0/17"; -my $small_ip = new NetAddr::IP "200.44.0.0/18"; - -print $small_ip->to_string, " is ", - $big_ip->contains($small_ip) ? '' : "not ", - "contained in ". $big_ip->to_string, "\n"; - -my $big_ip = new NetAddr::IP "200.44.0.0/18"; -my $small_ip = new NetAddr::IP "200.44.0.0/17"; - -print $small_ip->to_string, " is ", - $big_ip->contains($small_ip) ? '' : "not ", - "contained in ". $big_ip->to_string, "\n"; - -my $big_ip = new NetAddr::IP "161.196.0.0/23"; -my $small_ip = new NetAddr::IP "161.196.0.0/16"; - -print $small_ip->to_string, " is ", - $big_ip->contains($small_ip) ? '' : "not ", - "contained in ". $big_ip->to_string, "\n"; - -my $ip = new NetAddr::IP("10.0.0.1"); -print "Address: ", $ip->to_string, "\n"; -print "Network: ", $ip->network->to_string, "\n"; -print "Broadcast: ", $ip->broadcast->to_string, "\n"; -my $ip = new NetAddr::IP("200.44.0.0/17"); -print "Address: ", $ip->to_string, "\n"; -print "Network: ", $ip->network->to_string, "\n"; -print "Broadcast: ", $ip->broadcast->to_string, "\n"; -my $ip = new NetAddr::IP("200.44.32.19/255.255.255.252"); -print "Address: ", $ip->to_string, "\n"; -print "Network: ", $ip->network->to_string, "\n"; -print "Broadcast: ", $ip->broadcast->to_string, "\n"; -my $ip = new NetAddr::IP("10.0.0.0/255.255.255.192"); -print "Address: ", $ip->to_string, "\n"; -print "Network: ", $ip->network->to_string, "\n"; -print "Broadcast: ", $ip->broadcast->to_string, "\n"; -my $ip = new NetAddr::IP("0.0.0.0/0"); -print "Address: ", $ip->to_string, "\n"; -print "Network: ", $ip->network->to_string, "\n"; -print "Broadcast: ", $ip->broadcast->to_string, "\n"; - - +## +## These are some sample incantations. Hope they help! +## +## lem@cantv.net - 19990712 +## +############# +############# + + +use NetAddr::IP qw($Always_Display_Mask $Use_CIDR_Notation); + +$NetAddr::IP::Always_Display_Mask = 0; +# $NetAddr::IP::Use_CIDR_Notation = 0; + +my $range = new NetAddr::IP "161.196.0.0/17"; +my $other = new NetAddr::IP "200.44.0.0/30"; +print "Subnet ", $range->to_string, " contains ", $range->how_many, + " addresses\n"; +print "Subnet ", $other->to_string, " contains ", $other->how_many, + " addresses\n"; + +$range->set_mask($other); +$range->set_addr($other); +foreach $i ($range->enum) { + print $i->to_string, " is part of ", $range->to_string, " with mask ", + $i->mask_to_string, "\n"; +} + +my $first = new NetAddr::IP "161.196.0.0/30"; +my $middle = new NetAddr::IP "161.196.0.4/30"; +my $last = new NetAddr::IP "161.196.0.8/30"; +foreach $i ($first->range($middle, $last)) { + print $i->to_string, " is between ", $first->to_string, " and ", + $last->to_string, "\n"; +} + +my $big_ip = new NetAddr::IP "200.44.0.0/17"; +my $small_ip = new NetAddr::IP "200.44.0.0/18"; + +print $small_ip->to_string, " is ", + $big_ip->contains($small_ip) ? '' : "not ", + "contained in ". $big_ip->to_string, "\n"; + +my $big_ip = new NetAddr::IP "200.44.0.0/18"; +my $small_ip = new NetAddr::IP "200.44.0.0/17"; + +print $small_ip->to_string, " is ", + $big_ip->contains($small_ip) ? '' : "not ", + "contained in ". $big_ip->to_string, "\n"; + +my $big_ip = new NetAddr::IP "161.196.0.0/23"; +my $small_ip = new NetAddr::IP "161.196.0.0/16"; + +print $small_ip->to_string, " is ", + $big_ip->contains($small_ip) ? '' : "not ", + "contained in ". $big_ip->to_string, "\n"; + +my $ip = new NetAddr::IP("10.0.0.1"); +print "Address: ", $ip->to_string, "\n"; +print "Network: ", $ip->network->to_string, "\n"; +print "Broadcast: ", $ip->broadcast->to_string, "\n"; +my $ip = new NetAddr::IP("200.44.0.0/17"); +print "Address: ", $ip->to_string, "\n"; +print "Network: ", $ip->network->to_string, "\n"; +print "Broadcast: ", $ip->broadcast->to_string, "\n"; +my $ip = new NetAddr::IP("200.44.32.19/255.255.255.252"); +print "Address: ", $ip->to_string, "\n"; +print "Network: ", $ip->network->to_string, "\n"; +print "Broadcast: ", $ip->broadcast->to_string, "\n"; +my $ip = new NetAddr::IP("10.0.0.0/255.255.255.192"); +print "Address: ", $ip->to_string, "\n"; +print "Network: ", $ip->network->to_string, "\n"; +print "Broadcast: ", $ip->broadcast->to_string, "\n"; +my $ip = new NetAddr::IP("0.0.0.0/0"); +print "Address: ", $ip->to_string, "\n"; +print "Network: ", $ip->network->to_string, "\n"; +print "Broadcast: ", $ip->broadcast->to_string, "\n"; + + diff --git a/examples/expand.pl b/examples/expand.pl index 241fba3..5d22366 100644 --- a/examples/expand.pl +++ b/examples/expand.pl @@ -1,43 +1,43 @@ - -use NetAddr::IP; - -push @ips, ( - new NetAddr::IP("200.44.0.0/24"), - new NetAddr::IP("200.44.1.0/24"), - new NetAddr::IP("200.44.2.0/24"), - new NetAddr::IP("200.44.2.0/23"), - new NetAddr::IP("200.44.4.0/24"), - new NetAddr::IP("10.0.0.0/24"), - new NetAddr::IP("200.44.5.0/24"), - new NetAddr::IP("200.44.6.0/24"), - new NetAddr::IP("200.44.7.0/24"), - new NetAddr::IP("200.44.8.0/26"), - new NetAddr::IP("200.44.8.64/26"), - new NetAddr::IP("200.44.8.128/26"), - new NetAddr::IP("200.44.8.192/26"), -); - -my @compacted = NetAddr::IP::compact(@ips); - -foreach $net (@compacted) { - print $net->to_string, "\n"; -} - -print "BECOMES\n"; - -my @expanded = NetAddr::IP::expand(25, @ips); - -foreach $net (@expanded) { - print $net->to_string, "\n"; -} - -print "Another Range\n"; - -foreach $net (new NetAddr::IP("10.0.0.0/24")->expand(28)) { - print $net->to_string, "\n"; -} - - - - - + +use NetAddr::IP; + +push @ips, ( + new NetAddr::IP("200.44.0.0/24"), + new NetAddr::IP("200.44.1.0/24"), + new NetAddr::IP("200.44.2.0/24"), + new NetAddr::IP("200.44.2.0/23"), + new NetAddr::IP("200.44.4.0/24"), + new NetAddr::IP("10.0.0.0/24"), + new NetAddr::IP("200.44.5.0/24"), + new NetAddr::IP("200.44.6.0/24"), + new NetAddr::IP("200.44.7.0/24"), + new NetAddr::IP("200.44.8.0/26"), + new NetAddr::IP("200.44.8.64/26"), + new NetAddr::IP("200.44.8.128/26"), + new NetAddr::IP("200.44.8.192/26"), +); + +my @compacted = NetAddr::IP::compact(@ips); + +foreach $net (@compacted) { + print $net->to_string, "\n"; +} + +print "BECOMES\n"; + +my @expanded = NetAddr::IP::expand(25, @ips); + +foreach $net (@expanded) { + print $net->to_string, "\n"; +} + +print "Another Range\n"; + +foreach $net (new NetAddr::IP("10.0.0.0/24")->expand(28)) { + print $net->to_string, "\n"; +} + + + + + diff --git a/examples/serial.pl b/examples/serial.pl index a22cb55..08d4c38 100644 --- a/examples/serial.pl +++ b/examples/serial.pl @@ -1,28 +1,28 @@ - -use NetAddr::IP; - -print <to_numeric; - my $nip = new NetAddr::IP (@num); - print ( "$i: ", $ip->to_string, " == ", $nip->to_string, " == ", - join('/', ($ip->to_numeric)), "\n" ); -} - + +use NetAddr::IP; + +print <to_numeric; + my $nip = new NetAddr::IP (@num); + print ( "$i: ", $ip->to_string, " == ", $nip->to_string, " == ", + join('/', ($ip->to_numeric)), "\n" ); +} + diff --git a/examples/simple.pl b/examples/simple.pl index 08521c8..4f57869 100644 --- a/examples/simple.pl +++ b/examples/simple.pl @@ -1,188 +1,188 @@ - -use NetAddr::IP; - -print <to_string, "(", $ip->addr_to_string, - " / ", NetAddr::IP::_unpack_address($ip->{'mask'}), ")\n" ; - -} - -print <first->to_string, - ", last is ", $ip->last->to_string, "\n"; - -} - -print <to_string, "(", $ip->how_many, - " hosts), broadcast ", - $ip->broadcast->to_string, - ", network ", $ip->network->to_string, "\n"; - -} - -print <enum; - @range = $subnet->range($endnet); - print "Network ", $startnet[$i], ":\n"; - foreach $ip (@subnet) { - print " ", $ip->to_string, " belongs to it.\n"; - } - print "Range from ", $startnet[$i], " to ", $endnet[$i], ":\n"; - foreach $ip (@range) { - print " ", $ip->to_string, " belongs to it.\n"; - } -} - -print <contains($m_ip) ? " is contained " : - " is not contained ", "in ", $subnet, "\n"; - } -} + +use NetAddr::IP; + +print <to_string, "(", $ip->addr_to_string, + " / ", NetAddr::IP::_unpack_address($ip->{'mask'}), ")\n" ; + +} + +print <first->to_string, + ", last is ", $ip->last->to_string, "\n"; + +} + +print <to_string, "(", $ip->how_many, + " hosts), broadcast ", + $ip->broadcast->to_string, + ", network ", $ip->network->to_string, "\n"; + +} + +print <enum; + @range = $subnet->range($endnet); + print "Network ", $startnet[$i], ":\n"; + foreach $ip (@subnet) { + print " ", $ip->to_string, " belongs to it.\n"; + } + print "Range from ", $startnet[$i], " to ", $endnet[$i], ":\n"; + foreach $ip (@range) { + print " ", $ip->to_string, " belongs to it.\n"; + } +} + +print <contains($m_ip) ? " is contained " : + " is not contained ", "in ", $subnet, "\n"; + } +} diff --git a/t/1.t b/t/1.t index 502db9f..d159374 100644 --- a/t/1.t +++ b/t/1.t @@ -1,41 +1,41 @@ -# Before `make install' is performed this script should be runnable with -# `make test'. After `make install' it should work as `perl test.pl' - -######################### We start with some black magic to print on failure. - -# Change 1..1 below to 1..last_test_to_print . -# (It may become useful if the test is moved to ./t subdirectory.) - -BEGIN { $| = 1; print "1..5\n"; } -END {print "not ok 1\n" unless $loaded;} -use NetAddr::IP; -$loaded = 1; -print "ok 1\n"; - -######################### End of black magic. - -# Insert your test code below (better if it prints "ok 13" -# (correspondingly "not ok 13") depending on the success of chunk 13 -# of the test code): - -my $big_ip = new NetAddr::IP "200.44.0.0/17"; -my $small_ip = new NetAddr::IP "200.44.0.0/18"; - -print ($big_ip->contains($small_ip) ? "ok 2\n" : "not ok 2\n"); -print ($small_ip->contains($big_ip) ? "not ok 3\n" : "ok 3\n"); - -if ($big_ip->broadcast->addr_to_string eq "200.44.127.255") { - print "ok 4\n"; -} -else { - print "not ok 4\n"; -} - -if ($big_ip->how_many != 32768) { - print "not ok 5\n"; -} -else { - print "ok 5\n"; -} - -exit 0; +# Before `make install' is performed this script should be runnable with +# `make test'. After `make install' it should work as `perl test.pl' + +######################### We start with some black magic to print on failure. + +# Change 1..1 below to 1..last_test_to_print . +# (It may become useful if the test is moved to ./t subdirectory.) + +BEGIN { $| = 1; print "1..5\n"; } +END {print "not ok 1\n" unless $loaded;} +use NetAddr::IP; +$loaded = 1; +print "ok 1\n"; + +######################### End of black magic. + +# Insert your test code below (better if it prints "ok 13" +# (correspondingly "not ok 13") depending on the success of chunk 13 +# of the test code): + +my $big_ip = new NetAddr::IP "200.44.0.0/17"; +my $small_ip = new NetAddr::IP "200.44.0.0/18"; + +print ($big_ip->contains($small_ip) ? "ok 2\n" : "not ok 2\n"); +print ($small_ip->contains($big_ip) ? "not ok 3\n" : "ok 3\n"); + +if ($big_ip->broadcast->addr_to_string eq "200.44.127.255") { + print "ok 4\n"; +} +else { + print "not ok 4\n"; +} + +if ($big_ip->how_many != 32768) { + print "not ok 5\n"; +} +else { + print "ok 5\n"; +} + +exit 0;