2009-10-24 6 views
46

В настоящее время я работаю над приложением UDP-сокета, и мне нужно построить поддержку, чтобы соединения IPV4 и IPV6 могли отправлять пакеты на сервер.Как поддерживать соединения IPv4 и IPv6

Я надеялся, что кто-то может помочь мне и указать мне в правильном направлении; большая часть документации, которую я нашел, не была полной. Было бы также полезно указать на различия между Winsock и BSD сокетами.

Заранее благодарен!

ответ

72

Лучшим подходом является создание сокета сервера IPv6, который также может принимать соединения IPv4. Для этого создайте обычный сокет IPv6, поверните с в опцию сокета IPV6_V6ONLY, привяжите его к «любому» адресу и начните получать. Адреса IPv4 будут представлены в виде адресов IPv6 в формате IPv4-mapped.

Основное различие между системами заключается в том, доступен ли IPV6_V6ONLY и b) включен или выключен по умолчанию. Он отключается по умолчанию в Linux (т. Е. Разрешает сокеты с двумя стеками без setsockopt) и включается в большинстве других систем.

Кроме того, стек IPv6 в Windows XP не поддерживает эту опцию. В этих случаях вам нужно будет создать два отдельных сокета сервера и поместить их в один или несколько потоков.

+1

Спасибо за информацию, именно то, что я искал. – Charles

+7

Сказать, что IPV6_V6ONLY отключен по умолчанию в Linux, неверен: он зависит от операционной системы, а не только от ядра. Например, в Debian GNU/Linux он по умолчанию включен. – bortzmeyer

+1

OS X также имеет его по умолчанию, но лучше всего всегда устанавливать его явно. Возможно, локальный системный администратор изменил его. –

6

API сокетов управляется RFC-сетями IETF и должен быть одинаковым на всех платформах, включая Windows WRT IPv6.

Для приложений IPv4/IPv6 это ВСЕ около getaddrinfo() и getnameinfo(). getaddrinfo - гений - смотрит на DNS, имена портов и возможности клиента, чтобы решить вечный вопрос: «Могу ли я использовать IPv4, IPv6 или оба для достижения определенного адресата?» Или, если вы идете по маршруту двойного стека и хотите, чтобы он возвращал IPv4-адресам IPv4, и он тоже это сделает.

Это обеспечивает прямую sockaddr * структуру, которая может быть подключена к bind(), recvfrom(), sendto() и семейству адресов для socket() ... Во многих случаях это не означает, что не грязный sockaddr_in(6) структуры, чтобы заполнить и иметь дело.

Для реализации UDP я был бы осторожен в настройке сокетов двойного стека или, в более общем плане, привязке ко всем интерфейсам (INADDR_ANY). Классическая проблема заключается в том, что когда адреса не блокируются (см. bind()) для конкретных интерфейсов, и система имеет несколько запросов на интерфейсы, ответы могут проходить с разных адресов для компьютеров с несколькими адресами на основе прихотей таблицы маршрутизации ОС, запутывающего приложения протоколов, особенно любых систем с требованиями аутентификации.

Для реализации UDP, где это не проблема, или TCP, двойные стековые сокеты могут сэкономить много времени, когда IPv * -изменяет вашу систему. Нужно быть осторожным, чтобы не полагаться полностью на двойной стек, где это не совсем необходимо, поскольку нет недостатка в разумных платформах (Old Linux, BSD, Windows 2003), развернутых со стеками IPv6, не способными к двойным сокетам сокета.

2

В RFC не указано, действительно, существует опция сокета IPV6_V6ONLY, но, если она отсутствует, RFC довольно ясно, что реализация должна быть такой, как если бы этот параметр был FALSE.

Если параметр присутствует, я бы сказал, что он должен иметь значение по умолчанию FALSE, но, по причинам, передающим понимание, BSD и версии Windows по умолчанию имеют значение TRUE. Существует странное утверждение, что это проблема безопасности, потому что незнакомый программист IPv6 может связывать мысли, что они привязываются только к IN6ADDR_ANY только для IPv6 и случайно принимают соединение IPv4, вызывающее проблему безопасности. Я думаю, что это надуманно и абсурдно в дополнение к неожиданности для всех, кто ожидает реализацию RFC-совместимости.

В случае Windows несоблюдение обычно не является неожиданностью. В случае с BSD это, в лучшем случае, несчастливо.

+3

Стандарт API IPv6, RFC 3493, описывает IPV6_V6ONLY в разделе 5.3, если вы хотите прочитать все детали. – bortzmeyer

3

Я играл с этим под Windows, и на самом деле это проблема безопасности там, если вы привязываетесь к loopback-адресу, то сокет IPv6 правильно привязан к [:: 1], но сопоставленный сокет IPv4 привязана к INADDR_ANY, поэтому ваше (предположительно) безопасное локальное приложение действительно доступно миру.