use strict;
use warnings;
sub parse_ipv4 {
local *_ = \(@_ ? $_[0] : $_);
return unpack('N', pack('C4', split(/\./)));
}
sub format_ipv4 {
local *_ = \(@_ ? $_[0] : $_);
return join('.', unpack('C4', pack('N', $_)));
}
my $member = parse_ipv4('10.20.40.183');
my $mask = parse_ipv4('255.255.0.0');
my $first = $member & $mask;
my $broadcast = $first | ~$mask;
# my $num_machines = $broadcast - $first + 1 - 2;
# which simplifies to:
my $num_machines = ~$mask + 1 - 2;
printf("first = %s\n", format_ipv4($first));
printf("mask = %s\n", format_ipv4($mask));
printf("broadcast = %s\n", format_ipv4($broadcast));
printf("first usable = %s\n", format_ipv4($first+1));
printf("last usable = %s\n", format_ipv4($broadcast-1));
printf("This subnet can handle %d machines:\n", $num_machines);
# 128.x.x.x and higher pack into a negative number on
# 32-bit machines, so the following won't work:
#
# print(format_ipv4, $/)
# for ($first+1 .. $broadcast-1);
if ($mask & 0x7FFFFFFF == 0) {
print(format_ipv4($_), $/)
for (1 .. 0x7FFFFFFF);
print(format_ipv4($_|0x80000000), $/)
for (0 .. 0x7FFFFFFE);
} else {
print(format_ipv4($_+$first), $/)
for ($first+1-$first .. $broadcast-1-$first);
}
__END__
first = 10.20.0.0
mask = 255.255.0.0
broadcast = 10.20.255.255
first usable = 10.20.0.1
last usable = 10.20.255.254
This subnet can handle 65534 machines:
10.20.0.1
10.20.0.2
.
.
.
10.20.255.253
10.20.255.254
Update: Tweaks.
Update 2: Fixed for ($first+1 .. $broadcast-1).
Note: Requires a perl with 32-bit integers.
Note: I didn't write code to check if IP address and the mask are in the valid format.
sub parse_ipv4 {
local *_ = \(@_ ? $_[0] : $_);
/^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$/
&& $1 < 256
&& $2 < 256
&& $3 < 256
&& $4 < 256
or return undef;
return unpack('N', pack('C4', $1, $2, $3, $4));
}
Note: The mask isn't validated. The binary representation of the mask must matched (length == 32 && /^1*0*$/) || $_ == 0.
Note: Keep in mind the above code can print over 4 billion addresses!
Mask Number of addresses printed
/32 255.255.255.255 0
/31 255.255.255.254 0
/30 255.255.255.252 2
/29 255.255.255.248 6
/28 255.255.255.240 14
/27 255.255.255.240 30
/26 255.255.255.240 62
/25 255.255.255.240 126
/24 255.255.255.0 254
...
/16 255.255.0.0 65,534
...
/8 255.0.0.0 16,777,214
...
/3 224.0.0.0 536,870,910
/2 192.0.0.0 1,073,741,822
/1 128.0.0.0 2,147,483,646
/0 0.0.0.0 4,294,967,294
|