Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Module for working with IP Addresses and Ranges

by ait (Friar)
on Oct 22, 2010 at 12:29 UTC ( #866795=perlquestion: print w/ replies, xml ) Need Help??
ait has asked for the wisdom of the Perl Monks concerning the following question:

Hello my fellow monkymen,

I'm looking for a module that can tell me if an IP is in a range. For example, I have a file with a bunch of IP ranges of spammers in the form:

192.168.1.120-192.168.1.141

I want to know if IP address X is in the range above. I looked at too many modules on the CPAN already and some seem to suck big time, so I am asking for advice on which would be the best module to use for this application IYO.

TIA,

Alejandro Imass

Update 1:
Very decent ones seem to be Net::IP::Match by Marcel Grünauer and Net::IP::Match::Regexp by Chris Dolan but they don't really fit my purpose exactly because they seem to use CIDR only. I'm sure there has to be similar decent modules for ranges in the form above!

Update 2:
Paul Bennett's Net::IPAddress::Util and related modules seem very cool and probably fit my bill. Any other suggestions?

Comment on Module for working with IP Addresses and Ranges
Re: Module for working with IP Addresses and Ranges
by halfcountplus (Hermit) on Oct 22, 2010 at 13:30 UTC

    It's your choice, but you don't really need a module for this. The simplest way might just be to match the first three numbers, then do a ">= and <=" on the range in the last one.

    A slightly more elegant method exploits the fact that IPv4 address are actually 4 byte values -- notice each number ranges from 0-255 (an unsigned, one byte char). If you pack them in order you have a "big endian" (aka. network byte order) number, which is actually how low level networking uses them. Making this easy:

    #!/usr/bin/perl -w use strict; sub dot2int { my $address = pop; my @bytes; while ($address =~ /(\d+)/g) { push @bytes,$1 } return unpack('N',pack('C*',@bytes)); } my $first = dot2int('192.168.1.120'); my $last = dot2int('192.168.1.141'); my @testcases = qw( 192.168.1.130 193.168.1.122 255.0.0.27 192.168.1.127 192.168.1.144 192.168.1.139 ); print "$first to $last = ". ($last-$first)." addresses in range\n"; foreach (@testcases) { print $_; my $int = dot2int($_); if ($int >= $first && $int <= $last) { print " spammer!!!\n"; } else { print " OK.\n" } }

    The output:

    3232235896 to 3232235917 = 21 addresses in range
    192.168.1.130 spammer!!!
    193.168.1.122 OK.
    255.0.0.27 OK.
    192.168.1.127 spammer!!!
    192.168.1.144 OK.
    192.168.1.139 spammer!!!

    I would assume there is a module somewhere that includes a function like that, but I can't tell you which one.

      By the way,
      my @bytes; while ($address =~ /(\d+)/g) { push @bytes,$1 }
      can be written as
      my @bytes = $address =~ /(\d+)/g;
      so you end up with
      unpack('N', pack('C*', $address =~ /(\d+)/g))
      It's your choice, but you don't really need a module for this. The simplest way might just be to match the first three numbers, then do a ">= and <=" on the range in the last one.

      While that would work for the example given, it wouldn't work if he needed to see if an address was in the range 192.168.0.0 - 192.168.1.255.

      Works like a charm, finally wound up using most of your example above. many thanks!

      Alex

Re: Module for working with IP Addresses and Ranges
by Kanji (Parson) on Oct 22, 2010 at 13:31 UTC

    Not sure on how you're judging suckage, but Net::Netmask includes the helper function range2cidrlist that will turn an arbitrary range into an equivalent array of CIDRs (actually, Net::Netmask objects):-

    my $is_in_range = grep $_->match($ip_x), range2cidrlist($ip_range_start, $ip_range_end);

    (match is a Net::Netmask method.)

        --k.


      Thanks for tip on CIDR.
      Not sure on how you're judging suckage, but...

      Interesting you highlighted that part of my post. I know that criticism is not very popular, so shoot me me. Maybe it's just me but it's my impression that the "IP" related modules need some revision/cleanup, at least when compared to other similar parts of the CPAN (example: HTTP:x modules). Again, it may very well be an incorrect perception but in these IP modules I noticed: namespace scattering/pollution on all the "IP", "NetAddr", "Net", etc... is really confusing. Several modules seemed to do the same thing, a lot of wheel re-invention IMO, some are poorly or carelessly documented, and several other things.

Re: Module for working with IP Addresses and Ranges
by DrHyde (Prior) on Oct 25, 2010 at 09:41 UTC
    IMO the canonical tool for this is Net::CIDR. The interface and documentation is kinda clunky in some ways, but it works, and works very well, for both IPv4 and IPv6.
    $ perl -MNet::CIDR -e ' print Net::CIDR::cidrlookup( "192.168.1.130", Net::CIDR::range2cidr("192.168.1.120-192.168.1.141") )' 1 $ perl -MNet::CIDR -e ' print Net::CIDR::cidrlookup( "192.168.1.180", Net::CIDR::range2cidr("192.168.1.120-192.168.1.141") )' 0

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://866795]
Approved by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (13)
As of 2014-12-17 21:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (34 votes), past polls