2012-03-06 2 views
2

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

Редактировать для уточнения; Он работает следующим образом:

Белый список содержит записи в формате, указанном ниже. Используя 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 клиента и $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() здесь ...

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

+0

Что именно должен делать фильтр? Я не понимаю, что ожидаемый результат здесь. Не могли бы вы предоставить демо? Должен ли результат быть таким, чтобы данный IP соответствовал данному патерну? –

+0

Да, это Ip-фильтр, сопоставляющий IP с белым списком, проверяя, является ли '$ ip == $ filter', где' $ filters' - это единственная запись из белого списка в одном из указанных форматов. В принципе, я просматриваю свой белый список и останавливаюсь, как только нахожу запись, которая соответствует моему ip. Я отредактирую свой вопрос, чтобы сделать его более ясным. – dbrumann

ответ

2

Если 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.

 Смежные вопросы

  • Нет связанных вопросов^_^