Canonicalize CIDR

Revision as of 03:51, 9 July 2020 by Markjreed (talk | contribs) (Create task and add initial implementations.)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Implement a function or program that, given a range of IP addresses in CIDR notation (dotted-decimal/network-bits), will return/output the same range in canonical form, that is, with none of the host bits set.

Task
Canonicalize CIDR
You are encouraged to solve this task according to the task description, using any language you may know.

Example: given 87.70.141.1/22, your code should output 87.70.140.0/22.

Perl

<lang perl>

  1. !/usr/bin/env perl

use v5.16; use Socket qw(inet_aton inet_ntoa);

  1. canonicalize a CIDR block: make sure none of the host bits are set

if (!@ARGV) {

  chomp(@ARGV = <>);

}

for (@ARGV) {

 my ($dotted, $size) = split m#/#;
 my $binary = sprintf "%032b", unpack('N', inet_aton($dotted));
 substr($binary,$size) = "0" x (32 - $size);
 $dotted = inet_ntoa(pack('B32', $binary));
 print "$dotted/$size\n";

} </lang>

Output:
$ canonicalize_cidr.pl 87.70.141.1/22
87.70.140.0/22

{header|Python}}

Translation of: Perl

<lang python>

  1. !/usr/bin/env python
  2. canonicalize a CIDR block specification:
  3. 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