Canonicalize CIDR

From Rosetta Code
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)
Task
Canonicalize CIDR
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 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.

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