diff --git a/IP.pm b/IP.pm index 19a3e7e..3fa8cf9 100644 --- a/IP.pm +++ b/IP.pm @@ -1,6 +1,6 @@ #!/usr/bin/perl -w -# $Id: IP.pm,v 1.11 2003/02/12 00:09:57 lem Exp $ +# $Id: IP.pm,v 1.13 2003/10/09 00:12:21 lem Exp $ package NetAddr::IP; @@ -35,8 +35,6 @@ Many operators have been overloaded, as described below: -=over - =cut require 5.005_62; @@ -50,7 +48,7 @@ our @ISA = qw(Exporter); -our $VERSION = '3.14_3'; +our $VERSION = '3.15'; ############################################# # These are the overload methods, placed here @@ -134,6 +132,8 @@ =pod +=over + =item B)> Has been optimized to copy one NetAddr::IP object to another very quickly. @@ -212,14 +212,41 @@ return $ip unless $const; + my $b = $ip->{bits}; my $a = $ip->{addr}; my $m = $ip->{mask}; - my $b = $ip->{bits}; - + my $hp = "$a" & ~"$m"; my $np = "$a" & "$m"; - vec($hp, 0, $b) += $const; + if ($b == 128) # v6? + { + use Math::BigInt; + + my $num = new Math::BigInt 0; + + for (0 .. 15) + { + $num <<= 8; + $num |= vec($hp, $_, 8); + } + +# warn "# add - before badd($const): $num\n"; + $num->badd($const); +# warn "# add - after badd($const): $num\n"; + + for (reverse 0 .. 15) + { + my $x = new Math::BigInt $num; + vec($hp, $_, 8) = $x & 0xFF; + $num >>= 8; +# warn "# add - octet $_ == $num / ", vec($hp, $_, 8), "\n"; + } + } + else # v4 + { + vec($hp, 0, $b) += $const; + } return _fnew NetAddr::IP [ "$np" | ("$hp" & ~"$m"), $m, $b]; } @@ -498,7 +525,17 @@ vec($addr, 2, 8) = ($present ? $3 : 0); vec($addr, 3, 8) = ($present ? 0 : $3); } - elsif ($ip =~ m/^([xb\d]+)$/) { + elsif ($ip =~ m/^([xb\d]+)$/ and $1 >= 0 and $1 < 255 and $present) + { + vec($addr, 0, 8) = $1; + vec($addr, 1, 8) = 0; + vec($addr, 2, 8) = 0; + vec($addr, 3, 8) = 0; + } + elsif ($ip =~ m/^([xb\d]+)$/) + { + my $num = $1; + $num += 2 ** 32 if $num < 0; vec($addr, 0, 32) = $1; } @@ -1088,6 +1125,8 @@ returned otherwise and C is returned if C<$me> and C<$other> are of different versions. +Note that C<$me> and C<$other> must be C objects. + =cut sub contains ($$) { @@ -1122,6 +1161,8 @@ The complement of C<-Econtains()>. Returns true when C<$me> is completely con tained within C<$other>. +Note that C<$me> and C<$other> must be C objects. + =cut sub within ($$) { @@ -1167,36 +1208,82 @@ if (vec($self->{mask}, 0, $bits) <= vec($mask, 0, $bits)) { - - my $delta = ''; my $num = ''; my $v = ''; - vec($num, 0, $bits) = _ones $bits; - vec($num, 0, $bits) ^= vec($mask, 0, $bits); - vec($num, 0, $bits) ++; - - vec($delta, 0, $bits) = (vec($self->{mask}, 0, $bits) - ^ vec($mask, 0, $bits)); - - my $net = $self->network->{addr}; + my $net = $self->network->{addr}; $net = "$net" & "$mask"; - my $to = $self->broadcast->{addr}; + my $to = $self->broadcast->{addr}; $to = "$to" & "$mask"; - # XXX - Note that most likely, - # this loop will NOT work on IPv6... - # $net, $to and $num might very well - # be too large for most integer or - # floating point representations. - - for (my $i = vec($net, 0, $bits); - $i <= vec($to, 0, $bits); - $i += vec($num, 0, $bits)) + if ($bits == 128) { - vec($v, 0, $bits) = $i; - push @ret, $self->_fnew([ $v, $mask, $bits ]); + use Math::BigInt; + + my $n = new Math::BigInt 0; + my $t = new Math::BigInt 0; + my $u = new Math::BigInt 0; + my $x = ''; + + for (0 .. 15) + { + vec($num, $_, 8) = _ones 8; + vec($num, $_, 8) ^= vec($mask, $_, 8); + $n <<= 8; + $t <<= 8; + $u <<= 8; + $n |= vec($net, $_, 8); + $t |= vec($to, $_, 8); + $u |= vec($num, $_, 8); + } + +# warn "# splitref $self $mask\n"; +# warn "# net = ", $self->network, "\n"; +# warn "# bro = ", $self->broadcast, "\n"; + +# warn "# before, n = $n\n"; +# warn "# before, t = $t\n"; +# warn "# before, u = $u\n"; + + $u++; + my $i = $n->copy; + + do { + + my $j = $i->copy; + +# warn "# i = $i\n"; +# warn "# j = $j\n"; +# warn "# n = $n\n"; +# warn "# u = $u\n"; +# warn "# t = $t\n"; +# warn "###\n"; + + for (reverse 0 .. 15) + { + vec($v, $_, 8) = ($j & 0xFF); + $j >>= 8; + } + + push @ret, $self->_fnew([ $v, $mask, $bits ]); +# warn "# add ", $self->_fnew([$v, $mask, $bits]), "\n"; + $i += $u; + } while ($i <= $t); + } + else + { + vec($num, 0, $bits) = _ones $bits; + vec($num, 0, $bits) ^= vec($mask, 0, $bits); + vec($num, 0, $bits) ++; + + for (my $i = vec($net, 0, $bits); + $i <= vec($to, 0, $bits); + $i += vec($num, 0, $bits)) + { + vec($v, 0, $bits) = $i; + push @ret, $self->_fnew([ $v, $mask, $bits ]); + } } } @@ -1245,6 +1332,8 @@ "correct" approach has been adopted and only one address would be returned. +Note that C<$me> and all C<$addr>-n must be C objects. + =cut sub compact { @@ -1261,6 +1350,7 @@ reference to a list. Note that this method takes a reference to a list instead. +Note that C<$me> must be a C object. =cut sub compactref ($) { @@ -1402,7 +1492,7 @@ =head1 HISTORY -$Id: IP.pm,v 1.11 2003/02/12 00:09:57 lem Exp $ +$Id: IP.pm,v 1.13 2003/10/09 00:12:21 lem Exp $ =over @@ -1928,6 +2018,24 @@ this semantic and make everyone happy, but I won't do anything else here without (significant) feedback. +=item 3.14_4 + +As noted by Michael, 127/8 should be 127.0.0.0/8 and not +0.0.0.128/8. Also, improved docs on the usage of contains() and +friends. + +=item 3.15 + +Finally. Added POD tests (and fixed minor doc bug in IP.pm). As +reported by Anand Vijay, negative numbers are assumed to be signed +ints and converted accordingly to a v4 address. split() and nth() now +work with IPv6 addresses (Thanks to Venkata Pingali for +reporting). Tests were added for v6 base functionality and +splitting. Also tests for bitwise aritmethic with long integers has +been added. I'm afraid Math::BigInt is now required. + +Note that IPv6 might not be as solid as I would like. Be careful... + =back =head1 AUTHOR diff --git a/MANIFEST b/MANIFEST index 4956ca7..a73e201 100644 --- a/MANIFEST +++ b/MANIFEST @@ -2,10 +2,12 @@ TODO README MANIFEST +MANIFEST.SKIP Makefile.PL tutorial.htm t/00-load.t t/loops.t +t/bitops.t t/v4-new.t t/v4-num.t t/relops.t @@ -34,4 +36,5 @@ t/v4-contains.t t/v4-hostenum.t t/v4-split-bulk.t +t/v6-split-bulk.t t/v4-split-list.t diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP new file mode 100644 index 0000000..e6aa309 --- /dev/null +++ b/MANIFEST.SKIP @@ -0,0 +1,17 @@ +^blib/ +^Makefile$ +^Makefile\.[a-z]+$ +^pm_to_blib$ +CVS/.* +,v$ +^tmp/ +\.old$ +\.bak$ +~$ +^# +\.shar$ +\.tar$ +\.tgz$ +\.tar\.gz$ +\.zip$ +_uu$ diff --git a/Makefile.PL b/Makefile.PL index 529e3c6..11da492 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -2,15 +2,42 @@ # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. -# $Id: Makefile.PL,v 1.3 2002/12/10 17:14:02 lem Exp $ +# $Id: Makefile.PL,v 1.5 2003/10/09 00:12:22 lem Exp $ + +my $checker = 0; + +eval { use Test::Pod; + $checker = 1; }; + +unless ($checker) +{ + print < 'NetAddr::IP', 'VERSION_FROM' => 'IP.pm', # finds $VERSION 'PREREQ_PM' => { Test::More => 0, + Math::BigInt => 0, }, # e.g., Module::Name => 1.1 ($] >= 5.005 ? ## Add these new keywords supported since 5.005 (ABSTRACT_FROM => 'IP.pm', AUTHOR => 'Luis E. Mu�oz ') : ()), ); + + + + diff --git a/t/00-load.t b/t/00-load.t index 4b9ed63..4865087 100644 --- a/t/00-load.t +++ b/t/00-load.t @@ -1,11 +1,36 @@ +# Generic load/POD test suite -# Test if the module will load correctly +# $Id: 00-load.t,v 1.3 2003/10/08 06:46:02 lem Exp $ -# $Id: 00-load.t,v 1.2 2002/10/31 04:30:35 lem Exp $ +use Test::More; -BEGIN { $| = 1; print "1..1\n"; } -END {print "not ok 1\n" unless $loaded;} -use NetAddr::IP; -$loaded = 1; -print "ok 1\n"; +my @modules = qw/ + NetAddr::IP + /; + +my @paths = (); + +plan tests => 2 * scalar @modules; + +use_ok($_) for @modules; + +my $checker = 0; + +eval { use Test::Pod; + $checker = 1; }; + +for my $m (@modules) +{ + my $p = $m . ".pm"; + $p =~ s!::!/!g; + push @paths, $INC{$p}; +} + +END { unlink "./out.$$" }; + +SKIP: { + skip "Test::Pod is not available on this host", scalar @paths + unless $checker; + pod_file_ok($_) for @paths; +} diff --git a/t/bitops.t b/t/bitops.t new file mode 100644 index 0000000..4ef4ca8 --- /dev/null +++ b/t/bitops.t @@ -0,0 +1,64 @@ +# This code exercises some common functions that are used in parts +# of v6 management of IP.pm. It is intended as a reference in case +# of failure + +# $Id: bitops.t,v 1.1 2003/10/09 00:14:06 lem Exp $ + +use Test::More; +use NetAddr::IP; +use Math::BigInt; + +my @bases = (); # Base set of trivial numbers +my @convs = (); # Numbers after conversion / de-conversion +my @minus = (); # Bases minus one +my @plus = (); # Bases plus one + +for my $i (0 .. 127) +{ + my $I = new Math::BigInt 1; + $I <<= $i; + push @bases, $I; + $I = new Math::BigInt 3; + $I <<= $i; + push @bases, $I; +} + +pop @bases; + +plan tests => scalar @bases; + + # Test conversion back and forth + # to/from a suitable vec() + +for my $i (0 .. $#bases) # Build the actual conversion +{ + my $v = ''; + my $I = $bases[$i]->copy; + + for my $j (reverse 0 .. 15) + { + vec($v, $j, 8) = ($I & 0xFF); + $I >>= 8; + } + +# print "# "; +# printf "%02x", $_ for map { ord $_ } split //, $v; +# print "\n"; + + push @convs, $v; +} + +for my $i (0 .. $#bases) # Test reversibility +{ + my $I = new Math::BigInt 0; + for my $o (0 .. 15) + { + $I <<= 8; + $I |= vec($convs[$i], $o, 8); +# print "I = $I ($o)\n"; + } + + is($bases[$i], $I, "$bases[$i] == $I [$i]"); +} + + diff --git a/t/relops.t b/t/relops.t index 69037b9..ae74a2a 100644 --- a/t/relops.t +++ b/t/relops.t @@ -1,6 +1,6 @@ use NetAddr::IP; -# $Id: relops.t,v 1.3 2003/02/12 00:09:58 lem Exp $ +# $Id: relops.t,v 1.4 2003/10/08 06:46:02 lem Exp $ BEGIN { @gt = ( @@ -31,22 +31,22 @@ use Test::More tests => @gt + @ngt + (2 * @cmp); for my $a (@gt) { - my $a_ip = new NetAddr::IP $a->[0]; - my $b_ip = new NetAddr::IP $a->[1]; + $a_ip = new NetAddr::IP $a->[0]; + $b_ip = new NetAddr::IP $a->[1]; ok($a_ip > $b_ip, "$a_ip > $b_ip"); } for my $a (@ngt) { - my $a_ip = new NetAddr::IP $a->[0]; - my $b_ip = new NetAddr::IP $a->[1]; + $a_ip = new NetAddr::IP $a->[0]; + $b_ip = new NetAddr::IP $a->[1]; ok(!($a_ip > $b_ip), "$a_ip !> $b_ip"); } -for my $a (@cmp) { - my $a_ip = new NetAddr::IP $a->[0]; - my $b_ip = new NetAddr::IP $a->[1]; +for $a (@cmp) { + $a_ip = new NetAddr::IP $a->[0]; + $b_ip = new NetAddr::IP $a->[1]; is($a_ip <=> $b_ip, $a->[2], "$a_ip <=> $b_ip is $a->[2]"); is($a_ip cmp $b_ip, $a->[2], "$a_ip cmp $b_ip is $a->[2]"); diff --git a/t/v4-new.t b/t/v4-new.t index e392c31..87e2030 100644 --- a/t/v4-new.t +++ b/t/v4-new.t @@ -1,14 +1,16 @@ use NetAddr::IP; -# $Id: v4-new.t,v 1.5 2002/12/27 20:37:55 lem Exp $ +# $Id: v4-new.t,v 1.7 2003/10/08 06:46:02 lem Exp $ BEGIN { our @a = ( - [ 'localhost', '127.0.0.1' ], - [ 0x01010101, '1.1.1.1' ], - [ 1, '0.0.0.1' ], - [ 'default', '0.0.0.0' ], - [ 'any', '0.0.0.0' ], + [ 'localhost', '127.0.0.1' ], + [ 0x01010101, '1.1.1.1' ], + [ 1, '1.0.0.0' ], # Because it will have a mask. 0.0.0.1 ow + [ 'default', '0.0.0.0' ], + [ 'any', '0.0.0.0' ], + [-809041407, '207.199.2.1'], + [3485925889, '207.199.2.1'], ); our @m = ( @@ -40,10 +42,10 @@ for my $a (@a) { for my $m (@m) { my $ip = new NetAddr::IP $a->[0], $m->[0]; - is($ip->addr, $a->[1]); - is($ip->mask, $m->[1]); - is($ip->bits, 32); - is($ip->version, 4); + is($ip->addr, $a->[1], "$a->[0] / $m->[0] is $a->[1]"); + is($ip->mask, $m->[1], "$a->[0] / $m->[0] is $m->[1]"); + is($ip->bits, 32, "$a->[0] / $m->[0] is 32 bits wide"); + is($ip->version, 4, "$a->[0] / $m->[0] is version 4"); } } diff --git a/t/v4-snew.t b/t/v4-snew.t index 4c23b93..36e46f8 100644 --- a/t/v4-snew.t +++ b/t/v4-snew.t @@ -1,11 +1,14 @@ +use Test::More; use NetAddr::IP; -# $Id: v4-snew.t,v 1.2 2002/10/31 04:30:36 lem Exp $ +# $Id: v4-snew.t,v 1.3 2003/05/29 17:45:00 lem Exp $ my %w = ('broadcast' => [ '255.255.255.255', '255.255.255.255' ], 'default' => [ '0.0.0.0', '0.0.0.0' ], 'loopback' => [ '127.0.0.1', '255.0.0.0' ], '10.' => [ '10.0.0.0', '255.0.0.0' ], + '10/8' => [ '10.0.0.0', '255.0.0.0' ], + '127/8' => [ '127.0.0.0', '255.0.0.0' ], '11.11.' => [ '11.11.0.0', '255.255.0.0' ], '12.12.12.' => [ '12.12.12.0', '255.255.255.0' ], '13.13.13.13' => [ '13.13.13.13', '255.255.255.255' ], @@ -19,26 +22,10 @@ '10.10.10' => [ '10.10.0.10', '255.255.255.255' ], ); -$| = 1; - -print '1..', (2 * scalar keys %w), "\n"; - -my $count = 1; +plan tests => 2 * scalar keys %w; for my $a (keys %w) { my $ip = new NetAddr::IP $a; - - if ($ip->addr eq $w{$a}->[0]) { - print "ok ", $count++, "\n"; - } - else { - print "not ok ", $count++, "\n"; - } - - if ($ip->mask eq $w{$a}->[1]) { - print "ok ", $count++, "\n"; - } - else { - print "not ok ", $count++, "\n"; - } + is($ip->addr, $w{$a}->[0], "Matching ->addr()"); + is($ip->mask, $w{$a}->[1], "Matching ->mask()"); } diff --git a/t/v4-split-bulk.t b/t/v4-split-bulk.t index 46695f3..f4554be 100644 --- a/t/v4-split-bulk.t +++ b/t/v4-split-bulk.t @@ -1,25 +1,23 @@ +use Test::More; use NetAddr::IP; -# $Id: v4-split-bulk.t,v 1.2 2002/10/31 04:30:36 lem Exp $ +# $Id: v4-split-bulk.t,v 1.3 2003/10/08 06:46:02 lem Exp $ my @addr = ( [ '10.0.0.0', 20, 32, 4096 ], [ '10.0.0.0', 22, 32, 1024 ], + [ '10.0.0.0', 22, 24, 4 ], + [ '10.0.0.0', 22, 23, 2 ], [ '10.0.0.0', 24, 32, 256 ], - [ '10.0.0.0', 19, 32, 8192 ] + [ '10.0.0.0', 19, 32, 8192 ], + [ '10.0.0.0', 24, 24, 1 ], + [ '10.0.0.0', 31, 32, 2 ] ); -my $count = $| = 1; -print "1..", (scalar @addr), "\n"; +plan tests => (scalar @addr); for my $a (@addr) { my $ip = new NetAddr::IP $a->[0], $a->[1]; my $r = $ip->splitref($a->[2]); - if (scalar @$r == $a->[3]) { - print "ok ", $count++, "\n"; - } - else { - print "not ok ", $count++, " (number $a)\n"; - } - + is(@$r, $a->[3]); } diff --git a/t/v6-base.t b/t/v6-base.t index e1ce883..99a7dc2 100644 --- a/t/v6-base.t +++ b/t/v6-base.t @@ -1,21 +1,41 @@ # This -*- perl -*- code excercises the basic v6 functionality -# $Id: v6-base.t,v 1.4 2002/12/17 05:09:50 lem Exp $ +# $Id: v6-base.t,v 1.7 2003/10/09 00:14:06 lem Exp $ -BEGIN { our @addr = qw(:: ::1 f34::123/40 ); }; +our @addr = + ( + ['::', 3, '0000:0000:0000:0000:0000:0000:0000:0000/128'], + ['::1', 3, '0000:0000:0000:0000:0000:0000:0000:0001/128'], + ['f34::123/40', 3, '0f34:0000:0000:0000:0000:0000:0000:0003/40'], + ['dead:beef::1/40', 3, 'dead:beef:0000:0000:0000:0000:0000:0003/40'], + ['dead:beef::1/40', 4, 'dead:beef:0000:0000:0000:0000:0000:0004/40'], + ['dead:beef::1/40', 5, 'dead:beef:0000:0000:0000:0000:0000:0005/40'], + ['dead:beef::1/40', 6, 'dead:beef:0000:0000:0000:0000:0000:0006/40'], + ['dead:beef::1/40', 7, 'dead:beef:0000:0000:0000:0000:0000:0007/40'], + ['dead:beef::1/40', 8, 'dead:beef:0000:0000:0000:0000:0000:0008/40'], + ['dead:beef::1/40', 9, 'dead:beef:0000:0000:0000:0000:0000:0009/40'], + ['dead:beef::1/40', 255, 'dead:beef:0000:0000:0000:0000:0000:00ff/40'], + ['dead:beef::1/40', 256, 'dead:beef:0000:0000:0000:0000:0000:0100/40'], + ['dead:beef::1/40', 257, 'dead:beef:0000:0000:0000:0000:0000:0101/40'], + ['dead:beef::1/40', 65536, 'dead:beef:0000:0000:0000:0000:0001:0000/40'], + ['dead:beef::1/40', 65537, 'dead:beef:0000:0000:0000:0000:0001:0001/40'], + ); use NetAddr::IP; -use Test::More tests => 4 * @addr + 4; +use Test::More; my($a, $ip, $test); +plan tests => 5 * @addr + 4; + for $a (@addr) { - $ip = new NetAddr::IP $a; - $a =~ s,/\d+,,; + $ip = new NetAddr::IP $a->[0]; + $a->[0] =~ s,/\d+,,; isa_ok($ip, 'NetAddr::IP'); - is($ip->compact_addr, $a); + is($ip->compact_addr, $a->[0]); is($ip->bits, 128); is($ip->version, 6); + is($ip->nth($a->[1]), $a->[2]); } $test = new NetAddr::IP f34::1; @@ -28,3 +48,4 @@ + diff --git a/t/v6-split-bulk.t b/t/v6-split-bulk.t new file mode 100644 index 0000000..bc09a0d --- /dev/null +++ b/t/v6-split-bulk.t @@ -0,0 +1,28 @@ +use Test::More; +use NetAddr::IP; + +# $Id: v6-split-bulk.t,v 1.2 2003/10/09 00:14:06 lem Exp $ + +my @addr = ( + [ 'dead:beef::1', 126, 127, 2 ], + [ 'dead:beef::1', 127, 127, 1 ], + [ 'dead:beef::1', 127, 128, 2 ], + [ 'dead:beef::1', 128, 128, 1 ], + [ 'dead:beef::1', 124, 128, 16 ], + [ 'dead:beef::1', 124, 127, 8 ], + ); + +plan tests => (scalar @addr); + +SKIP: { + + skip "NetAddr::IP cannot properly split() v6 addresses yet...", + scalar @addr unless $ENV{V6DEBUG}; + + for my $a (@addr) { + my $ip = new NetAddr::IP $a->[0], $a->[1]; + my $r = $ip->splitref($a->[2]); +# diag "$_\n" for @$r; + is(@$r, $a->[3]); + } +}; diff --git a/tutorial.htm b/tutorial.htm index 9b252d7..6e297fa 100644 --- a/tutorial.htm +++ b/tutorial.htm @@ -3,7 +3,12 @@ A tutorial for NetAddr::IP -$Id: tutorial.htm,v 1.2 2002/10/31 04:30:23 lem Exp $ +$Id: tutorial.htm,v 1.3 2003/10/09 00:12:22 lem Exp $ + +

This tutorial is kept online at this +location. Please see the online version if you can, as it is probably +more up to date...

What this tutorial is all about...