Canonicalize CIDR: Difference between revisions
Content added Content deleted
Line 76: | Line 76: | ||
for @*ARGS -> $cidr { |
for @*ARGS -> $cidr { |
||
# dotted-decimal / bits in network part |
# dotted-decimal / bits in network part |
||
my ($dotted, $size) = $cidr.split('/'); |
my ($dotted, $size) = $cidr.split('/'); |
||
Line 83: | Line 84: | ||
# Replace the host part with all zeroes |
# Replace the host part with all zeroes |
||
$binary.substr-rw($size) = |
$binary.substr-rw($size) = 0 x (32 - $size); |
||
# Convert back to dotted-decimal |
# Convert back to dotted-decimal |
Revision as of 04:55, 9 July 2020
Canonicalize CIDR
You are encouraged to solve this task according to the task description, using any language you may know.
You are encouraged to solve this task according to the task description, using any language you may know.
Implement a function or program that, given a range of IPv4 addresses in CIDR notation (dotted-decimal/network-bits), will return/output the same range in canonical form. That is, the IP address portion of the output CIDR block must not contain any set (1) bits in the host part of the address.
Example: given 87.70.141.1/22, your code should output 87.70.140.0/22.
Perl
<lang perl>#!/usr/bin/env perl use v5.16; use Socket qw(inet_aton inet_ntoa);
- canonicalize a CIDR block: make sure none of the host bits are set
if (!@ARGV) {
chomp(@ARGV = <>);
}
for (@ARGV) {
# dotted-decimal / bits in network part my ($dotted, $size) = split m#/#;
# get IP as binary string my $binary = sprintf "%032b", unpack('N', inet_aton $dotted);
# Replace the host part with all zeroes substr($binary,$size) = 0 x (32 - $size);
# Convert back to dotted-decimal $dotted = inet_ntoa(pack 'B32', $binary);
# And output say "$dotted/$size";
}</lang>
- Output:
$ canonicalize_cidr.pl 87.70.141.1/22 87.70.140.0/22
Python
<lang python>#!/usr/bin/env python
- canonicalize a CIDR block specification:
- make sure none of the host bits are set
import sys from socket import inet_aton, inet_ntoa from struct import pack, unpack
for cidr in sys.argv[1:]:
# IP in dotted-decimal / bits in network part dotted, size_str = cidr.split('/') size = int(size_str)
numeric = unpack('!I', inet_aton(dotted))[0] # IP as an integer binary = f'{numeric:#034b}' # then as a padded binary string prefix = binary[:size + 2] # just the network part # (34 and +2 are to account # for leading '0b')
canon_binary = prefix + '0' * (32 - size) # replace host part with all zeroes canon_numeric = int(canon_binary, 2) # convert back to integer canon_dotted = inet_ntoa(pack('!I', (canon_numeric))) # and then to dotted-decimal print(f'{canon_dotted}/{size}') # output result</lang>
- Output:
$ canonicalize_cidr.py 87.70.141.1/22 87.70.140.0/22
Raku
<lang raku>#!/usr/bin/env raku
- canonicalize a CIDR block: make sure none of the host bits are set
if (!@*ARGS) {
@*ARGS = $*IN.lines;
}
for @*ARGS -> $cidr {
# dotted-decimal / bits in network part my ($dotted, $size) = $cidr.split('/');
# get IP as binary string my $binary = ($dotted.split('.').map: { sprintf "%08b", $_ }).join;
# Replace the host part with all zeroes $binary.substr-rw($size) = 0 x (32 - $size);
# Convert back to dotted-decimal my $canon = ($binary.comb.batch(8).map: { .join.parse-base(2) }).join('.');
# And output say "$canon/$size";
}</lang>
- Output:
$ canonicalize_cidr.raku 87.70.141.1/22 87.70.140.0/22