#! perl -slw
use strict;
use Time::HiRes qw[ time ];
use Data::Dump qw[ pp ];
use enum qw[ CIDR NETWORK SIZE RANGE ];
use enum qw[ FIRST LAST ];
sub dd2n { unpack 'N', pack 'C4', split '\.', $_[0] }
sub n2dd { join '.', unpack 'C4', pack 'N', $_[0] }
sub CIDR2Range {
my( $network, $bits ) = $_[ 0 ] =~ m[([^/]+)/(\d+)]
or die "Bad CIDR: '$_[0]'";
my $start = dd2n( $network );
my $hostMask = ( 1 << ( 32 - $bits ) ) -1;
die "Bad CIDR: '$_[0]'" if $start & $hostMask;
my $end = $start | $hostMask;
return [ $start, $end ];
}
sub rangesOverlap {
my( $thisFirst, $thisLast ) = @{ $_[0] };
my( $thatFirst, $thatLast ) = @{ $_[1] };
return 1 unless
$thisFirst > $thatLast or $thatFirst > $thisLast;
}
sub isContainedBy {
my( $thisFirst, $thisLast ) = @{ $_[0] };
my( $thatFirst, $thatLast ) = @{ $_[1] };
return 1
if $thisFirst <= $thatFirst
and $thisLast >= $thatLast;
}
my $start = time;
chomp( my @CIDRs = <> );
my $count = @CIDRs;
@CIDRs = sort {
$b->[SIZE] <=> $a->[SIZE] || $b->[RANGE][FIRST] <=> $a->[RANGE][FIRST]
} map[
$_, m[([^/]+)/(\d+)$], CIDR2Range( $_ )
], @CIDRs;
#pp \@CIDRs;
my @forest;
OUTER: while( @CIDRs ) {
my $next = pop @CIDRs;
my $that = $next->[RANGE];
for my $tree ( @forest ) {
my $this = $tree->{root}[RANGE];
if( isContainedBy( $this, $that ) ) {
push @{ $tree->{contains} }, $next;
next OUTER;
}
}
push @forest, { root => $next };
}
@forest = sort{
$a->{root}[RANGE][FIRST] <=> $b->{root}[RANGE][FIRST]
} @forest;
for my $tree ( @forest ) {
print $tree->{root}[CIDR];
print "\t", join ' ', map $_->[CIDR], @{ $tree->{contains} };
}
printf STDERR "Took %.3f seconds for $count CIDRs\n",
time() - $start;
####
0.0.0.0/12
0.10.0.0/15 0.1.0.0/16 0.7.0.0/16 0.12.0.0/16 0.11.0.0/17 0.4.128.0/19 0.11.160.0/19 0.12.72.0/21 0.2.132.0/22 0.3.184.0/22 0.15.254.0/24 0.14.150.128/26
0.16.128.0/17
0.17.0.0/16
0.18.163.128/26
0.19.237.0/24
0.24.16.0/20
0.24.104.0/21
0.25.0.0/19
0.25.144.0/22
0.27.0.0/16
0.28.190.0/23
0.28.203.128/25
0.29.0.0/16
0.29.64.0/20
0.30.240.0/20
0.31.157.160/27
0.34.0.0/16
0.35.0.0/18
0.37.252.0/22
0.38.64.0/22
0.40.0.0/13
0.40.0.0/15 0.40.0.0/16 0.47.0.0/16 0.42.0.0/18 0.44.128.0/18 0.47.192.0/18 0.43.0.0/19 0.47.64.0/21 0.47.192.0/21
0.48.0.0/13
0.54.0.0/15 0.55.128.0/18 0.48.160.0/19 0.52.224.0/19 0.53.96.0/19 0.55.32.0/20 0.49.124.0/22 0.51.241.128/26
0.56.168.0/23
0.58.0.0/21
...
####
#! perl -slw
use strict;
use Math::Random::MT qw[ rand srand ];
sub n2dd { join '.', unpack 'C4', pack 'N', $_[0] }
our $N //= 50e3;
our $S //= 1;
srand( $S );
my %uniq;
for( 1 .. $N ) {
my $bits = 8 + int( rand( 8 ) + rand( 8 ) + rand( 8 ) );
my $ip = int( rand( 2 **32 ) );
$ip &= ~( ( 1 << ( 32 - $bits ) ) -1 );
$ip = n2dd( $ip );
my $cidr = "$ip/$bits";
redo if exists $uniq{ $cidr };
$uniq{ $cidr } = undef;
print $cidr;
}