Литмир - Электронная Библиотека
Содержание  
A
A

Хотя четверть из представленных в таблице сочетаний недопустима, в обозримом будущем большинство реализаций IPv6 будут использоваться на узлах с двойным стеком протоколов и поддерживать не только IPv6. Если мы удалим из таблицы вторую строку и вторую колонку, все записи «Нет» исчезнут и единственной проблемой останется запись, помеченная звездочкой.

12.4. Макроопределения проверки адреса IPv6

Существует небольшой класс приложений IPv6, которые должны знать, с каким собеседником они взаимодействуют (IPv4 или IPv6). Эти приложения должны знать, является ли адрес собеседника адресом IPv4, преобразованным к виду IPv6. Определены двенадцать макросов, проверяющих некоторые свойства адреса Ipv6.

#include <netinet/in.h>

int IN6_IS_ADDR_UNSPECIFIED(const struct in6_addr *<i>aptr</i>);

int IN6_IS_ADDR_LOOPBACK(const struct in6_addr *<i>aptr</i>);

int IN6_IS_ADDR_MULTICAST(const struct in6_addr *<i>aptr</i>);

int IN6_IS_ADDR_LINKLOCAL(const struct in6_addr *<i>aptr</i>);

int IN6_IS_ADDR_SITELOCAL(const struct in6_addr *<i>aptr</i>);

int IN6_IS_ADDR_V4MAPPED(const struct in6_addr *<i>aptr</i>);

int IN6_IS_ADDR_V4COMPAT(const struct in6_addr *<i>aptr</i>);

int IN6_IS_ADDR_MC_NODELOCAL(const struct in6_addr *<i>aptr</i>);

int IN6_IS_ADDR_MC_LINKLOCAL(const struct in6_addr *<i>aptr</i>);

int IN6_IS_ADDR_MC_SITELOCAL(const struct in6_addr *<i>aptr</i>);

int IN6_IS_ADDR_MC_ORGLOCAL(const struct in6_addr *<i>aptr</i>);

int IN6_IS_ADDR_MC_GLOBAL(const struct in6_addr *<i>aptr</i>);

<i>Все возвращают: ненулевое значение, если адрес IPv6 имеет указанный тип, 0 в противном случае</i>

Первые семь макросов проверяют базовый тип адреса IPv6. Мы покажем различные типы адресов в разделе А.5. Последние пять макросов проверяют область действия адреса многоадресной передачи IPv6 (см. раздел 19.2).

Клиент IPv6 может вызвать макрос

IN6_IS_ADDR_V4MAPPED
для проверки адреса IPv6, возвращенного распознавателем. Сервер IPv6 может вызвать этот макрос для проверки адреса IPv6, возвращенного функцией accept или
recvfrom
.

Как пример приложения, которому нужен этот макрос, можно привести FTP и его команду

PORT
. Если мы запустим FTP-клиент, зарегистрируемся на FTP-сервере и выполним команду FTP
dir
, FTP-клиент пошлет команду
PORT
FTP-серверу через управляющее соединение. Она сообщит серверу IP-адрес и порт клиента, с которым затем сервер создаст соединение. (В главе 27 [111] содержатся подробные сведения о протоколе приложения FTP.) Но FTP-клиент IPv6 должен знать, с каким сервером имеет дело — IPv4 или IPv6, поскольку сервер IPv4 требует команду в формате
PORT a1, a2, a3, a4, p1, p2
(где первые четыре числа, каждое от 0 до 255, формируют 4-байтовый адрес IPv4, а два последних — 2-байтовый номер порта), а серверу IPv6 необходима команда
EPRT
(RFC 2428 [3]), содержащая семейство адреса, адрес в текстовом формате и порт в текстовом формате. В упражнении 12.1 приводятся примеры использования обеих команд.

12.5. Переносимость исходного кода

Большинство существующих сетевых приложений написаны для IPv4. Структуры

sockaddr_in
размещаются в памяти и заполняются, а функция
socket
задает
AF_INET
в качестве первого аргумента. При переходе от листинга 1.1 к листингу 1.2 мы видели, что эти приложения IPv4 можно преобразовать в приложения IPv6 без особых усилий. Многие показанные нами изменения можно выполнить автоматически, используя некоторые сценарии редактирования. Программы, более зависящие от IPv4, использующие такие свойства, как многоадресная передача, параметры IP или символьные (неструктурированные) сокеты, потребуют больших усилий при преобразовании.

Если мы преобразуем приложение для работы с IPv6 и распространим его исходный код, нам придется думать о том, поддерживает ли принимающая система протокол IPv6. Типичный способ решения этой проблемы — применять в коде

#ifdef
, используя по возможности IPv6 (поскольку мы видели в этой главе, что клиент IPv6 может взаимодействовать с серверами IPv4 и наоборот). Проблема такого подхода в том, что код очень быстро засоряется директивами
#ifdef
, и его становится сложнее отслеживать и обслуживать.

Наилучшим подходом будет рассмотрение перехода на IPv6 как возможности сделать программу не зависящей от протокола. Первым шагом здесь будет удаление вызовов функций

gethostbyname
и
gethostbyaddr
и использование функций
getaddrinfo
и
getnameinfo
, описанных в предыдущей главе. Это позволит нам обращаться со структурами адресов сокетов как с непрозрачными объектами, ссылаться на которые можно с помощью указателя и размера, что как раз и выполняют основные функции сокетов:
bind
,
connect
,
recvfrom
и т.д. Наши функции
sock_XXX
из раздела 3.8 помогут работать с ними независимо от IPv4 и IPv6. Очевидно, эти функции содержат
#ifdef
для работы с IPv4 и IPv6, но если мы скроем эту зависимость от протокола в нескольких библиотечных функциях, наш код станет проще. В разделе 21.7 мы разработаем ряд функций
mcast_XXX
, которые помогут сделать приложения многоадресной передачи не зависящими от версии протокола IP.

Другой момент, который нужно учесть, — что произойдет, если мы откомпилируем наш исходный код в системе, поддерживающей и IPv4, и IPv6, затем распространим либо исполняемый код, либо объектные файлы (но не исходный код) и кто-то запустит наше приложение в системе, не поддерживающей IPv6. Есть вероятность, что сервер локальных имен поддерживает записи типа AAAA и возвращает как записи типа AAAA, так и записи типа А некоему собеседнику, с которым пытается соединиться наше приложение. Если наше приложение, работающее с IPv6, вызовет функцию

socket
для создания сокета IPv6, она не будет работать, если узел не поддерживает IPv6. Мы решаем этот вопрос с помощью функций, описанных в следующей главе, игнорируя ошибку функции
socket
и пытаясь использовать следующий адрес в списке, возвращаемом сервером имен. Если предположить, что у собеседника имеется запись типа А и что сервер имен возвращает запись типа А в дополнение к любой записи типа AAAA, то сокет IPv4 успешно создастся. Этот тип функциональности имеется в библиотечной функции, но не в исходном коде каждого приложения.

145
{"b":"225366","o":1}