Canonicalize_CIDR.md 2.3 KB

Canonicalize CIDR

String manipulation

#!/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(*.fmt("%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(8).map(*.join.parse-base(2)).join('.');
 
  # And output
  say "$canon/$size";
}

Output:

$ canonicalize_cidr.raku 87.70.141.1/22
87.70.140.0/22

Bit mask and shift

# canonicalize a IP4 CIDR block
sub CIDR-IP4-canonicalize ($address) {
  constant @mask = 24, 16, 8, 0;
 
  # dotted-decimal / subnet size
  my ($dotted, $size) = |$address.split('/'), 32;
 
  # get IP as binary address
  my $binary = sum $dotted.comb(/\d+/) Z+< @mask;
 
  # mask off subnet
  $binary +&= (2 ** $size - 1) +< (32 - $size);
 
  # Return dotted-decimal notation
  (@mask.map($binary +> * +& 0xFF).join('.'), $size)
}
 
my @tests = <
  87.70.141.1/22
  36.18.154.103/12
  62.62.197.11/29
  67.137.119.181/4
  161.214.74.21/24
  184.232.176.184/18
  100.68.0.18/18
  10.4.30.77/30
  10.207.219.251/32
  10.207.219.251
  110.200.21/4
  10.11.12.13/8
  10.../8
>;
 
printf "CIDR: %18s  Routing prefix: %s/%s\n", $_, |.&CIDR-IP4-canonicalize
  for @*ARGS || @tests;

Output:

CIDR:     87.70.141.1/22  Routing prefix: 87.70.140.0/22
CIDR:   36.18.154.103/12  Routing prefix: 36.16.0.0/12
CIDR:    62.62.197.11/29  Routing prefix: 62.62.197.8/29
CIDR:   67.137.119.181/4  Routing prefix: 64.0.0.0/4
CIDR:   161.214.74.21/24  Routing prefix: 161.214.74.0/24
CIDR: 184.232.176.184/18  Routing prefix: 184.232.128.0/18
CIDR:     100.68.0.18/18  Routing prefix: 100.68.0.0/18
CIDR:      10.4.30.77/30  Routing prefix: 10.4.30.76/30
CIDR:  10.207.219.251/32  Routing prefix: 10.207.219.251/32
CIDR:     10.207.219.251  Routing prefix: 10.207.219.251/32
CIDR:       110.200.21/4  Routing prefix: 96.0.0.0/4
CIDR:      10.11.12.13/8  Routing prefix: 10.0.0.0/8
CIDR:            10.../8  Routing prefix: 10.0.0.0/8