Проверка не-частных IP-адресов с помощью PHP

Я пытаюсь проверить, является ли IP-адрес внутренним (то есть частным) IP-адресом, но я получаю любопытный результат:

filter_var('173.194.66.94', FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE); // returns 173.194.66.94
filter_var('192.168.0.1', FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE); // returns false
filter_var('127.0.0.1', FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE); // returns 127.0.0.1?

Разумеется, 127.0.0.1 считается частным IP-адресом? Я нашел этот отчет об ошибках с 2010 года, который сообщает об этом как о проблеме, но отмечен как фиксированный. Это регресс, или я не понимаю, что делает этот фильтр? Я использую PHP 5.4.6.

Ответ 1

Я думаю, это потому, что 127.0.0.1 не является реальным диапазоном private IP, но loopback IP-диапазон, как описано здесь

Обычно, когда приложение TCP/IP хочет отправлять информацию, эта информация перемещается вниз по уровням протокола на IP, где она инкапсулирована в IP-датаграмму. Затем датаграмма переходит к уровню линии передачи данных физической сети устройства для передачи на следующий скачок на пути к IP-адресату.

Тем не менее, один специальный диапазон адресов отложен для функциональности loopback. Это диапазон от 127.0.0.0 до 127.255.255.255. IP-датаграммы, отправленные хостом на адрес loopback 127.x.x.x, не передаются на уровень канала передачи данных для передачи. Вместо этого они "возвращаются" к исходному устройству на уровне IP. По сути, это представляет собой "короткое замыкание" обычного стека протоколов; данные отправляются тремя уровнями реализации IP-уровня устройства, а затем немедленно принимаются им.

Целью цикла loopback является тестирование реализации протокола TCP/IP на хосте. Так как нижние слои закорочены, отправка по петлевому адресу позволяет эффективно тестировать более высокие уровни (IP и выше) без возможности возникновения проблем на нижних уровнях. 127.0.0.1 - это адрес, наиболее часто используемый для целей тестирования.

В руководстве по флагу фильтра есть комментарий к этой конкретной проблеме.

<?php
function FILTER_FLAG_NO_LOOPBACK_RANGE($value) {
    // Fails validation for the following loopback IPv4 range: 127.0.0.0/8
    // This flag does not apply to IPv6 addresses
    return filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? $value :
        (((ip2long($value) & 0xff000000) == 0x7f000000) ? FALSE : $value);
}

$var = filter_var('127.0.0.1', FILTER_CALLBACK, array('options' => 'FILTER_FLAG_NO_LOOPBACK_RANGE'));
// Returns FALSE

$var = filter_var('74.125.19.103', FILTER_CALLBACK, array('options' => 'FILTER_FLAG_NO_LOOPBACK_RANGE'));
// Returns '74.125.19.103'

// To filter Private IP ranges and Loopback ranges
$var = filter_var('127.0.0.1', FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE)  && filter_var('127.0.0.1', FILTER_CALLBACK, array('options' => 'FILTER_FLAG_NO_LOOPBACK_RANGE'));
// Returns FALSE
?>