3. Клиент IPv6 вызывает функцию connect с адресом IPv4, преобразованным к виду IPv6, в структуре адреса сокета IPv6. Ядро обнаруживает преобразованный адрес и автоматически посылает серверу сегмент SYN IPv4.
4. Сервер отвечает сегментом SYN/ACK IPv4, и устанавливается соединение, по которому происходит обмен дейтаграммами IPv4. Этот сценарий мы схематически изображаем на рис. 12.3.
Рис. 12.3. Обработка клиентских запросов в зависимости от типа адреса и типа сокета
Если TCP-клиент IPv4 вызывает функцию
connect
,
задавая адрес IPv4, или если UDP-клиент IPv4 вызывает функцию
sendto
, задавая адрес IPv4, ничего особенного не происходит. На рисунке это изображено двумя стрелками, помеченными «IPv4».
Если TCP-клиент IPv6 вызывает функцию
connect
, задавая адрес IPv6, или если UDP-клиент IPv6 вызывает функцию
sendto
, задавая адрес IPv6, тоже ничего особенного не происходит. На рисунке это показано двумя стрелками, помеченными «IPv6».
Если TCP-клиент IPv6 вызывает функцию
connect
, задавая адрес IPv4, преобразованный к виду IPv6, или если UDP-клиент вызывает функцию
sendto
, задавая адрес IPv4, преобразованный к виду IPv6, ядро обнаруживает сопоставленный адрес и инициирует отправку дейтаграммы IPv4 вместо дейтаграммы IPv6. На рисунке это показано двумя штриховыми стрелками.
Клиент IPv4 не может задать адрес IPv6 ни функции
connect
, ни функции
sendto
, поскольку 16-байтовый адрес IPv6 не соответствует 4-байтовой структуре
in_addr
в структуре IPv4
sockaddr_in
. Следовательно, на рисунке нет стрелок от сокетов IPv4 к протоколу IPv6.
В предыдущем разделе (дейтаграмма IPv4, приходящая для сокета сервера IPv6) преобразование полученного адреса IPv4 к виду IPv6 выполняется ядром и результат прозрачно (то есть незаметно для приложения) возвращается приложению функцией
accept
или
recvfrom
. В этом разделе (если необходимо отправить дейтаграмму IPv4 на сокете IPv6) преобразование адреса IPv4 к виду IPv6 выполняется распознавателем в соответствии с правилами, представленными в табл. 11.3, и затем преобразованный адрес прозрачно передается приложению функцией
connect
или
sendto
.
Резюме: совместимость IPv4 и IPv6
Таблица 12.2, содержащая сочетания клиентов и серверов, подводит итог обсуждению, проведенному в данном и предыдущем разделах.
Таблица 12.2. Обобщение совместимости клиентов и серверов IPv4 и IPv6
Сервер IPv4, узел только IPv4 (только А)
Сервер IPv4, узел только IPv6 (только AAAA)
Сервер IPv4, узел с двойным стеком (А и AAAA)
Сервер IPv6, узел с двойным стеком (А и AAAA)
Клиент IPv4, узел только IPv4
IPv4
Нет
IPv4
IPv4
Клиент IPv6, узел только IPv6
Нет
IPv6
Нет
IPv6
Клиент IPv4, узел с двойным стеком
IPv4
Нет
IPv4
IPv4
Клиент IPv6, узел с двойным стеком
IPv4
IPv6
Нет*
IPv6
Каждая
ячейка этой таблицы содержит поля «IPv4» или «IPv6» с указанием используемого протокола, если данное сочетание работает, либо «нет», если комбинация недопустима. Ячейка в последней строке третьей колонки отмечена звездочкой, поскольку совместимость зависит от адреса, выбранного клиентом. При выборе записи типа AAAA отправка дейтаграммы IPv6 будет невозможна. Но выбор записи типа А, которая возвращается клиенту как адрес IPv4, преобразованный к виду IPv6, приведет к отправке дейтаграммы IPv4. Перебрав все адреса, возвращаемые
getaddrinfo
, мы обязательно доберемся до адреса IPv4, преобразованного к виду IPv6, пусть даже и потратив некоторое время на безуспешное ожидание.
Хотя четверть из представленных в таблице сочетаний недопустима, в обозримом будущем большинство реализаций IPv6 будут использоваться на узлах с двойным стеком протоколов и поддерживать не только IPv6. Если мы удалим из таблицы вторую строку и вторую колонку, все записи «Нет» исчезнут и единственной проблемой останется запись, помеченная звездочкой.
12.4. Макроопределения проверки адреса IPv6
Существует небольшой класс приложений IPv6, которые должны знать, с каким собеседником они взаимодействуют (IPv4 или IPv6). Эти приложения должны знать, является ли адрес собеседника адресом IPv4, преобразованным к виду IPv6. Определены двенадцать макросов, проверяющих некоторые свойства адреса Ipv6.
#include <netinet/in.h>
int IN6_IS_ADDR_UNSPECIFIED(const struct in6_addr * aptr);
int IN6_IS_ADDR_LOOPBACK(const struct in6_addr * aptr);
int IN6_IS_ADDR_MULTICAST(const struct in6_addr * aptr);
int IN6_IS_ADDR_LINKLOCAL(const struct in6_addr * aptr);
int IN6_IS_ADDR_SITELOCAL(const struct in6_addr * aptr);
int IN6_IS_ADDR_V4MAPPED(const struct in6_addr * aptr);
int IN6_IS_ADDR_V4COMPAT(const struct in6_addr * aptr);
int IN6_IS_ADDR_MC_NODELOCAL(const struct in6_addr * aptr);
int IN6_IS_ADDR_MC_LINKLOCAL(const struct in6_addr * aptr);
int IN6_IS_ADDR_MC_SITELOCAL(const struct in6_addr * aptr);
int IN6_IS_ADDR_MC_ORGLOCAL(const struct in6_addr * aptr);
int IN6_IS_ADDR_MC_GLOBAL(const struct in6_addr * aptr);
Все возвращают: ненулевое значение, если адрес IPv6 имеет указанный тип, 0 в противном случае
Первые семь макросов проверяют базовый тип адреса IPv6. Мы покажем различные типы адресов в разделе А.5. Последние пять макросов проверяют область действия адреса многоадресной передачи IPv6 (см. раздел 19.2).