#!/usr/local/bin/perl -w use strict; use Getopt::Std; use vars qw($opt_c); use vars qw($opt_v); use vars qw($opt_V); my @block = ("KR", "CN", "TW"); sub inet_addr($) { my($ipstr) = @_; my(@v, $i, $s_addr); @v = split(/\./, $ipstr . ".0.0.0.0"); $s_addr = 0; for ($i = 0; $i < 4; $i++) { $s_addr = ($s_addr * 256) + $v[$i]; } return $s_addr; } sub s_addr_to_v($) { my($s_addr) = @_; my(@v); $v[0] = ($s_addr >> 24) & 0xff; $v[1] = ($s_addr >> 16) & 0xff; $v[2] = ($s_addr >> 8) & 0xff; $v[3] = $s_addr & 0xff; return @v; } sub s_addr_to_dec($) { my($s_addr) = @_; my(@v) = s_addr_to_v($s_addr); return sprintf("%d.%d.%d.%d", $v[0], $v[1], $v[2], $v[3]); } sub count_mask($$) { my($bip, $x) = @_; my($i) = 0; my($bw) = 32; while ($i < $bw && ($bip & 1) == $x) { $bip = $bip >> 1; $i++; } return $bw - $i; } my @bitmask; sub bitmask_setup() { my $i; my $bm = 0; for ($i = 0; $i < 32; $i++) { $bitmask[$i] = $bm; $bm = ($bm >> 1) | 0x80000000; } $bitmask[32] = 0xffffffff; } sub netaddr($$) { my($bip, $mlen) = @_; return $bip & $bitmask[$mlen]; } sub broaddr($$) { my($bip, $mlen) = @_; my $bro = ($bip & $bitmask[$mlen]) | (~$bitmask[$mlen] & 0xffffffff); my $x = ($bip & $bitmask[$mlen]); my $y = (~$bitmask[$mlen]) & 0xffffffff; $opt_v && printf(STDERR "broaddr(%x,%s)=%x\n", $bip, $mlen, $bro); return $bro; } sub find_split_point($$$) { my($blo, $bhi, $l0) = @_; my $lx = $l0; while (broaddr($blo, $lx) > $bhi) { $lx++; } $opt_v && printf(STDERR "find_split_point(%x,%x,%d)=%d\n", $blo, $bhi, $l0, $lx); return $lx; } sub tobin($$) { my($x, $col) = @_; my($s, $i); $s = ""; for ($i = 0; $i < $col; $i++) { $s = (($x & 1) ? "1" : "0") . $s; $x >>= 1; } return $s; } sub tobin8($) { my($x) = @_; my $i; my $s = ""; for ($i = 0; $i < 4; $i++) { $s = ":" . tobin($x & 0xff, 8) . $s; $x >>= 8; } $s =~ s/.//; return $s; } sub range_to_cidr($$$$); sub range_to_cidr($$$$) { my($blo, $bhi, $lvl, $co) = @_; my($l0, $l1, $mlen); my($bnet, $bbro); $opt_v && printf(STDERR "%d>>%s-%s\n", $lvl, s_addr_to_dec($blo), s_addr_to_dec($bhi)); $l0 = count_mask($blo, 0); $l1 = count_mask($bhi, 1); $opt_v && printf(STDERR "%s/%d\n", tobin8($blo), $l0); $opt_v && printf(STDERR "%s/%d\n", tobin8($bhi), $l1); $mlen = ($l0 > $l1 ? $l0 : $l1); $bnet = netaddr($blo, $mlen); $bbro = broaddr($blo, $mlen); $opt_v && printf(STDERR "net:%s/%d\n", s_addr_to_dec($bnet), $mlen); $opt_v && printf(STDERR "bro:%s/%d\n", s_addr_to_dec($bbro), $mlen); if ($blo != $bnet || $bhi != $bbro) { my $split_mlen = find_split_point($blo, $bhi, $l0); my $split_bbro = broaddr($blo, $split_mlen); #printf("split1:%s/%d\n", s_addr_to_dec($split_bbro), $split_mlen); #printf("split2:%s-%s\n", s_addr_to_dec($split_bbro+1), s_addr_to_dec($bhi)); range_to_cidr($blo, $split_bbro, $lvl + 1, $co); range_to_cidr($split_bbro + 1, $bhi, $lvl + 1, $co); } else { my $anet = s_addr_to_dec($bnet); my $abro = s_addr_to_dec($bbro); printf("%s/%d - %s %s\n", $anet, $mlen, $abro, $co); } } sub net_to_cidr($$) { my($blo, $bhi) = @_; my($i) = 0; my($bm) = 0x80000000; while ($bm != 0 && ($blo & $bm) == ($bhi & $bm)) { $bm = 0x80000000 | ($bm >>= 1); $i++; } $bm = ($bm << 1) & 0xffffffff; my $net = $blo & $bm; my $bro = ($blo & $bm) | ~$bm; if ($net != $blo || $bro != $bhi) { # not CIDR $i = -$i; } return $i; } my %bad; sub setup() { my $k; foreach $k (@block) { $bad{$k} = $k; } } my %bad_net; my %bad_co; sub nain() { my $lbuf; while ($lbuf = <>) { chomp($lbuf); if ($lbuf =~ /^apnic\|(..)\|ipv4\|([0-9.]*)\|(\d+)/) { my ($co, $net, $count) = ($1, $2, $3); if (defined($bad{$co})) { #printf("%s\n", $lbuf); my $s_addr = inet_addr($net); $bad_net{$s_addr} = $count; $bad_co{$s_addr} = $co; } } } return 0; } my @net_sorted; sub merge() { my $net; @net_sorted = sort keys %bad_net; my ($i, $n); $n = $#net_sorted + 1; for ($i = 0; $i < $n - 1; $i++) { my $net = $net_sorted[$i]; my $co = $bad_co{$net}; my $count = $bad_net{$net}; while ($i < $n - 1 && $net + $count == $net_sorted[$i + 1] # && $bad_co{$net_sorted[$i + 1]} eq $co) { ) { if ($bad_co{$net_sorted[$i + 1]} ne $co) { $co = $bad_co{$net_sorted[$i + 1]}; $bad_co{$net} .= "," . $co; } $count += $bad_net{$net_sorted[$i + 1]}; splice(@net_sorted, $i + 1, 1); $n--; } $bad_net{$net} = $count; #printf("%s %d\n", s_addr_to_dec($net), $count); } } sub output() { my ($i, $n); $n = $#net_sorted + 1; for ($i = 0; $i < $n; $i++) { my $net = $net_sorted[$i]; my $count = $bad_net{$net}; #printf(">>%s %d\n", s_addr_to_dec($net), $count); range_to_cidr($net, $net + $count - 1, 0, $bad_co{$net}); } } sub main() { my $ex = 1; getopts('c:vV'); if ($::opt_V) { printf(STDERR "usage: $0 [-c 'CN,CN,..'] delegated-apnic-latest\n"); } else { if ($::opt_c) { @block = split(/,/, $::opt_c); } bitmask_setup(); setup(); nain(); merge(); output(); } return $ex; } exit main();