Как обрабатывать IPv6-адреса вместе с IPv4 PHP - PullRequest
3 голосов
/ 03 сентября 2011

Я разработчик для iphone - новичок в веб-разработке, поэтому наберитесь терпения!
В настоящее время я использую MAMP для локального тестирования.

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

Если пользователь входит в систему, и его IP-адрес не совпадает ни с одним из IP-адресов, связанных с его идентификатором пользователя в моей «разрешенной» таблице, он выполняет вышеуказанную задачу и получает электронное письмо.

Код, который я использую для генерации URL ссылки, по которой они щелкают, выглядит примерно так:

if (preg_match('/^127./',$ip)) {
    // accessed from this machine
    $val_url = "http://localhost:8888/mywebsite/admin/aproove_ip.php?email=$admin_email&val=$hash";
}
else if (preg_match('/^192\.168./',$ip)) {
    // accessed form a local networked computer
    $val_url = "http://super.local:8888/mywebsite/admin/aproove_ip.php?email=$admin_email&val=$hash";
    // note super.local is my machine's address, 8888 is MAMP port
}
else {
    // accessed from the WWW
    $val_url = "http://www.mywebsite.com/admin/aproove_ip.php?email=$admin_email&val=$hash";
}

Теперь, это работало отлично при тестировании на моем компьютере.

Тем не менее, я решил (не спрашиваю, почему) протестировать мой iPod Touch, и в электронном письме, которое он мне отправил (для проверки IP), он дал мне полный онлайн-адрес, как если бы к нему обращались из WWW. (т.е. ни одно из регулярных выражений не было выполнено). Я посмотрел в таблицу хранения, которая содержит запросы, и запрошенный IP был: fe80::da30:62ff:fe18:6681.

Я предполагаю, что это ipv6? - Мне нужно знать следующее:

  • Стоит ли ожидать, что адрес ipv6 появится на моем сайте, когда он будет запущен?
  • Как я могу определить, был ли это локальный запрос (например, мое регулярное выражение для 192.168 ... и 127 ...)

Я был бы очень признателен за любые советы по этому вопросу, поскольку я нахожу это действительно запутанным

Ответы [ 2 ]

7 голосов
/ 03 сентября 2011

Если вы хотите, чтобы не было соединений IPv6, можете добавить Listen 0.0.0.0:80 в вашу конфигурацию apache.Но большинство веб-хостов все еще не поддерживают IPv6 (да, я знаю, мы находимся в 2011 году), поэтому очень маловероятно, что люди могут даже подключиться к вам через IPv6.Единственная причина, по которой вы это видите, заключается в том, что bonjour (что делает .local адрес работающим) работает по IPv6.

Если вы хотите получить готовый код IPv6, почти не нужно вносить никаких изменений, так как большинство функций PHP PHPработать как на IPv4, так и на IPv6.Единственное изменение, которое я помню, было увеличение типа данных varchar в таблице MySQL до максимальной длины адреса IPv6 (39).

Я не уверен, что IPv6 воспроизводится по тем же правилам подсеть , что делает IPv4, но я ожидаю, что было бы немного сложнее проверить локальный адрес IPv6.

РЕДАКТИРОВАТЬ:

fe80::/10 представляется адресами локальной ссылки, это может быть так же просто, как проверка первых 4 цифр.

2 голосов
/ 03 сентября 2011

Чтобы узнать, является ли IPv6-адрес локальным, вы должны знать, какие адреса используются локально. IPv6 не делает NAT (обычно). Некоторые сети используют ULA (уникальные локальные адреса) для внутреннего использования, но многие просто используют адреса, которые они получают от интернет-провайдера.

Одна вещь, которую вы должны принять во внимание, это то, что некоторые (большинство? В наши дни) используют расширения конфиденциальности. Это означает, что их IPv6-адреса будут меняться со временем. Это приведет к значительному росту вашей таблицы, и это заставит пользователя повторно проходить аутентификацию снова и снова. Я думаю, что ваш лучший вариант - хранить только подсеть (первые 64 бита) и сопоставлять ее.

На всякий случай, если вы не знаете синтаксис IPv6-адресов: адреса используют шестнадцатеричные цифры и имеют форму ssss: ssss: ssss: ssss: nnnn: nnnn: nnnn: nnnn где s - подсеть, а n - узел / хост. Ведущие нули в каждом блоке из 4 цифр опущены, а несколько блоков 0 заменены на :: один раз. Так что fe80::da30:62ff:fe18:6681 на самом деле fe80:0000:0000:0000:da30:62ff:fe18:6681. Мой собственный веб-сервер имеет адрес 2001:4038:0:16::16, что сокращенно от 2001:4038:0000:0016:0000:0000:0000:0016, а подсеть - 2001:4038:0:16::/64.

Пример кода для получения подсети с адреса:

<?php

# Get the original IP address, for example from the command line
$original_ip_str = $argv[1];

# Converto to binary form (suppress errors, we handle them)
$original_ip_bin = @inet_pton($original_ip_str);
if ($original_ip_bin === FALSE) {
  $subnet_str = FALSE;
  $subnet_bin = FALSE;
} else {
  if (strlen($original_ip_bin) == 16) {
    # IPv6: Replace the last 64 bits with zeroes
    $subnet_bin = substr_replace($original_ip_bin, str_repeat("\000", 8), -8);
  }

  # Convert the result back to readable form (optional)
  $subnet_str = inet_ntop($subnet_bin);
}

# Show the result
echo "IPv6 address: $original_ip_str\n";
echo "IPv6 subnet: $subnet_str\n";
...