unoh.github.com

IPアドレス帯をチェックする

Tue Mar 17 18:46:34 -0700 2009

こんにちは。新入社員の ryosuke です。

ウノウに入社してから携帯サイトに関わっているのですが、これまで本格的に携帯サイトを構築した事が個人的に無く、ノウハウが足りず周囲に助けて貰ったりしながら楽しくやってます。という訳で携帯のノウハウをご紹介という訳にはいきませんが、その周辺知識に絡んで今回はIPアドレス周りの処理について書かせてもらおうと思います。

携帯専用サイトでは携帯端末以外からのアクセスを制御(アク禁)したい場合があると思います(なんといっても携帯専用ですから)。

USER_AGENT等は簡単に変更できてしまうので、携帯キャリアのゲートウェイ経由で接続しているかどうかをチェックする事になります。ゲートウェイのIPアドレス帯は各キャリアのWEBサイトで公開されているのですが、69.208.0.0/24のようなIPアドレスの範囲を表現できるCIDR表記で公開されており、クライアントのIPアドレスがその範囲に含まれているか検査するにはIPアドレスに関する基礎的な知識が求められます。

CIDR表記はネットワーク部アドレス/ネットワークアドレス長で構成されていて、CIDRで表されるネットワークアドレスと比較IPのネットワークアドレス部分が一致すればIPがCIDRの範囲に属していると判断できます。文章で解説しても分かりにくいので、コードで見てください。

<?php
function inCIDR($ip, $cidr) {
    list($network, $mask_bit_len) = explode('/', $cidr);
    $host = 32 - $mask_bit_len;
    $net = ip2long($network) >> $host << $host; // 11000000101010000000000000000000
    $ip_net = ip2long($ip) >> $host << $host; // 11000000101010000000000000000000
    return $net === $ip_net;
}

$cidr = '192.168.0.8/27'; // 11000000101010000000000000001000
$remote_addr = '192.168.0.20'; // 11000000101010000000000000010100
var_dump(inCIDR($remote_addr, $cidr)); // true
?>


コメントの2進数表記を見比べるとわかりやすいのですが、ネットワークアドレス長の27桁までは $cidr も $remote_addr も同じですね。サンプルコードではシフトして整えてから数値として比較していますが、2進数表記にしてネットワーク部27桁を切り出して文字列比較しても同様に判定できます。

というわけで、携帯キャリアのゲートウェイチェックという例でIPに少し触れてみましたが、実際にこのような仕組みをアプリ側で実装する場合、PHPならPEARモジュールのNet_IPv4などを使うべきだと思います。

そのため判定方法等気にする機会も少ないのですが、面倒に感じる割に原理事態はとってもシンプルなんだという事で取り上げてみました。