У меня есть IP-фильтр для белого списка в одном из моих старых проектов, который я хочу использовать в новом приложении.
редактировать для уточнения; Это работает так:
Белый список содержит записи в формате, указанном ниже. Используя foreach ($whitelist as $listed)
, я проверяю тип текущей записи ($listed
), а затем сравниваю эту запись с $ip
. Как только он находит запись, которая соответствует указанному IP, он вернет true, если после прохождения всего белого списка совпадений не будет найдено, он вернет false.
На данный момент поддерживается только IPv4, а фильтр позволяет вводить записи в белый список, как показано ниже:
- IP-диапазон с указанием BEGIN - END (
192.168.0.1-192.168.0.5
)
- один IP-адрес (например,
192.168.0.2
)
- IP-диапазон с использованием * -wildcard (например,
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()
.
Я нашел inet_ntop()
и inet_pton()
в php-документах. Могу ли я просто использовать следующее для сравнения двух отдельных 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()
здесь ...
То же самое касается групповых диапазонов. Должен ли я сохранить их, и достаточно ли проверить :
как разделитель сегментов, и, если он не найден, вернуться к .
как разделитель?