IPアドレス帯域をまとめる方法

EZwebのIPアドレス帯域追加 - Kimura.Memoにも書きましたが、携帯各キャリアのIPアドレス帯域のリストをまとめて、なるべく少なくしたいと思っていました。

例えば、KDDIが2011年1月に追加したIPアドレス帯域

  • 111.86.147.32/27
  • 111.86.147.64/27
  • 111.86.147.96/27
  • 111.86.147.128/27
  • 111.86.147.160/27
  • 111.86.147.192/27
  • 111.86.147.224/27

上記の7つは、まとめれば、

  • 111.86.147.32/26
  • 111.86.147.96/27
  • 111.86.147.128/25

の3つになります。

しばらく忘れていたのですが、IPv6のことを調べたりしているうちに、NetAddr::IPというPerlモジュールで可能になることがわかりました。

#!/usr/bin/perl
use NetAddr::IP();

our @KDDI = qw(
59.135.38.128/25
61.117.1.0/28
61.117.2.32/29
61.117.2.40/29
111.86.141.64/26
111.86.141.128/26
111.86.141.192/26
111.86.142.0/26
111.86.142.128/27
111.86.142.160/27
111.86.142.192/27
111.86.142.224/27
111.86.143.0/27
111.86.143.32/27
111.86.143.192/27
111.86.143.224/27
111.86.147.0/27
111.86.147.32/27
111.86.147.64/27
111.86.147.96/27
111.86.147.128/27
111.86.147.160/27
111.86.147.192/27
111.86.147.224/27
118.152.214.192/26
118.159.131.0/25
118.159.132.160/27
118.159.133.0/25
118.159.133.192/26
121.111.227.0/25
121.111.227.160/27
121.111.231.0/25
210.230.128.224/28
219.108.157.0/25
219.108.158.0/27
219.108.158.40/29
219.125.145.0/25
219.125.146.0/28
219.125.148.0/25
222.5.62.128/25
222.5.63.0/25
222.5.63.128/25
);

main:
{
    my @addrs = ();

    for ( my $i=0; $i<@KDDI; $i++ ) {
        my ( $ipv4, $mask ) = split ( '/', $KDDI[$i] );
        my $addr = NetAddr::IP->new($ipv4, $mask);
        push ( @addrs, $addr );
    }

    my $me = shift @addrs;

    my @compact = $me->compact(@addrs);

    print join( "\n", @compact );

    exit;
}

【結果】
59.135.38.128/25
61.117.1.0/28
61.117.2.32/28
111.86.141.64/26
111.86.141.128/25
111.86.142.0/26
111.86.142.128/25
111.86.143.0/26
111.86.143.192/26
111.86.147.0/24
118.152.214.192/26
118.159.131.0/25
118.159.132.160/27
118.159.133.0/25
118.159.133.192/26
121.111.227.0/25
121.111.227.160/27
121.111.231.0/25
210.230.128.224/28
219.108.157.0/25
219.108.158.0/27
219.108.158.40/29
219.125.145.0/25
219.125.146.0/28
219.125.148.0/25
222.5.62.128/25
222.5.63.0/24

うむ。使えそう。

ただ、重たそうな処理なので(そもそもNetAddr::IPが重い?)、事前に上記のようなスクリプトを実行し、コンパクト化したリストをIPアドレスチェックに使う--という手順になると思います。

IPv6対応は..後で、後で考えよう。。。