Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Get network information from supplied IPv4 address & netmask

by johngg (Canon)
on Mar 03, 2020 at 15:55 UTC ( #11113711=CUFP: print w/replies, xml ) Need Help??

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

Replies are listed 'Best First'.
Re: Get network information from supplied IPv4 address & netmask
by jwkrahn (Monsignor) on Mar 03, 2020 at 23:23 UTC

    I wrote something similar to that a few years ago:

    #!/usr/bin/perl use warnings; use strict; use Socket; $0 =~ s|.*/||; @ARGV == 2 or die "usage: $0 address netmask\n"; my $address = inet_aton( shift ); my $netmask = inet_aton( shift ); my $bits = unpack '%32b*', $netmask; my $class = vec( $address, 7, 1 ) ? vec( $address, 6, 1 ) ? vec( $addr +ess, 5, 1 ) ? 'D' : 'C' : 'B' : 'A'; printf "Address: %15s\n", inet_ntoa( $address ); printf "Netmask: %15s\n", inet_ntoa( $netmask ); printf "Network: %15s/%d (Class %s)\n", inet_ntoa( $netmask & $add +ress ), $bits, $class; printf "Broadcast: %15s\n", inet_ntoa( ~$netmask | $add +ress ); printf "HostMin: %15s\n", inet_ntoa( ($netmask & $add +ress) | "\x00\x00\x00\x01" ); printf "HostMax: %15s\n", inet_ntoa( (~$netmask | $add +ress) & "\xFF\xFF\xFF\xFE" ); printf "Hosts/Net: %15s\n", 2 ** ( 32 - $bits ) - 2;
Re: Get network information from supplied IPv4 address & netmask
by Fletch (Chancellor) on Mar 03, 2020 at 19:05 UTC

    Shades of Net::Netmask . . .

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (3)
As of 2020-11-28 17:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?