#!/usr/bin/perl # file: inetaddr.pl, Marcus Fritzsch, http://fritschy.de, 20050330 # desc: some calculations of ipv4-addr formats # license: GPL # $Id: inetaddr.pl,v 1.15 2005/04/11 00:10:09 m Exp $ use warnings; use strict; use IO::Socket; # [hn]to[nh][sl] sub htons ($) { return unpack 'v', pack 'n', shift; } sub htonl ($) { return unpack 'V', pack 'N', shift; } # transforms an ip-address in dotted-quad format to an unsigned int sub inaddr ($) { return unpack 'N', inet_aton shift; } #sub inaddr ($) { return unpack 'N', pack 'C*', split /\./, shift; } # convert an inet-address to dotted-quad format sub addr ($) { return inet_ntoa pack 'N', shift; } #sub addr ($) { return join '.', unpack 'C*', pack 'N', shift; } print 'htons (12) = ', htons (12), "\n"; print 'inaddr (192.168.102.9) = ', inaddr ('192.168.102.9'), "\n"; print 'addr (3232261641) = ', addr (3232261641), "\n\n"; ######################################################################## # parseIpNet ($) # # this is a quite spghetti-like one, it takes as argument an ip address # or a subnet sepcification like 10/8 or 10.0.0.0/255.240.0.0 # # out of the input, it calculates all possible values, i.e. address, # network broadcast, netmask, low-host, high-host and bits on the # netmask # # well, it depends on the input what need to be calculated and what is # already given. # # If some data does not make much sense, like a broadcast for a single # address (input e.g.: 192.168.103.2) or an address for an entire # network (input e.g.: 172.16/12) - these are replaced by '-' as output # # ok, this subroutine does not return any data - but feel free to make # it return something useful ;) # # PS: I never said this type of coding is beautiful :o) sub parseIpNet ($) { my $data = shift; my ($addr, $bits, $mask) = split /\//, $data; if (defined $mask) { warn ("format of $data is invalid!"); return; } if ($addr !~ /^(\d+\.){3}\d+$/) { my ($a, $b, $c, $d) = split /\./, $addr; $b = 0 unless defined $b; $c = 0 unless defined $c; $d = 0 unless defined $d; $addr = "$a.$b.$c.$d"; } sub ipOctetsValid ($) { map { unless ($_ >= 0 and $_ <= 255 and $_ =~ /^\d{1,3}$/) { return 0; }; } split /\./, shift; return 1; } if ($addr !~ /^(\d+\.){3}\d+$/ || not ipOctetsValid ($addr)) { warn ("$addr is not a valid ipv4 address!"); return; } $bits = 32 unless defined $bits; if ($bits =~ /^(\d+\.){3}\d+$/) { unless (ipOctetsValid ($bits)) { warn ("the given mask seems to be invalid: $bits!"); return; } $mask = inaddr ($bits); $bits = 0; map { $_ eq '1' and $bits++; } split (//, unpack ('b*', pack ('N', $mask))); } else { if ($bits < 0 or $bits > 32 or $bits !~ /^\d{1,2}$/) { warn ("format of $data is invalid!"); return; } $mask = 2**32 - 2**(32 - $bits); } my $inaddr = inaddr ($addr); # needed for calculations my $low = addr (($inaddr & $mask) + ($bits == 32 ? 0 : 1)); my $high = addr (($inaddr & $mask) + 2**(32 - $bits) - ($bits == 32 ? 1 : 2)); my $bcast = addr (inaddr ($high) + 1); my $net = addr ($inaddr & $mask); $mask = addr ($mask); $net = $mask = $bcast = $low = $high = '-' if $bits == 32; $addr = '-' if $net eq $addr; my $hostbits = 32 - $bits; $hostbits = $bits = '-' if $bits == 32; print "$data:\n\taddress $addr\n\tnetwork $net\n\tnetmask", " $mask\n\tlowip $low\n\thighip $high\n\tbroadcast", " $bcast\n\tnetbits $bits\n\thostbits $hostbits\n\n"; } parseIpNet ('172.16.0.3/122'); parseIpNet ('10/8'); parseIpNet ('10.255/16'); parseIpNet ('192.168/29'); parseIpNet ('192.168.103.25'); parseIpNet ('192.168.103.25/29'); map{parseIpNet $_}@ARGV;