memcachedを利用し海外のIPアドレスに対して高速に503エラーを返す
日本に割り当てられているIPを取得
DOS/DDOSアタック対策の一環でPHPによる海外IPのアクセス制限を行う。
日本に割り当てられているIPアドレスは下のサイトで取得可能
http://www.cgis.biz/tools/access/
ページの下の方に
[IPアドレス表示]
というボタンがあり、押すとIPの一覧が表示される。今回は、
ip_address_jp.txt
というファイルを作成しIPアドレス一覧をコピーした。
IPリストをメモリにキャッシュする
アクセスがあるたびにIPアドレスリストのファイルにアクセスしていると負荷が高くなるので、memcachedを利用して以下のようにPHPでコードを書いた。
$ip = $_SERVER['REMOTE_ADDR']; /* テスト用IPリスト $test_ip_list = array( "210.248.0.1", // 日本のip "58.14.0.1", // 中国のip "10.0.0.1", // USのip "25.0.0.1" // UKのip ); $index = mt_rand(0, 3); $ip = $test_ip_list[$index]; */ // パスの設定 $list = "c:\ip_address_jp.txt"; // memcachedの接続処理 $memcache = new Memcache(); $memcache->pconnect('127.0.0.1', 11211) or die('connect failed.'); // キャッシュ有無確認 if ( !$memcache->get('mem_pure') ) { $pure = @file($list); // キャッシュが無い場合はファイルから読む $memcache->set('mem_pure', $pure, 0, 86400); // メモリにキャッシュをセット } else { $pure = $memcache->get('mem_pure'); // キャッシュが有る場合はメモリから読む //$memcache->delete('mem_pure'); // 開発中にキャッシュを削除する際に利用 } // 日本割り当てのipをループ処理 $i = 0; $c = count($pure); while ($i < $c) { $cidr = chop($pure[$i]); list($subnet, $mask) = explode('/', $cidr); // アクセスしているIPアドレスと一致していれば、$jpをセットしてループを抜ける if ((ip2long($ip) & ~((1 << (32 - $mask)) - 1) ) == ip2long($subnet)) { $jp = true; break; } $i++; } // $jpがfalseの場合はHTTP503エラーを返す if(empty($jp)) { header ('HTTP/1.0 503 Service Temporarily Unavailable'); exit(); }
テスト用IPアドレスなども載せてあるので少々長くなっているが、肝心な部分は、
日本に割り当てられているIPリストをループして、アクセスしてきたIPアドレスとマッチング処理をするコード
が本記事において重要な部分になると思う。
その部分を書くにあたり参考にしたのが、php.netに載っていた下のコード
http://www.php.net/manual/en/function.ip2long.php#82397
上のPHPコードをauto_prepend_fileを利用して、メインスクリプト(WordPressなど)実行前に処理を入れることで、DDOSアタックやボットネットを利用した攻撃の影響を抑制するために利用出来る。