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

I'm trying to generate a list of all IP adresses in a range. For example 1.2.3.0/24 should generate a list of 1.2.3.0 to 1.2.3.255. This is the code I use:
sub getAllIPs { my $ip = Net::IP->new($range) or die (Net::IP::Error()); my @IPs ; # Loop do { push @IPs, $ip->ip() ; } while (++$ip); return @IPs ; }

This works fine, but when I use 1.2.3.4/23 for instance, I get an Invalid prefix error. That's logical because that's an IP that resides in the middle of a subnet.

Since this is going to be used by people who aren't interested in the technical aspects of networking, I was thinking about something like:

http://jodies.de/ipcalc?host=1.2.3.4&mask1=23&mask2=

where it calculates the first (1.2.2.1) and the last adress (1.2.3.254) and shows every IP in between.

I skimmed the manuals, but don't find any reference as to how you can generate the first and last IP instead of giving an error?

Replies are listed 'Best First'.
Re: Display all IPs in given range
by Discipulus (Canon) on Oct 17, 2016 at 09:48 UTC
    NetAddr::IP can be useful in this case: you can adapt to fill in your array of valid IPs in your subnet (you consider the broadcast one as valid?) see Managing your IP space with Perl
    use NetAddr::IP; my $ip = new NetAddr::IP('10.0.0.0/30'); while ($ip < $ip->broadcast) { print "ip = $ip\n"; $ip ++; }

    L*

    PS the module also has ->first() and ->last() methods that are what you are looking for.

    PPS fixed module link thanks to hippo

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

      Yeah, I consider broadcast as valid. Looks interesting but I'm having some problems with installing the module (dependencies) so I haven't tested it yet.

      PS: call is anonymous but forgot to log in appearantly..

        forgot to log in appearantly.. if so welcome to the monastery Noosrep!

        L*

        There are no rules, there are no thumbs..
        Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Display all IPs in given range
by johngg (Canon) on Oct 17, 2016 at 20:41 UTC

    In the event of a restricted environment where non-core modules are banned, here's a way to do it using only the core Socket module.

    use strict; use warnings; use feature qw{ say }; use Socket; my $ipAddr = shift; my( $quad, $mask ) = split m{/}, $ipAddr; die qq{Bad IP\n} unless my $binAddr = inet_aton( $quad ); my $rxValidMask = do { local $" = q{|}; my @vals = ( 8 .. 30 ); qr{^(?:@vals)$}; }; die qq{Bad mask\n} unless $mask =~ $rxValidMask; my $value = 0xffffffff; $value = do { no warnings qw{ portable }; ( $value <<= 1 ) % 0x100000000; } for 1 .. ( 32 - $mask ); my $binMask = pack q{N}, $value; my $network = $binAddr & $binMask; my $lowMask = $network ^ pack q{H*}, q{00000001}; my $lowAddr = $network | $lowMask; my $highMask = $binMask ^ pack q{H*}, q{ffffffff}; my $highAddr = $network | $highMask; my $hrNetwork = inet_ntoa( $network ) . q{/} . ( unpack( q{B*}, $binMask ) =~ tr{1}{} ); print qq{\n}; my $lineFmt = qq{%-13s: %s %s %s %s : %s\n}; printf $lineFmt x 5, q{IP address}, unpack( q{(a8)*}, unpack( q{B*}, $binAddr ) ), $quad, q{Netmask}, unpack( q{(a8)*}, unpack( q{B*}, $binMask ) ), inet_ntoa( $binMa +sk ), q{Network}, unpack( q{(a8)*}, unpack( q{B*}, $network ) ), $hrNetwork, q{Low address}, unpack( q{(a8)*}, unpack( q{B*}, $lowAddr ) ), inet_ntoa( $lowAd +dr ), q{High address}, unpack( q{(a8)*}, unpack( q{B*}, $highAddr ) ), inet_ntoa( $high +Addr ); print qq{\nAddress range\n}; do { say q{ }, inet_ntoa( $lowAddr ); $lowAddr = pack q{N}, 1 + ( unpack q{N}, $lowAddr ); } while $lowAddr le $highAddr;

    The full output running with a 27-bit mask.

    johngg@shiraz:~/perl/Monks > ./spw1174132 1.2.3.4/27 IP address : 00000001 00000010 00000011 00000100 : 1.2.3.4 Netmask : 11111111 11111111 11111111 11100000 : 255.255.255.224 Network : 00000001 00000010 00000011 00000000 : 1.2.3.0/27 Low address : 00000001 00000010 00000011 00000001 : 1.2.3.1 High address : 00000001 00000010 00000011 00011111 : 1.2.3.31 Address range 1.2.3.1 1.2.3.2 1.2.3.3 1.2.3.4 1.2.3.5 1.2.3.6 1.2.3.7 1.2.3.8 1.2.3.9 1.2.3.10 1.2.3.11 1.2.3.12 1.2.3.13 1.2.3.14 1.2.3.15 1.2.3.16 1.2.3.17 1.2.3.18 1.2.3.19 1.2.3.20 1.2.3.21 1.2.3.22 1.2.3.23 1.2.3.24 1.2.3.25 1.2.3.26 1.2.3.27 1.2.3.28 1.2.3.29 1.2.3.30 1.2.3.31

    Head and tail of a run with an 18-bit mask.

    johngg@shiraz:~/perl/Monks > ./spw1174132 1.2.3.4/18 IP address : 00000001 00000010 00000011 00000100 : 1.2.3.4 Netmask : 11111111 11111111 11000000 00000000 : 255.255.192.0 Network : 00000001 00000010 00000000 00000000 : 1.2.0.0/18 Low address : 00000001 00000010 00000000 00000001 : 1.2.0.1 High address : 00000001 00000010 00111111 11111111 : 1.2.63.255 Address range 1.2.0.1 1.2.0.2 1.2.0.3 1.2.0.4 1.2.0.5 1.2.0.6 1.2.0.7 1.2.0.8 1.2.0.9 1.2.0.10 1.2.0.11 1.2.0.12 1.2.0.13 1.2.0.14 1.2.0.15 1.2.0.16 1.2.0.17 ... 1.2.63.241 1.2.63.242 1.2.63.243 1.2.63.244 1.2.63.245 1.2.63.246 1.2.63.247 1.2.63.248 1.2.63.249 1.2.63.250 1.2.63.251 1.2.63.252 1.2.63.253 1.2.63.254 1.2.63.255

    I hope this is of interest.

    Update: Fixed typo and condensed the address range code slightly.

    Update 2: Fixed line above which was garbled for some reason.

    Cheers,

    JohnGG