2

古いプロジェクトの1つにホワイトリスト用のIPフィルターがあり、新しいアプリケーションで再利用したいと考えています。

明確にするために編集します。それはこのように動作します:

ホワイトリストには、以下に指定された形式のエントリが含まれています。を使用しforeach ($whitelist as $listed)て、現在のエントリ($listed)がどのタイプであるかを確認し、このエントリを。と比較し$ipます。指定されたIPに一致するエントリが見つかるとすぐに、trueを返します。ホワイトリスト全体を調べた後、一致するものが見つからなかった場合は、falseを返します。

現在のところ、IPv4のみがサポートされており、フィルターは次のようなホワイトリストエントリを許可します。

  1. BEGIN-END(192.168.0.1-192.168.0.5)を指定してIP範囲
  2. 単一のIPアドレス(例192.168.0.2
  3. *-ワイルドカードを使用したIP範囲(例192.168.0.*

これらの各ケースをチェックする方法は次のようになります。ここ$ipで、はクライアントのIPであり$listed、上記の形式のいずれかに一致するホワイトリスト/ブラックリストからのエントリです。

public function checkAgainstRange($ip, $listed)
{
    list($begin, $end) = explode('-', $listed);
    $begin = ip2long($begin);
    $end = ip2long($end);
    $ip = ip2long($ip);
    return ($ip >= $begin && $ip <= $end);
}

public function checkAgainstSingle($ip, $listed)
{
    return long2ip(ip2long($ip)) === long2ip(ip2long($listed));
}

public function checkAgainstWildcard($ip, $listed)
{
    $listedSegment = explode('.', $listed);
    $ipSegment = explode('.', $ip);

    for ($i = 0; $i < count($listedSegment); $i++) {
        // We're finished when the wildcarded block is reached
        // Important: Check for wildcard first, as it won't match the client IP!
        if ($listedSegment[$i] == '*') {
            return true;
        }
        if ($listedSegment[$i] != $ipSegment[$i]) {
            return false;
        }
    }
    // Just to be safe: If we reach this, something went wrong
    return false;
}

これらをIPv6アドレスで機能させる方法についていくつかの指示が必要です。

必要な変更のいくつかは明らかです:* ip2long()IPv4アドレスでのみ機能します*で:可能な区切り文字としてチェックする必要がありcheckAgainstWildcard()ます。

私はphp-docsでinet_ntop()見つけました。inet_pton()以下を使用して、2つの単一のIPアドレスを比較できますか?

public function checkAgainstSingle($ip, $listed)
{
    $ip = inet_ntop($ip);
    $listed = inet_ntop($listed);
    if ($ip === false || $listed === false) {
        throw new \Exception;
    }
    return $ip === $false;
}

使用例:

$filter = new IpFilter();
$ip = $_SERVER['REMOTE_ADDR'];

$result = $filter->checkAgainstSingle($ip, '192.168.0.1');
$result = $filter->checkAgainstRange($ip, '192.168.0.1-192.168.0.10');
$result = $filter->checkAgainstWildcard($ip, '192.168.0.*');

次のようなものを保持することも役に立ちcheckAgainstRange()ますか?もしそうなら、どうすれば同様の方法でIPv6範囲をチェックできますか?明らかにここに変更ip2long()することはできinet_ntop()ません...

ワイルドカード範囲についても同じことが言えます。それらを保持する必要があり:、セグメント区切り文字としてチェックするだけで十分であり、見つからない場合は、.区切り文字としてフォールバックしますか?

4

1 に答える 1

2

IPアドレスが人間が読める形式/印刷可能な形式の場合は、inet_pton()を使用してバイナリ形式に変換できます。次に、たとえばbin2hex()を使用して、バイナリデータを16進形式で表示できます。

例:

$address = inet_pton("2a00:8640:1::1");
echo bin2hex($address);

あなたに表示されます:

2a008640000100000000000000000001

次に、個別のアドレスではなくサブネットを確認する場合は、最初の16個の16進文字を比較できます。IPv6サブネットはほとんどの場合/64ネットワークであり、各16進文字は4ビットであるため、最初の(64/4 =)16文字はサブネットを示します。IPv6では、マシンが複数のIPv6アドレスを持つことができ、プライバシー拡張機能(最近のWindowsおよびMac OS Xシステムではデフォルトで有効)を使用している場合、マシンは定期的に送信元アドレスを変更することに注意してください。サブネットでのマッチングは、IPv6で最も役立つ場合があります。

于 2012-03-06T17:22:40.270 に答える