古いプロジェクトの1つにホワイトリスト用のIPフィルターがあり、新しいアプリケーションで再利用したいと考えています。
明確にするために編集します。それはこのように動作します:
ホワイトリストには、以下に指定された形式のエントリが含まれています。を使用しforeach ($whitelist as $listed)
て、現在のエントリ($listed
)がどのタイプであるかを確認し、このエントリを。と比較し$ip
ます。指定されたIPに一致するエントリが見つかるとすぐに、trueを返します。ホワイトリスト全体を調べた後、一致するものが見つからなかった場合は、falseを返します。
現在のところ、IPv4のみがサポートされており、フィルターは次のようなホワイトリストエントリを許可します。
- BEGIN-END(
192.168.0.1-192.168.0.5
)を指定してIP範囲 - 単一のIPアドレス(例
192.168.0.2
) - *-ワイルドカードを使用した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()
ません...
ワイルドカード範囲についても同じことが言えます。それらを保持する必要があり:
、セグメント区切り文字としてチェックするだけで十分であり、見つからない場合は、.
区切り文字としてフォールバックしますか?