Рефакторинг IP-фильтра на основе PHP для работы с IPv6 - PullRequest
2 голосов
/ 06 марта 2012

У меня есть IP-фильтр для белого списка в одном из моих старых проектов, который я хочу использовать в новом приложении.

редактировать для уточнения; Это работает так:

Белый список содержит записи в формате, указанном ниже. Используя foreach ($whitelist as $listed), я проверяю тип текущей записи ($listed), а затем сравниваю эту запись с $ip. Как только он находит запись, которая соответствует указанному IP, он вернет true, если после прохождения всего белого списка совпадений не будет найдено, он вернет false.

На данный момент поддерживается только IPv4, а фильтр позволяет вводить записи в белый список, как показано ниже:

  1. IP-диапазон с указанием BEGIN - END (192.168.0.1-192.168.0.5)
  2. один IP-адрес (например, 192.168.0.2)
  3. 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() здесь ...

То же самое касается групповых диапазонов. Должен ли я сохранить их, и достаточно ли проверить : как разделитель сегментов, и, если он не найден, вернуться к . как разделитель?

1 Ответ

2 голосов
/ 06 марта 2012

Если IP-адрес находится в удобочитаемом / печатаемом формате, вы можете использовать inet_pton () для преобразования его в двоичную форму. Затем вы можете, например, использовать bin2hex () для отображения двоичных данных в шестнадцатеричной форме.

Пример:

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

покажет вам:

2a008640000100000000000000000001

Если вы хотите проверить подсеть вместо отдельного адреса, вы можете сравнить первые 16 шестнадцатеричных символов. Подсети IPv6 - это почти всегда / 64 сети, каждый шестнадцатеричный символ составляет 4 бита, поэтому первые (64/4 =) 16 символов показывают подсеть. Помните, что с IPv6 у машины может быть несколько адресов IPv6, и если она использует расширения конфиденциальности (по умолчанию включены в последних системах Windows и Mac OS X), то она будет регулярно менять свой исходный адрес. Совпадение в подсети может быть наиболее полезным для IPv6.

...