diff --git a/IP.pm b/IP.pm index 1a5608a..e33e67a 100644 --- a/IP.pm +++ b/IP.pm @@ -139,7 +139,7 @@ ############################################# -our $VERSION = '3.04'; +our $VERSION = '3.05'; # Preloaded methods go here. @@ -416,6 +416,34 @@ vec($mask, 2, 8) = 0xFF; vec($mask, 3, 8) = _obits $4, $5; } + elsif ($ip =~ m/^(\d+)\.(\d+)\.(\d+)\.(\d+) + \s*-\s*(\d+)\.(\d+)\.(\d+)\.(\d+)$/x + and $1 >= 0 and $1 <= 255 + and $2 >= 0 and $2 <= 255 + and $3 >= 0 and $3 <= 255 + and $4 >= 0 and $4 <= 255 + and $5 >= 0 and $5 <= 255 + and $6 >= 0 and $6 <= 255 + and $7 >= 0 and $7 <= 255 + and $8 >= 0 and $8 <= 255) + { + my $last = ''; + + vec($addr, 0, 8) = $1; + vec($addr, 1, 8) = $2; + vec($addr, 2, 8) = $3; + vec($addr, 3, 8) = $4; + + vec($last, 0, 8) = $5; + vec($last, 1, 8) = $6; + vec($last, 2, 8) = $7; + vec($last, 3, 8) = $8; + + vec($mask, 0, 8) = _obits $1, $5; + vec($mask, 1, 8) = _obits $2, $6; + vec($mask, 2, 8) = _obits $3, $7; + vec($mask, 3, 8) = _obits $4, $8; + } elsif (my $a = gethostbyname($ip)) { if (inet_ntoa($a) =~ m!^(\d+)\.(\d+)\.(\d+)\.(\d+)$!) { vec($addr, 0, 8) = $1; @@ -574,6 +602,14 @@ return do_prefix $mask, \@faddr, \@laddr; } +sub range ($) { + my $self = shift; + my $mask = $self->masklen; + + return undef if $self->{bits} > 32; + return $self->network->addr . ' - ' . $self->broadcast->addr; +} + sub broadcast ($) { my $self = shift; return $self->_fnew($self->_broadcast); @@ -892,6 +928,11 @@ Returns a scalar with the address and mask in CIDR notation. +=item C<-Erange()> + +Returns a scalar with the base address and the broadcast address +separated by a dash and spaces. This is called range notation. + =item C<-Eprefix()> Returns a scalar with the address and mask in prefix @@ -1364,6 +1405,17 @@ =back +=item 3.05 + +=over + +=item * + +Added support for range notation, where base and broadcast addresses +are given as arguments to C<-Enew()>. + +=back + =back =head1 AUTHOR diff --git a/MANIFEST b/MANIFEST index 762eba8..a8f9cca 100644 --- a/MANIFEST +++ b/MANIFEST @@ -13,6 +13,7 @@ t/v4-base.t t/v4-cidr.t t/over-arr.t +t/v4-range.t t/v4-basem.t t/v4-first.t t/wildcard.t diff --git a/README b/README index 5f06b73..54cedb5 100644 --- a/README +++ b/README @@ -1,23 +1,276 @@ NAME NetAddr::IP - Manages IPv4 addresses and subnets -This module provides a simple interface to manipulate IP addresses as -objects. Among the operations that can be done are comparison, tests -for addresses within subnets, enumeration, splitting, summarization -and others. +SYNOPSIS + use NetAddr::IP; -NetAddr::IP objects also "stringify" themselves automatically to -unclutter I/O functions. + my $ip = new NetAddr::IP 'loopback'; -To install, follow the traditional incantations: + print "The address is ", $ip->addr, " with mask ", $ip->mask, "\n" ; -perl Makefile.PL -make -make test -make install + if ($ip->within(new NetAddr::IP "127.0.0.0", "255.0.0.0")) { + print "Is a loopback address\n"; + } -This module has been tested under many platforms, using perl 5.6.0 or -newer. + # This prints 127.0.0.1/32 + print "You can also say $ip...\n"; + +DESCRIPTION + This module provides a number of methods useful for handling IPv4 + addresses ans subnets. Hopefully, its methods are also usable for IPv6 + addresses. + + Methods so far include: + + `->new([$addr, [ $mask ]])' + This method creates a new IPv4 address with the supplied address in + `$addr' and an optional netmask `$mask', which can be omitted to get + a /32 mask. + + `$addr' can be almost anything that can be resolved to an IP address + in all the notations I have seen over time. It can optionally + contain the mask in CIDR notation. + + If called with no arguments, 'default' is assumed. + + `->broadcast()' + Returns a new object refering to the broadcast address of a given + subnet. + + `->network()' + Returns a new object refering to the network address of a given + subnet. + + `->addr()' + Returns a scalar with the address part of the object as a + dotted-quad. + + `->mask()' + Returns a scalar with the mask as a dotted-quad. + + `->masklen()' + Returns a scalar the number of one bits in the mask. + + `->cidr()' + Returns a scalar with the address and mask in CIDR notation. + + `->numeric()' + When called in a scalar context, will return a numeric + representation of the address part of the IP address. When called in + an array contest, it returns a list of two elements. The first + element is as described, the second element is the numeric + representation of the netmask. + + `$me->contains($other)' + Returns true when `$me' completely contains `$other'. False is + returned otherwise and `undef' is returned if `$me' and `$other' are + of different versions. + + `$me->within($other)' + The complement of `->contains()'. Returns true when `$me' is + completely con tained within `$other'. + + `->split($bits)' + Returns a list of objects, representing subnets of `$bits' mask + produced by splitting the original object, which is left unchanged. + Note that `$bits' must be longer than the original object's mask in + order for it to be splittable. + + Note that `$bits' can be given as an integer (the length of the + mask) or as a dotted-quad. If omitted, a host mask is assumed. + + `->splitref($bits)' + A (faster) version of `->split()' that returns a reference to a list + of objects instead of a real list. This is useful when large numbers + of objects are expected. + + `->hostenum()' + Returns the list of hosts within a subnet. + + `->hostenumref()' + Faster version of `->hostenum()', returning a reference to a list. + + `$me->compact($addr1, $addr2, ...)' + Given a list of objects (including `$me'), this method will compact + all the addresses and subnets into the largest (ie, least specific) + subnets possible that contain exactly all of the given objects. + + Note that in versions prior to 3.02, if fed with the same IP subnets + multiple times, these subnets would be returned. From 3.02 on, a + more "correct" approach has been adopted and only one address would + be returned. + + `$me->compactref(\@list)' + As usual, a faster version of =item `->compact()' that returns a + reference to a list. Note that this method takes a reference to a + list instead. + + `->first()' + Returns a new object representing the first useable IP address + within the subnet (ie, the first host address). + + `->last()' + Returns a new object representing the last useable IP address within + the subnet (ie, one less than the broadcast address). + + `->num()' + Returns the number of useable addresses IP addresses within the + subnet, not counting the broadcast address. + + In addition to the methods, some functions are overloaded to ease + manipulation of the objects. The available operations are: + + Stringification + An object can be used just as a string. For instance, the following + code + + my $ip = new NetAddr::IP 'loopback'; + print "$ip\n"; + + Will print the string 127.0.0.1/8. + + Equality + You can test for equality with either `eq' or `=='. + + Dereferencing as an ARRAY + You can do something along the lines of + + my $net = new NetAddr::IP $cidr_spec; + for my $ip (@$net) { + print "Host $ip is in $net\n"; + } + + However, note that this might generate a very large amount of items + in the list. You must be careful when doing this kind of expansion. + + EXPORT + + None by default. + +HISTORY + 0.01 + * original version; Basic testing and release to CPAN as version + 0.01. This is considered beta software. + + 0.02 + * Multiple changes to fix endiannes issues. This code is now + moderately tested on Wintel and Sun/Solaris boxes. + + 0.03 + * Added ->first and ->last methods. Version changed to 0.03. + + 1.00 + * 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. + + 1.10 + * 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. + + 1.20 + * Implemented ->compact and ->expand methods. + + * Applying for official name + + 1.21 + * 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 + * Released under the new *official* name of NetAddr::IP + + 2.10 + * Added support for ->new($min, $max, $bits) form + + * Added ->to_numeric. This helps serializing objects + + 2.20 + * Chris Dowling reported that the sort method introduced in v1.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 + + 2.21 + * Dennis Boylan pointed out a bug under Linux and perhaps other + platforms as well causing the error "Sort subroutine didn't + return single value at + /usr/lib/perl5/site_perl/5.6.0/NetAddr/IP.pm line 299, <> line + 2." or similar. This was fixed. + + 2.22 + * Some changes suggested by Jeroen Ruigrok and Anton Berezin were + included. Thanks guys! + + 2.23 + * Bug fix for /XXX.XXX.XXX.XXX netmasks under v5.6.1 suggested by + Tim Wuyts. Thanks! + + * Tested the module under MACHTYPE=hppa1.0-hp-hpux11.00. It is now + konwn to work under Linux (Intel/AMD), Digital Unix (Alpha), + Solaris (Sun), HP-UX11 (HP-PA-RISC), Windows 9x/NT/2K (using + ActiveState on Intel). + + 2.24 + * A spurious warning when expand()ing with -w under certain + circumstances was removed. This involved using /31s, /32s and + the same netmask as the input. Thanks to Elie Rosenblum for + pointing it out. + + * Slight change in license terms to ease redistribution as a + Debian package. + + 3.00 + This is a major rewrite, supposed to fix a number of issues + pointed out in earlier versions. + + The goals for this version include getting rid of BigInts, + speeding up and also cleaning up the code, which is written in a + modular enough way so as to allow IPv6 functionality in the + future, taking benefit from most of the methods. + + Note that no effort has been made to remain backwards compatible + with earlier versions. In particular, certain semantics of the + earlier versions have been removed in favor of faster + performance. + + This version was tested under Win98/2K (ActiveState + 5.6.0/5.6.1), HP-UX11 on PA-RISC (5.6.0), RedHat Linux 6.2 + (5.6.0), Digital Unix on Alpha (5.6.0), Solaris on Sparc (5.6.0) + and possibly others. + + 3.01 + * Added `->numeric()'. + + * `->new()' called with no parameters creates a default + NetAddr::IP object. + + 3.02 + * Fxed `->compact()' for cases of equal subnets or + mutually-contained IP addresses as pointed out by Peter Wirdemo. + Note that now only distinct IP addresses will be returned by + this method. + + * Fixed the docs as suggested by Thomas Linden. + + * Introduced overloading to ease certain common operations. + + * + Fixed compatibility issue with C<-Enum()> on 64-bit processors. + +AUTHOR + Luis E. Munoz WARRANTY This software comes with the same warranty as perl itself (ie, none), so @@ -29,4 +282,6 @@ the author is preserved in the form of this copyright notice and license for this module. +SEE ALSO + perl(1). diff --git a/t/v4-range.t b/t/v4-range.t new file mode 100644 index 0000000..d4da8a8 --- /dev/null +++ b/t/v4-range.t @@ -0,0 +1,41 @@ +use NetAddr::IP; + +my @ranges = ( + [ '10.0.0.0/8', '10.0.0.0', '10.255.255.255' ], + [ '192.168.0.0/16', '192.168.0.0', '192.168.255.255' ], + ); + +print "1..", (3 * scalar @ranges), "\n"; + +my $count = 1; + +for my $r (@ranges) { + my $r1 = new NetAddr::IP $r->[1] . '-' . $r->[2]; + + if ($r1 and $r1 eq $r->[0]) { + print "ok $count\n"; + } + else { + print "not ok $count\n"; + } + ++ $count; + + $r1 = new NetAddr::IP $r->[1] . ' - ' . $r->[2]; + if ($r1 and $r1 eq $r->[0]) { + print "ok $count\n"; + } + else { + print "not ok $count\n"; + } + ++ $count; + + $r1 = new NetAddr::IP $r->[0]; + if ($r1 and $r1->range eq $r->[1] . ' - ' . $r->[2]) { + print "ok $count\n"; + } + else { + print "not ok $count\n"; + } + ++ $count; +} +