http://qs321.pair.com?node_id=11113711

I expect there are plenty of tools out there to do this but I had to resort to paper and pencil after someone unplugged the wrong wires in a datacentre ... not me I hasten to add! A script to do the job was called for, especially as I worked in a closed environment where getting any bought-in application approved was a labour of Hercules. This is a tidied up version of the original which might be useful to someone out there.

#!/usr/bin/perl # # Use strictures and warnings. Use Getopt::Long for options parsing # and Socket for manipulation of IP quads. # use strict; use warnings; use Getopt::Long; use Socket; # Declare option scalars. # my $address; my $netmask; my $hexmask; my $help; # Parse command line options, die if bad. # my $rhOpts = { address => \ $address, netmask => \ $netmask, hexmask => \ $hexmask, help => \ $help, }; my $getoptRes = GetOptions( $rhOpts, q{address=s}, q{netmask=s}, q{hexmask=s}, q{help} ); die qq{\n} unless $getoptRes; # Show help text then terminate if requested. # die <<__EOT__ if $help; User Commands tellNe +twork Name: tellNetwork - given an IP address and netmask, outputs +which network the address belongs to Synopsis: tellNetwork --address nnn.nnn.nnn.nnn/nn tellNetwork --address nnn.nnn.nnn.nnn --hexmask xxxxxxx +x tellNetwork --address nnn.nnn.nnn.nnn --netmask nnn.nnn +.nnn.nnn tellNetwork --help Description: Script that takes an IPv4 address and a netmask, either + in decimal quad or hexadecimal form, and calculates the network number and low/high addresses. The script does +not do any validation of the netmask in relation to the IPv +4 class of the supplied address, e.g. a /10 netmask on a class C address would not be flagged as an error Options: --address IP address in decimal quad form with the possibility of slash notation netmask app +ended --netmask Netmask in decimal quad form --hexmask Netmask in hexadecimal form --help display this help text Files: /path/to/bin/tellNetwork this executable script file Dependencies: No non-core dependencies __EOT__ # Create a hash of valid netmask values keyed by slash notation mask # width. # my %validNetmasks; my $value = 0xfffffffc; for my $maskLen ( reverse 8 .. 30 ) { my $netmask = pack q{N}, $value; $validNetmasks{ $maskLen } = $value; $validNetmasks{ sprintf q{%x}, $value } ++; $validNetmasks{ sprintf q{%X}, $value } ++; $validNetmasks{ inet_ntoa( $netmask ) } ++; $value = do { no warnings qw{ portable }; ( $value <<= 1 ) % 0x100000000; }; } # Check that we have the mandatory options, --address that includes a # slash notation netmask on its own or --address not including netmask # and either one or the other but not both of --netmask and --hexmask. # my $hasSlash; if ( not defined $address ) { die qq{tellNetwork: Incorrect options: must have --address and, if\ +n}, qq{ address does not include an appended slash\n}, qq{ notation netmask, either --netmask or --hexmask +\n}; } elsif ( $address =~ m{^(?:\d{1,3}\.){3}\d{1,3}/\d\d?$} ) { $hasSlash ++; die qq{tellNetwork: Incorrect options: --netmask or --hexmask shoul +d\n}, qq{ not be supplied if address includes slash notat +ion\n}, qq{ netmask\n} if $netmask or $hexmask; } else { die qq{tellNetwork: Incorrect options: if --address without a slash +\n}, qq{ notation netmask is supplied then one of either +\n}, qq{ --netmask or --hexmask must also be present\n} unless $netmask xor $hexmask; } # Check that supplied options are valid. # my $nBitsMask; my $binAddr; do { ( $address, $nBitsMask ) = split m{/}, $address; die qq{Invalid slash notation netmask\n} unless $validNetmasks{ $nBitsMask }; } if $hasSlash; die qq{Invalid IP address\n} unless $binAddr = validQuad( $address ); die qq{Invalid decimal quad netmask - $netmask\n} if $netmask and not $validNetmasks{ $netmask }; die qq{Invalid hexadecimal netmask - $hexmask\n} if $hexmask and not $validNetmasks{ $hexmask }; # Convert netmask to binary numeric values with either the # Socket module's inet_aton() if decimal quads or pack with the # 'H*' template if a hexadecimal string. # my $binMask; if ( $hasSlash ) { $binMask = pack q{N}, $validNetmasks{ $nBitsMask }; } elsif ( $netmask ) { $binMask = inet_aton( $netmask ); } else { $binMask = pack q{H*}, $hexmask; } # Calculate the network number by binary AND'ing the address and # netmask. Get human-readable nnn.nnn.nnn.nnn/nn form for output. # my $network = $binAddr & $binMask; my $readable = inet_ntoa( $network ) . q{/} . ( unpack( q{B*}, $binMask ) =~ tr{1}{} ); # Calculate the lowest IP address in the range by binary or'ing the # network with the network xor'ed with a value of 0x1. # my $lowMask = $network ^ pack q{H*}, q{00000001}; my $lowAddr = $network | $lowMask; # Calculate the highest IP address in the range by binary OR'ing the # network with the netmask XOR'ed with a value of 0xffffffff. # my $highMask = $binMask ^ pack q{H*}, q{ffffffff}; my $highAddr = $network | $highMask; # Output nicely formatted results. # print qq{\n}; my $lineFmt = qq{%-13s: %s %s %s %s : %s\n}; printf $lineFmt x 5, q{IP address}, unpack( q{(B8)*}, $binAddr ), $address, q{Netmask}, unpack( q{(B8)*}, $binMask ), inet_ntoa( $binMask ), q{Network}, unpack( q{(B8)*}, $network ), $readable, q{Low address}, unpack( q{(B8)*}, $lowAddr ), inet_ntoa( $lowAddr ), q{High address}, unpack( q{(B8)*}, $highAddr ), inet_ntoa( $highAddr ); print qq{\n}; # Subroutine to check that string is a valid decimal IP quad. # # --------- sub validQuad # --------- { my $quad = shift; my $packed = inet_aton( $quad ); return defined $packed ? $packed : 0; }

Some example usage.

johngg@shiraz:~/perl/utils$ for i in `seq 11 15`; do ./tellNetwork --a +ddress 17.23.175.209/$i; done IP address : 00010001 00010111 10101111 11010001 : 17.23.175.209 Netmask : 11111111 11100000 00000000 00000000 : 255.224.0.0 Network : 00010001 00000000 00000000 00000000 : 17.0.0.0/11 Low address : 00010001 00000000 00000000 00000001 : 17.0.0.1 High address : 00010001 00011111 11111111 11111111 : 17.31.255.255 IP address : 00010001 00010111 10101111 11010001 : 17.23.175.209 Netmask : 11111111 11110000 00000000 00000000 : 255.240.0.0 Network : 00010001 00010000 00000000 00000000 : 17.16.0.0/12 Low address : 00010001 00010000 00000000 00000001 : 17.16.0.1 High address : 00010001 00011111 11111111 11111111 : 17.31.255.255 IP address : 00010001 00010111 10101111 11010001 : 17.23.175.209 Netmask : 11111111 11111000 00000000 00000000 : 255.248.0.0 Network : 00010001 00010000 00000000 00000000 : 17.16.0.0/13 Low address : 00010001 00010000 00000000 00000001 : 17.16.0.1 High address : 00010001 00010111 11111111 11111111 : 17.23.255.255 IP address : 00010001 00010111 10101111 11010001 : 17.23.175.209 Netmask : 11111111 11111100 00000000 00000000 : 255.252.0.0 Network : 00010001 00010100 00000000 00000000 : 17.20.0.0/14 Low address : 00010001 00010100 00000000 00000001 : 17.20.0.1 High address : 00010001 00010111 11111111 11111111 : 17.23.255.255 IP address : 00010001 00010111 10101111 11010001 : 17.23.175.209 Netmask : 11111111 11111110 00000000 00000000 : 255.254.0.0 Network : 00010001 00010110 00000000 00000000 : 17.22.0.0/15 Low address : 00010001 00010110 00000000 00000001 : 17.22.0.1 High address : 00010001 00010111 11111111 11111111 : 17.23.255.255 johngg@shiraz:~/perl/utils$ ./tellNetwork --address 203.176.10.197 --h +exmask ffffffe0 IP address : 11001011 10110000 00001010 11000101 : 203.176.10.197 Netmask : 11111111 11111111 11111111 11100000 : 255.255.255.224 Network : 11001011 10110000 00001010 11000000 : 203.176.10.192/27 Low address : 11001011 10110000 00001010 11000001 : 203.176.10.193 High address : 11001011 10110000 00001010 11011111 : 203.176.10.223

I hope this is of interest.

Cheers,

JohnGG