Кратко

  • Базовые функции уже принимали непрозрачный указатель на адрес и его длину, поэтому синтаксис вызова удалось сохранить. Поддержка IPv6 всё же потребовала PF_INET6, sockaddr_in6 и новых операций с именами и представлением адреса.
  • Работа старого приложения PF_INET с узлами IPv4 и возможность нового приложения PF_INET6 представить узел IPv4 отображённым адресом — разные гарантии. Ни одна не подтверждает успешную услугу IPv6.

Представим, что работающий сокет передали следующему процессу. Он вызывает getpeername() без затруднений, но разбирает возвращённые байты как sockaddr_in, хотя они относятся к sockaddr_in6. Сигнатура функции осталась прежней, договор о содержимом данных — нет. Именно этот случай разбирал RFC 2133, опубликованный в апреле 1997 года как информационный документ. Впоследствии его заменил RFC 2553; это материал по истории проектирования, а не инструкция для нынешних систем.

Разница в размере задавала предел старому формату. Адрес IPv4 занимал 32 бита, IPv6 — 128. Функции сокетов передавали адрес через непрозрачный указатель вместе с длиной; bind(), connect() и sendto() не требовали нового синтаксиса. Однако sockaddr_in не мог вместить полный адрес IPv6, семейство и порт даже с учётом свободных байтов. Понадобились AF_INET6, PF_INET6, sockaddr_in6, расширенные преобразования адресов и поиск по именам. Варианты структуры для BSD 4.3 и 4.4 различались расположением полей длины и семейства. Код с жёстким размером буфера не становился безопасным от сохранения старого названия вызова.

Первая гарантия защищала прежние программы. Система с новым интерфейсом должна была сохранять исходную и двоичную совместимость для PF_INET и sockaddr_in: старые приложения продолжали общаться с узлами IPv4. Это не делало старый исполняемый файл приложением IPv6. Вторая гарантия относилась к новой программе PF_INET6. Она могла поместить адрес узла IPv4 в sockaddr_in6 как ::FFFF:<адрес IPv4>. Такое отображение — форма адреса в API. Оно не доказывает, что удалённая сторона или пакеты говорили на IPv6.

Неопределённый адрес IPv6 и адрес обратной связи тоже имеют узкую область смысла. Первый позволяет системе выбрать локальный адрес, второй ведёт на тот же компьютер. По ним нельзя судить о доступности сервиса извне. RFC описывал допустимые операции, но не приводил статистики их внедрения.

Опция IPV6_ADDRFORM в историческом предложении решала проблему передачи открытого сокета через exec() или иным способом. Она меняла вид адресов, который последующие вызовы представляли как PF_INET либо PF_INET6. Переход обратно к PF_INET разрешался, только если все уже связанные адреса, кроме wildcard, были отображёнными адресами IPv4. Ограничение зависело от существующего состояния ядра; простая смена ярлыка не помогала. Из устаревшего текста нельзя выводить, что все современные платформы одинаково поддерживают эту опцию.

Индексы интерфейсов давали ещё один пример локального контекста. if_nametoindex связывал имя с номером, назначенным ядром. Настройки многоадресной передачи выбирали выходной интерфейс или локальное членство в группе. Эти факты не доказывают доставку пакета другому узлу и обработку его приложением. Результат разрешения имени — лишь кандидат для дальнейшего соединения.

Статья Lu Heng о первенстве работающего кода помогает поставить редакционный вопрос о наблюдаемом результате. Технические положения здесь опираются на RFC; эссе не заменяет первичный документ.

Источники: RFC 2133, запись RFC Editor и RFC 2553.