Resumo

  • As funções centrais recebiam ponteiro opaco e comprimento do endereço; por isso sua sintaxe podia permanecer. IPv6 ainda exigia PF_INET6, sockaddr_in6 e novas rotinas de nomes e conversão.
  • Preservar aplicativos PF_INET para conversar com nós IPv4 e permitir que aplicativos PF_INET6 representem um par IPv4 como endereço mapeado são compromissos diferentes, nenhum deles prova entrega de serviço.

O teste mais revelador ocorre entre processos. Um programa passa um socket aberto a outro, e o sucessor chama getpeername() como sempre. Se esperar sockaddr_in quando o sistema devolve sockaddr_in6, a chamada conhecida produz uma leitura errada. O RFC 2133, texto informativo publicado em abril de 1997 e posteriormente tornado obsoleto pelo RFC 2553, incluiu esse caso em seu desenho de compatibilidade.

O problema começava com o tamanho. IPv4 usa 32 bits para o endereço; IPv6, 128. As funções de socket carregavam um endereço por ponteiro opaco e recebiam seu comprimento, então bind(), connect() e sendto() não precisavam de nova assinatura. Já sockaddr_in não comportava endereço IPv6 completo, família e porta, mesmo aproveitando bytes não usados. Surgiram AF_INET6, PF_INET6 e sockaddr_in6. Resolução de nomes e conversão entre endereço binário e texto também precisaram de uma interface mais ampla. As versões de sockaddr_in6 descritas para BSD 4.3 e 4.4 diferiam no arranjo dos campos de família e comprimento. Código preso a um buffer antigo continuava vulnerável.

Uma promessa era preservar programas antigos: fonte recompilada e binário existente usando PF_INET e sockaddr_in continuariam a falar com nós IPv4 em um sistema que também suportasse IPv6. Isso não os transformava em programas IPv6. Outra promessa servia ao aplicativo novo. Em um socket PF_INET6, o endereço de um nó IPv4 podia ser codificado como ::FFFF:<endereço IPv4> e transportado em sockaddr_in6. A representação mapeada pertence à API. Não é observação de que o par ou o tráfego sejam IPv6.

Endereço curinga e loopback adicionam cautela. O primeiro permite ao sistema escolher um endereço local; o segundo aponta para a própria máquina. Nenhum equivale a medir quem consegue chegar ao serviço. RFC 2133 especificou operações disponíveis, não o resultado de redes implantadas.

A opção histórica IPV6_ADDRFORM tratava justamente do descritor passado a outro processo. Ela podia alterar a forma pela qual chamadas posteriores expunham um socket como PF_INET ou PF_INET6. A passagem para PF_INET exigia que todos os endereços não curinga já associados fossem IPv4 mapeados. O estado existente no núcleo restringia a conversão. Como o documento foi substituído, essa proposta não deve ser apresentada como recurso portátil de sistemas atuais.

Também havia contexto local nos índices de interface. if_nametoindex relacionava nome e número atribuído pelo núcleo; opções de multicast selecionavam a interface de saída ou a participação local em um grupo. Configurar essa escolha não demonstrava que um pacote alcançou outro host. Da mesma forma, obter um endereço por resolução de nome não comprovava que a aplicação concluiu a comunicação.

O valor histórico do RFC está em separar as camadas de prova. A reflexão de Lu Heng sobre a primazia do código em funcionamento ajuda a formular a pergunta editorial sobre observação; ela não é fonte das afirmações técnicas, que vêm do próprio RFC.

Fontes: RFC 2133, registro do RFC Editor e RFC 2553.