携帯ゲートウェイのIPアドレス帯更新を効率的に確認する方法
携帯電話各キャリアは、そのゲートウェイのIPアドレス帯域を公開しています。
携帯ブラウザからのアクセスの場合、このIPアドレスがソースアドレスとなるので、アクセス制御や判別のために使っている方は多いのではないかと思います。
今回は、このIPアドレス帯の更新を効率的に確認する方法についてのお話です。
更新されたかどうかの確認だけならアンテナ系のWebサービスを使えばよいのですが、それだけだと、
- どのIPアドレス帯が追加・削除されたのかわかりづらい。
- IPアドレス帯のコピペが面倒くさい。
といった不満点があります。
そこでNet::CIDR::MobileJPというPerlのモジュールの出番です。(作者はモバイルファクトリという会社の方のようです)
このモジュールには与えたIPアドレスが携帯かどうかを判別する機能があるのですが、次のようにすれば、特定のキャリア(例の場合はSoftBank(旧Vodafone))のIPアドレス帯を取得することもできます。
use Net::CIDR::MobileJP::Scraper::Plugin::Vodafone; print Dumper( Net::CIDR::MobileJP::Scraper::Plugin::Vodafone->new->run ); 出力結果: VAR1 = [ '123.108.236.0/24', '123.108.237.0/27', '202.179.204.0/24', (以下略)
この機能を使ってIPアドレス帯を得た後、前回の結果と違っている場合は、追加された部分や削除された部分をレポートする、というようなスクリプトを書いてcronで定期的に実行しています。
ちなみに、追加・削除の差分をとるのにはArray::Diffというモジュールを使っています。(作者はKAYACという面白法人の方のようです)
実行結果はこのようになります。(先日のSoftBankの更新の際のものです)
---
Vodafone:
- url: http://developers.softbankmobile.co.jp/dp/tech_svc/web/ip.php
- added:
- 123.108.236.0/24
- 123.108.237.0/27
- 202.253.96.224/27
- 210.169.130.112/28
- deleted:
- 202.253.96.248/29
- 210.169.130.112/29
- 210.169.130.120/29
- 210.169.176.0/24
- new:
- 123.108.236.0/24
- 123.108.237.0/27
- 202.179.204.0/24
- 202.253.96.224/27
- 210.146.7.192/26
- 210.146.60.192/26
- 210.151.9.128/26
- 210.169.130.112/28
- 210.175.1.128/25
- 210.228.189.0/24
- 211.8.159.128/25
- old:
- 202.179.204.0/24
- 202.253.96.248/29
- 210.146.7.192/26
- 210.146.60.192/26
- 210.151.9.128/26
- 210.169.130.112/29
- 210.169.130.120/29
- 210.169.176.0/24
- 210.175.1.128/25
- 210.228.189.0/24
- 211.8.159.128/25
スクリプトは末尾に掲載しますので、煮るなり焼くなり好きにしてくださいませー
差分情報はYAMLの形式でメールで送るように(コメントアウトしてあります)なっていますが、メールで送るのではなくYAMLでファイルに出力してほかの機構で再利用したり、YAMLではなく他の形式(JSONとか)で書き出して再利用したり、といったことはスクリプトをちょっといじればできると思います。
#!/usr/bin/env perl
use strict;
use warnings;
use Carp;
use Readonly;
use UNIVERSAL::require;
use Net::CIDR::MobileJP;
use Array::Diff;
use Pod::Usage;
use YAML;
use Mail::Send;
use Getopt::Long;
use Data::Dumper;
$Data::Dumper::Indent = 1;
$Data::Dumper::Deepcopy = 1;
$Data::Dumper::Sortkeys = 1;
BEGIN {
my $debug_flag = $ENV{SMART_COMMENTS} || $ENV{SMART_COMMENT} || $ENV{SMART_DEBUG} || $ENV{SC};
if ($debug_flag) {
my @p = map { '#'x$_ } ($debug_flag =~ /([345])?s*/g);
Smart::Comments->use(@p);
}
}
# name of Net::CIDR::MobileJP::Scraper::Plugin::*
Readonly my @CARRIER => qw(DoCoMo EZweb Vodafone AirHPhone);
Readonly my $STORE_DIR => '/var/state/ktai-cidr';
MAIN: {
my %opt;
Getopt::Long::Configure("bundling");
GetOptions(?%opt,
'help|h|?') or pod2usage(2);
pod2usage(2) if exists $opt{'help'};
for my $carrier (@CARRIER) {
### start: $carrier
my $module = 'Net::CIDR::MobileJP::Scraper::Plugin::' . $carrier;
unless ($module->use) {
carp "[SKIP] $module: $@";
next;
}
my $scraper = $module->new;
my $retry = 3;
my $result;
while ($retry-- > 0) {
$result = $scraper->run;
### $result
last if @{ $result };
### retry: $retry
}
if (! @{ $result } > 0) {
carp "[SKIP] cannot retrieve CIDR for $carrier";
next;
}
my $cidr_new = $result;
my $cidr_old;
if (-r "${STORE_DIR}/${carrier}.yaml") {
$cidr_old = YAML::LoadFile("${STORE_DIR}/${carrier}.yaml");
} else {
$cidr_old = ['NO DATA'];
}
### old: $cidr_old
### new: $cidr_new
my $diff = Array::Diff->diff( $cidr_old, $cidr_new );
if ($diff->count > 0) {
process_diff(carrier => $carrier,
url => $scraper->url,
old => $cidr_old,
new => $cidr_new,
diff => $diff,
);
YAML::DumpFile("${STORE_DIR}/${carrier}.yaml", $cidr_new);
}
}
exit 0;
}
sub process_diff {
my %param = @_;
my $carrier = $param{carrier};
my $url = $param{url};
my $old = $param{old};
my $new = $param{new};
my $diff = $param{diff};
my $change;
push @{ $change->{$carrier} }, { url => $url };
if (@{ $diff->added }) {
push @{ $change->{$carrier} }, { added => $diff->added };
}
if (@{ $diff->deleted }) {
push @{ $change->{$carrier} }, { deleted => $diff->deleted };
}
push @{ $change->{$carrier} }, { new => $new};
push @{ $change->{$carrier} }, { old => $old};
my $change_text = YAML::Dump( $change );
### change: $change_text
# send_diff($carrier, $change_text);
}
sub send_diff {
my ($carrier, $body) = @_;
### send_diff
my $mail = Mail::Send->new;
$mail->subject("[NOTIFY] $carrier GW IP address was updated");
$mail->set('Mime-Version', '1.0');
$mail->set('Content-Type', 'text/plain; charset=iso-2022-jp');
$mail->set('Content-Transfer-Encoding', '7bit');
$mail->set('X-Mailer', $0);
$ENV{QMAILSUSER} = 'ktai-cidr-scraper';
$ENV{QMAILSHOST} = 'example.org';
$mail->set('From', join('@', @ENV{qw(QMAILSUSER QMAILSHOST)}));
$mail->to('notifyme@example.org');
my $fh = $mail->open;
print {$fh} $body;
$fh->close;
}
__END__
