Подтвердить что ты не робот

Преобразование приложений TCP/IP С++ с IPv4 на IPv6. Сложно? Стоит беда?

На протяжении многих лет я разработал небольшую массу серверных/клиентских приложений С++ для Windows с использованием WinSock (маршрутизаторы, серверы Web/Mail/FTP и т.д. и т.д.).

Я начинаю все больше думать о создании IPv6-версии этих приложений (хотя, конечно же, сохраняя исходную версию IPv4).

Вопросы:

  • Какие проблемы могут возникнуть у меня?
  • Не слишком ли затруднено перенос/преобразование?
  • Соответствует ли стоимость преобразования?


Для справки (или для удовольствия) вы можете очистить пик кода IPv4 в основе моих приложений.

4b9b3361

Ответ 1

getaddrinfo и getnameinfo являются вашими друзья.. Насколько это возможно, я предлагаю вам стать лучшими друзьями в вашем стремлении предоставить поддержку IPv4 и IPv6 в существующем приложении.

Если сделать правильно, добавив поддержку IPv6, вы также завершите абстрагирование системы до того момента, когда неизвестный будущий IP-протокол может работать без изменения кода.

Обычно при подключении вы должны заполнить структуру сокетов, порт, семейство адресов, IP-адрес, преобразовать адрес/порты в сетевой порядок байтов и т.д.

С помощью getaddrinfo вы отправляете IP-адрес или имя хоста, а также имя порта или порта, и он возвращает связанный список со структурами и все готово для передачи непосредственно в socket() и connect().

getaddrinfo имеет решающее значение для работы с обоими IP-протоколами, поскольку он знает, имеет ли хост подключение к IPv6 или IPv4, и он знает, может ли сверстник также просматривать записи DNS AAAA vs A и динамически вычислять какой протокол доступен для обслуживания конкретного запроса на соединение.

Я настоятельно рекомендую использовать inet_pton(), inet_addr() или похожие устройства, которые относятся к конкретной версии IP. В частности, на платформе Windows inet_pton() не совместим с более ранними версиями MS Windows (XP, 2003 и др.), Если вы не сворачиваете свои собственные. Также советуйте против отдельных версий для IPv4 и IPv6... Это неработоспособно как техническое решение, потому что в ближайшем будущем оба протокола должны будут использоваться одновременно, и люди могут не знать заранее, что использовать. Интерфейсы сокетов являются абстрактными и легко обнаруживают поддержку dualstack или IPv6, пытаясь создать сокет IPv6 или попытаться установить опцию сокета для двойного стека IPv6 для слушателей. Нет причин, по которым результирующее приложение не будет работать в системе, которая не поддерживает или не знает о IPv6.

Для исходящих соединений используйте PF_UNSPEC в getaddrinfo, чтобы семейство адресов выбрано для вас при выполнении исходящих подключений. Это, ИМХО, лучше, чем подход с двойным стеклом, потому что он позволяет платформам, которые не поддерживают двойную сборку, работать.

Для входящих подключений вы можете либо подключать сокеты IPv4/IPv6 отдельно, если это разумно, учитывая дизайн, либо использовать двойную стек, если вы не можете делать отдельные прослушиватели. При использовании dualstack getnameinfo возвращает IPv6-адрес для адресов IPv4, который ИМХО оказывается совершенно бесполезным. Небольшая утилита может преобразовать строку в обычный IPv4-адрес.

Из моего опыта, когда все сделано правильно, вы удалили зависимости от определенных версий IP и закончили с меньшим кодом управления сокетами, чем вы начали.

Ответ 2

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

Единственное большое отличие - как вы храните IP-адреса:

В IPv4 вы сохраняете их как sockaddr_in (или если вы непослушны, как я, как uint32_t).

Для IPv6 вам необходимо сохранить их как sockaddr_in6 (или некоторую эквивалентную 128-битную структуру).

Хорошим шагом предварительного преобразования было бы пройти через ваш код и найти все места, где в настоящее время хранятся адреса IPv4, и абстрагировать их на общий класс IP-адресов, который впоследствии может быть переопределен внутренне, чтобы быть либо IPv4-адресом, либо IPv6-адресом.
Затем повторите проверку, чтобы убедиться, что в режиме IPv4 ничего не сломано... после того, как вы проверили, вы должны сделать переход на IPv6 всего несколькими изменяется (в основном, от PF_INET до PF_INET6, inet_aton() до inet_pton() и т.д.).

Моя библиотека по умолчанию поставляется как только с поддержкой IPv4, но с возможностью определения макроса препроцессора (-DMUSCLE_USE_IPV6) для перекомпиляции в режиме IPv6.
Таким образом, он все еще может быть скомпилирован в системах, которые не поддерживают IPv6. Одной из очень полезных функций, которые я нашел на этом пути, являются IPv4-отображаемые адреса IPv6: Указав один из них (по существу, адрес IPv4 с добавленным 0xFFFF), вы получаете сокет, который может разговаривать как с IPv4, так и с IPv6, и, следовательно, с сервером, который может одновременно разговаривать как с клиентами IPv4, так и с IPv6, без необходимости писать отдельные пути кода IPv4 и IPv6 для всего.

Что касается того, стоит ли это усилий, это действительно зависит от того, что вы намерены делать с кодом. Я бы сказал, что это хороший образовательный опыт, если ничего другого, и это позволяет использовать ваше программное обеспечение в среде IPv6, которое станет более распространенным с течением времени.

Ответ 4

Посмотрите журналы изменений некоторых проектов с открытым исходным кодом, которые внедрили IPv6. Большинство из них - это код Unix, но Winsock очень похож на сокеты BSD.

Exim, Courier, Squid, Apache, BIND DNS - это некоторые места для поиска.