#!/usr/bin/perl # Script for listing the IP addresses contained in a CIDR netblock. # Originally written to help someone out at work. # Copyright Rayner Lucas 2005-2018. use Getopt::Long; use Net::CIDR qw(:all); use strict; use warnings; my $VERSION = 1.0; # Options my $number_opt = ''; my $range_opt = ''; my $list_opt = ''; my $help_opt = ''; my $version_opt = ''; GetOptions( 'number' => \$number_opt, 'range' => \$range_opt, 'list' => \$list_opt, 'help' => \$help_opt, 'version' => \$version_opt ); # If no options given, assume --range. if (!$number_opt && !$range_opt && !$list_opt && !$help_opt && !$version_opt) { $range_opt = 'true'; } my $help_text = <<HELPTEXT; Usage: cidr2range [OPTIONS] [ADDRESS/MASK] List IP addresses in a CIDR netblock. Options: -l, --list List individual IP addresses, one address per line -n, --number Print number of IP addresses in the given block -r, --range Print the range of IP addresses in the given block -h, --help Print this help message and exit -v, --version Print version information and exit If no options are specified, --range is assumed. Example: ./cidr2range -r 192.168.1.2/23 The script contains full documentation, which you may be able to read with the command "perldoc cidr2range.pl". HELPTEXT if ($help_opt) { print $help_text; exit(0); } if ($version_opt) { print "cidr2range $VERSION\n"; print "Copyright R Lucas 2005-2010.\n"; print "This program is free software. You may copy or redistribute it "; print "under \nthe same terms as Perl itself.\n"; exit(0); } # Argument checking # fail_validation: function to be called when argument validation fails. # Prints a message and exits with a failure status code. # # Arguments: # message: failure message to print to STDERR. sub fail_validation { my $message = shift; print STDERR "$message\n"; exit(1); } my ($addr, $mask); my ($w, $x, $y, $z); if (!$ARGV[0]) { fail_validation("Invalid address or netmask. Use cidr2range --help for help."); } else { ($addr, $mask) = split(/\//, $ARGV[0]); ($w, $x, $y, $z) = split(/\./, $addr); foreach my $octet ($w, $x, $y, $z) { if (!defined($octet) || ($octet !~ /^\d+$/) || ($octet < 0) || ($octet > 255)) { fail_validation("Invalid address or netmask. Use cidr2range --help for help."); } } } if (!defined($mask) || $mask !~ /^\d+$/) { fail_validation("Invalid address or netmask. Use cidr2range --help for help."); } # Check that the address is valid. if (!cidrvalidate("$w.$x.$y.$z")) { fail_validation("Address specified was not valid. Use cidr2range --help for help."); } # Check netmask is within the limits of mathematical possibility. if ($mask < 0 || $mask > 32) { fail_validation("Netmask must be a number from 0 to 32. Use cidr2range --help for help."); } # Right, lets get to work. if ($number_opt) { my $num = 2**(32 - $mask); print "$num address" . ($num != 1 ? "es" : '') . ".\n"; } my @cidr_list = ("$w.$x.$y.$z/$mask"); my @range_list = cidr2range(@cidr_list); if ($range_opt) { print "Address range: " . $range_list[0] . "\n"; } if ($list_opt) { # Find the start address in the netblock and store it in $w, $x, $y, $z. my @addresses = split(/\-/, $range_list[0]); my @octets = split(/\./, $addresses[0]); $w = $octets[0]; $x = $octets[1]; $y = $octets[2]; $z = $octets[3]; # Count up through the addresses and print each one. for (my $count = 2**(32 - $mask); $count > 0; $count--) { # If the other error checks work properly, this error should # never happen. if ($w > 255) { fail_validation("Invalid address/mask specified: leftmost octet would be greater than 255. Use cidr2range --help for help."); } print "$w.$x.$y.$z\n"; $z++; if ($z > 255) { $y++; $z = 0; } if ($y > 255) { $x++; $y = 0; } if ($x > 255) { $w++; $x = 0; } } } exit(0); =head1 NAME cidr2range - convert CIDR notation to a range or list of IP addresses. =head1 SYNOPSIS B<cidr2range> I<[OPTIONS]> I<address>B</>I<mask> =head1 DESCRIPTION This command converts an address block in CIDR notation (address/netmask) into a range, list, or number of IP addresses. Options are: =over 4 =item B<-l, --list> list all IP addresses in the given CIDR block, one per line. =item B<-n, --number> print the number of IP addresses in the given CIDR block. =item B<-r, --range> print the range of IP addresses for the given CIDR block. =item B<-h, --help> display help text and exit. =item B<-v, --version> display version information and exit. =back The B<--list>, B<--number>, and B<--range> options can be combined, so specifying all three will cause the command to print the number of addresses, the range of addresses, and all the individual IP addresses for the specified block. If no options are given, B<--range> is assumed. =head1 EXAMPLES =over 4 =item cidr2range -l 192.168.1.2/30 Prints the list of IP addresses from 192.168.1.0 to 192.168.1.3, one address per line. =back =head1 README Converts CIDR notation (e.g. 192.168.1.1/23) to a list or range of IP addresses. =head1 PREREQUISITES This script requires the C<Net::CIDR> and C<Getopt::Long> modules. It also uses the C<strict> and C<warnings> pragmas. =head1 COPYRIGHT Copyright Rayner Lucas, 2005-2010. This program is free software. You may copy or redistribute it under the same terms as Perl itself. =pod OSNAMES any =pod SCRIPT CATEGORIES Networking =cut