LoginSignup
2
3

More than 5 years have passed since last update.

IPアドレスが指定したIPアドレス範囲の中にあるかチェック

Posted at

IPアドレスが指定したIPアドレス範囲の中にあるかチェック

はじめに

いろんなサイトをみるとIPv4とIPv6で書き方が違う。
IPv4は主にip2longでキャストしてチェックしている。
IPv6はintにキャストするとサイズオーバーするのでバイナリに直してチェックしている。

IPv4もバイナリチェックしよう。

IPv4もIPv6も別にバイナリチェックすれば同じロジックでできるよね?

実際のコード

ip.php
<?php
function conevrt_addr_mask(string $ip, int $subnet)
{
    $addr = inet_pton($ip);
    $len = 8 * strlen($addr);
    $mask = str_repeat('f', $subnet >> 2);
    switch ($subnet & 3) {
        case 1:
            $mask .= '8';
            break;
        case 2:
            $mask .= 'c';
            break;
        case 3:
            $mask .= 'e';
            break;
        default:
            break;
    }
    $mask = pack('H*', str_pad($mask, $len >> 2, '0'));
    $filt = $addr & $mask;
    return $filt;
}

function checkip(string $ip, string $addr_range)
{
    $ret_addr = explode("/", $addr_range);
    $chk_mask = conevrt_addr_mask($ret_addr[0], (int)$ret_addr[1]);
    $ip_mask  = conevrt_addr_mask($ip, (int)$ret_addr[1]);
    if ($chk_mask === $ip_mask) {
        return true;
    }
    return false;
}

var_dump(checkip("127.0.0.1", "127.0.0.1/32")); // true
var_dump(checkip("127.0.0.1", "127.0.0.2/32")); // false

var_dump(checkip("1023:4567:89ab:cdef:1023:4567:89ab:cdef", "1023:4567:89ab:cdef:1023:4567:89ab:cdef/128")); // true
var_dump(checkip("1023:4567:89ab:cdef:1023:4567:89ab:cdef", "1023:4567:89ab:cdef:1023:4567:89ab:cde0/128")); // false
?>

やっていることは単純。IPとIPレンジを受け取ったら、バイナリにしてからレンジ分だけ一致するか調べるだけ。

注意点

入力値検証

$ipおよび$addr_rangeは入力検証は行っていないので、この関数を掛ける前にかならず入力検証をしないといけない。
標準のfilter_var関数を利用しましょう。
mixed filter_var ( mixed $variable [, int $filter = FILTER_DEFAULT [, mixed $options ]] )
http://php.net/manual/ja/function.filter-var.php

IPv4とIPv6の互換性

IPv6 - Wikipedia #IPv4との相互運用

実際のパケットフォーマットは完全に異なる上、IPアドレス空間の大きさも違うため、一対一対応はできない。

IPv4でIPv6レンジでチェックしたりIPv6をIPv4レンジでチェックしたりすると、誤検知の可能性は低い(ほとんどfalse)にしても
バグが生まれる原因になるのできちんとどちらのパターンで変数が入ってくるか制御はしたほうがいいと思います。

IPv4とIPv6どちらが入ってくるかわかないという場合はビジネスロジック自体は見直したほうがいいとは思いますが、
必要であれば前述しているfilter_var関数で用意してくれているFILTER_FLAG_IPV4もしくはFILTER_FLAG_IPV6でどちらのプロトコルを利用しているのか調べてからチェック掛けましょう。
http://php.net/manual/ja/filter.filters.validate.php

あとがき

速度はよくわからない。実質サブネットマスクの計算の部分が大きいからこっちのほうが遅いかな。
そういえば枯渇問題はどこいったんだろう。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3