Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Iterating through all IP addresses in a CIDR

by grinder (Bishop)
on Nov 04, 2003 at 13:53 UTC ( [id://304414]=perlquestion: print w/replies, xml ) Need Help??

grinder has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to be Lazy and find a module that will iterate through an arbitrary CIDR for me. For example:

172.18.0.0/18
172.19.1.0/24
172.20.2.0/28
172.21.3.128/30

My first impulse was to dig out Net::CIDR and use cidr2octets but that only returns the leading octets representing the netblock in question. E.g., cidr2octets("172.19.1.0/24") returns 172.19.1. So then I turned to CPAN and found Net::IPv4Addr but, at a first brief glance, that doesn't help me. I'm sure there's a module that does what I want, I just don't know its name...

To be precise, I want something that takes something like 172.21.3.128/30 and returns

172.21.3.128
172.21.3.129
172.21.3.130
172.21.3.131

Thanks for any pointers (or code :)

Update: NetAddr::IP is indeed the ticket (so I guess patching Net::CIDR isn't necessary, although I will write to Sam suggesting a SEE ALSO item in the documentation of Net::CIDR).

For those following along at home, given an array of CIDR netblocks in @cidr, the following code will print all the IP addresses. Short, sharp and sweet.

for my $cidr( @cidr ) { print "$cidr\n"; my $n = NetAddr::IP->new( $cidr ); for my $ip( @{$n->hostenumref} ) { print "\t", $ip->addr, "\n"; } }

Replies are listed 'Best First'.
Re: Iterating through all IP addresses in a CIDR
by holo (Monk) on Nov 04, 2003 at 14:17 UTC

    Try NetAddr::IP

Re: Iterating through all IP addresses in a CIDR
by phydeauxarff (Priest) on Nov 04, 2003 at 15:09 UTC
    We had to do the same thing for our IP management system at work.

    Take a look at Net::Netmask, specifically the enumerate method which will return a list of the IPs within a block

Re: Iterating through all IP addresses in a CIDR
by BrowserUk (Patriarch) on Nov 04, 2003 at 16:22 UTC

    Only deals with IPv4.. but extending it wouldn't be hard.

    #! perl -slw use strict; our $M ||= 30; our $IP ||= '1.2.3.4'; sub bin2dd{ join '.', unpack 'C4', pack 'N', $_[0] } sub dd2bin{ unpack 'N', pack'C4', split'\.', $_[0] } sub CIDRList{ my $iter = 0xffffffff >> $_[0]; my $mask = ~$iter; my $lo = dd2bin( $_[1] ) & $mask; map{ bin2dd $lo++ } 0 .. $iter; } print for CIDRList $M, $IP; __END__ P:\test>CIDR -M=28 -IP=64.96.128.0 64.96.128.0 64.96.128.1 64.96.128.2 64.96.128.3 64.96.128.4 64.96.128.5 64.96.128.6 64.96.128.7 64.96.128.8 64.96.128.9 64.96.128.10 64.96.128.11 64.96.128.12 64.96.128.13 64.96.128.14 64.96.128.15

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    Hooray!
    Wanted!

Re: Iterating through all IP addresses in a CIDR
by DrHyde (Prior) on Nov 04, 2003 at 14:30 UTC
    No doubt Sam Varshavchik would welcome patches for Net::CIDR. He was happy to accept the patches I sent him to add the addr2cidr and addrandmask2cidr functions. Just remember that he wants functions to work with IPv6 addresses as well. Thankfully, using the functions he's provided for turning IPv6 addresses into a list of octets (which is a weird but convenient way of representing v6 addresses) means that the extra code to handle them is pretty trivial.
Re: Iterating through all IP addresses in a CIDR
by l2kashe (Deacon) on Nov 04, 2003 at 17:47 UTC

    Heres a nifty line to compute number of addresses based on the CIDR.

    my $cidr = 24; my $ips = 1 << (32 - $cidr); # alternately if your block is a /24 or larger (more IPS) # then you could do my $networks = (1 << (32 - $cidr)) / 256; # /24 == 1 # /23 == 2 etc..

    Just remember that the first snippet is the total number of IPs in the block, not actual usable. There are all sorts of fun ways to play with this. The logic gets a little tricky based on the smaller blocks, and determining if a network address for the block is on a valid boundary, but its certainly doable. Also module use for this kind of work is a GoodThing(TM). I ended up going through the pains of figuring it all out recently, as I thought the code was going to be semi-throwaway.

    use perl;

Re: Iterating through all IP addresses in a CIDR
by Roger (Parson) on Nov 05, 2003 at 05:17 UTC
    In the spirit of there is more than one way to do it, here is my solution to the problem without using any of the CPAN modules. Just straight forward divide and conquer.

    use strict; chomp(my @CIDR = <DATA>); foreach (@CIDR) { if (/\//) { # expand the address list my ($base, $range) = /(\d+\.\d+\.\d+\.)(.*)/; my ($r0, $r1) = split /\//, $range; if ($r1 < $r0) { die "invalid ip range" if length($r1) >= length($r0); $r1 = substr($r0, 0, length($r0) - length($r1)) . $r1; } print "$base$_\n" for $r0 .. $r1; } elsif (/-/) { my ($base, $from, $to) = /(\d+\.\d+\.\d+\.)(\d+)-\d+\.\d+\.\d+\.(\ +d+)/; print "$base$_\n" for $from .. $to; } else { # singular IP address print "$_\n"; } } __DATA__ 192.168.0.1 172.18.0.0/5 172.19.1.0/4 172.20.2.0/8 172.21.3.128/130 100.0.0.1-100.0.0.3 172.21.3.128/110
    And the output (last entry has incorrect range) -
    192.168.0.1 172.18.0.0 172.18.0.1 172.18.0.2 172.18.0.3 172.18.0.4 172.18.0.5 172.19.1.0 172.19.1.1 172.19.1.2 172.19.1.3 172.19.1.4 172.20.2.0 172.20.2.1 172.20.2.2 172.20.2.3 172.20.2.4 172.20.2.5 172.20.2.6 172.20.2.7 172.20.2.8 172.21.3.128 172.21.3.129 172.21.3.130 100.0.0.1 100.0.0.2 100.0.0.3 invalid ip range at p20.pl line 12, <DATA> line 7.
    Update: added simple IP - IP processing for smackdab.

Re: Iterating through all IP addresses in a CIDR
by smackdab (Pilgrim) on Nov 05, 2003 at 05:58 UTC
    In a similar vein, can this format be extended, so that I can specifiy a range of ip addresses:

    ie: 192.168.0.1-192.168.0.100
Re: Iterating through all IP addresses in a CIDR
by runrig (Abbot) on Mar 05, 2014 at 18:18 UTC
    Just noting that it would also be simple to get Net::CIDR::Lite to do this with the list_short_range() function, converting simple integer ranges like '5-7' to the separate values. It would be straightforward to just add this functionality also.
Re: Iterating through all IP addresses in a CIDR
by Anonymous Monk on Oct 21, 2009 at 16:11 UTC
    Did you actually try it? use NetAddr::IP; my $n = NetAddr::IP->new( '172.21.3.128/30' ); for my $ip( @{$n->hostenumref} ) { print "\t", $ip->addr, "\n"; } produces: 172.21.3.129 172.21.3.130 Which isn't what you asked for your in your requirement.
      use NetAddr::IP; my $n = NetAddr::IP->new('172.21.3.128/30' ); my $bits = $n->bits(); for my $ip( @{ $n->splitref( $bits ) } ) { print "\t", $ip->addr, "\n"; }

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (4)
As of 2024-03-29 13:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found