IPv6 para Programadores

O crescimento da Internet

A Internet como a conhecemos hoje teve as suas origens na ARPANET [1], a primeira rede a implementar o conjunto de protocolos IP (Internet Protocol) [2], do qual o mais conhecido é o TCP (Transmission Control Protocol) [3].

Pretendia-se um protocolo que transmitisse informação, dividida em pacotes de tamanho reduzido, e cuja gestão de rede fosse descentralizada, já que em tempo de Guerra Fria havia a possibilidade de destruição de partes da rede.

Foi utilizada a versão 4 do protocolo IP (IPv4). Na altura estimava-se um número reduzido de máquinas ligadas à rede, mas 40 anos depois a situação é bem diferente:

DataUtilizadores ligados à Internet
1995-1216 M
2000-12361 M
2005-121018 M
2010-091971 M
2015-12 (est.)3353 M

Fonte: http://www.internetworldstats.com/emarketing.htm

No início dos anos 1990s, e até hoje, dá-se um crescimento continuado do número de pessoas ligadas à Internet, que actualmente se situa perto de 50% da população mundial. Adicionalmente, cada utilizador tem mais que um aparelho (computador, telemóvel, etc.). Mais recentemente (e apesar de o conceito não ser novo), surge a Internet of Things, cuja ideia é ligar todos os aparelhos do dia-a-dia à Internet (televisão, frigorífico, carro, elevador, relógio, roupa, animal de estimação, etc.).

O protocolo IPv4 tem uma grave limitação de endereçamento: só suporta 232 ou 4294967296 endereços (teóricos) mas devido a limitações técnicas, apenas se podem atribuir pouco mais de 3000 milhões, ou seja, há actualmente menos endereços públicos disponíveis que o número de utilizadores e máquinas/dispositivos.

A IANA (Internet Assigned Numbers Authority) é a entidade responsável pela atribuição de endereços IPv4 e IPv6, assim como outras numerações (e.g. portas dos protocolos TCP e UDP, etc.). Esta, por sua vez, delega em 5 RIRs (Regional Internet Registries). O RIPE NCC é responsável pela atribuição de endereços na Europa (incluindo toda a Rússia) e Médio Oriente. Esta é a lista de endereços IPv4 actualmente disponíveis:

IPv4: disponibilidade de endereços

Nota: Um bloco “/8” corresponde a 224 ou 16777216 endereços

Fonte: http://www.potaroo.net/tools/ipv4/plotend.png (2015-12)

Devido a uma política conservadora de atribuição de endereços, assim como de recuperação de endereços não utilizados, a disponibilidade do RIPE tem-se mantido estável, actualmente com cerca de 15 milhões de endereços IPv4 disponíveis. Já a ARIN, o RIR da América do Norte, esgotou totalmente há alguns meses. Isto significa que os operadores que pretendam ligar-se à internet nesse continente terão que comprar os blocos de endereços num mercado especial (com custos muito elevados).

IPv6, o sucessor do IPv4

Desde o final dos anos 1980s que este problema tem sido analisado. Várias alternativas para substituição do IPv4 foram propostas:

Versão IP (*)NomeEstado
0 a 3Internet Protocol testsExperimental / Obsoleta
4Internet Protocol Version 4 (IPv4)Ainda em funcionamento
5Internet Stream ProtocolExperimental
6Internet Protocol Version 6 (IPv6)Em funcionamento / Actual
7TP/IXExperimental / Obsoleta
8PIPExperimental / Obsoleta
9TCP and UDP with Bigger Addresses (TUBA)Experimental / Obsoleta
10 a 15ReservadaReservada

(*) Corresponde ao campo de Versão do cabeçalho dum pacote IP, cuja dimensão é 4 bits.

Após vários anos de debate e análise, as instituições que geriam a internet optaram pelo IPv6 como melhor alternativa ao IPv4. Devido à lenta adopção do IPv6, foi também criado o protocolo NAT (Network Address Translation) [4] que permite partilhar um único endereço IPv4 público com vários dispositivos que usam endereçamento privado (e.g. 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, entre outros).

O IPv6 trouxe algumas melhorias. Estas são apenas algumas:

  • Endereçamento maior:
    • Permite 2128 ou 340282366920938463374607432768211456 endereços, o suficiente para atribuir um endereço a cada átomo do universo;
    • Efectivamente apenas 264 ou 18446744073709551616 endereços são atribuídos publicamente, mas mesmo assim mais que suficientes;
    • Os outros 264 endereços (ou mais) são atribuídos por cliente, também suficientes para todas as nossas necessidades em dispositivos IoT;
    • NAT é desnecessário: todos os dispositivos têm endereço IPv6 público.
  • Transmissão mais rápida:
    • Não se dá fragmentação de pacotes (i.e., necessidade de dividir os pacotes se excederem a MTU [5] de cada troço da rede por onde passa). A MTU típica de cada pacote em redes Ethernet é de 1500 bytes, embora seja possível usar Jumbo Frames até 9000 bytes. O tamanho máximo de cada pacote é obtido quando se inicia uma ligação (usando Path MTU Discovery [6]), evitando a fragmentação de pacotes e reduzindo assim a latência;
    • A checksum dos pacotes de IPv4 incluíam todos os campos do cabeçalho, o que obrigava a recalcular em cada hop (nó da rede). Em IPv6 a checksum aplica-se apenas aos campos do cabeçalho que não se alteram desde a origem até ao destino, evitando a necessidade de recalcular, reduzindo também a latência;
    • Simplificação do hardware em consequência da não fragmentação e de não necessitar de recalcular a checksum.
  • Routing mais eficiente:
    • O Routing em IPv4 implicava gerir uma lista significativa de blocos por cada AS (Autonomous System, ou seja, as atribuições de cada operador). Já em IPv6, como as atribuições são bastante grandes, cada operador tem tipicamente um único bloco;
    • Sem NAT não existe necessidade de tradução de endereços públicos/privados.

O IPv4 será descontinuado num futuro próximo, ficando apenas a funcionar o IPv6.

IPv6 para tótós

O protocolo IPv6 foi originalmente publicado no RFC1883 [7], e actualizado pelo RFC2460 [8], entre outros. Aqui fica o resumo que qualquer profissional de informática deve saber.

Consoante o tipo de ligação disponível, há várias alternativas para acesso aos mundos IPv4 e IPv6:

  • Apenas IPv4 nativo:
    • É possível ligar a IPv6 utilizando Túneis [9] (6in4, 6to4/Teredo, 6RD, etc.).
  • IPv4 + IPv6 nativos (chamado Dual Stack):
    • Acesso directo sem túneis;
    • Acesso IPv4 pode eventualmente utilizar NAT para partilhar um endereço público com vários dispositivos com endereços IPv4 privados.
  • Apenas IPv6 nativo:
    • É possível ligar a IPv4 utilizando túneis e outros métodos (NAT64/DNS64, 464XLAT, DS-Lite, etc.)
    • Muito utilizado na Ásia onde não é viável facultar endereços IPv4 públicos aos utilizadores;
    • A título de curiosidade, a infraestrutura interna do Facebook tem exclusivamente endereçamento IPv6, só os frontends suportam IPv4.

Formato dos endereços IPv6:

  • 128 bits;
  • 32 dígitos hexadecimais (0-9, A-F), case insensitive;
  • 8 grupos de 4 dígitos hexadecimais usando : como separador;
  • Em cada grupo, os 0 à esquerda podem ser omitidos;
  • :: significa que todos os dígitos num ou mais grupos seguidos são 0. Só pode ser utilizado uma vez;
  • / define o scope da subnet – usa dígitos em decimal (0 a 128);
  • % define a interface física por onde passa a comunicação;
  • Os endereços podem ser envolvidos em parêntesis rectos se necessário, em particular quando se usam números das portas.

O mesmo endereço IPv6 pode ser escrito de várias formas. Aqui fica um exemplo (os espaços estão presentes apenas para facilitar a leitura e não devem ser utilizados):

  • DNS: FCCN.PT (registo AAAA)
  • Endereço: 2001:0690:0A00:1036:1113:0000:0000:0247/128
  • Reduzido: 2001: 690: A00:1036:1113:   0:   0: 247/128
  • Canónico: 2001: 690: A00:1036:1113::          247
  • Alocação da rede: 2001: 690::/29
  • Com um interface: 2001: 690:A00:1036:1113::247%21
  • Com uma porta: [2001:690:A00:1036:1113::247]:80 (HTTP)

Também o PTR (pointer record – usado para reverse DNS, ou seja, para obter o endereço DNS a partir do endereço de IP) muda em IPv6:

  • PTR: 4.2.0.0.0.0.0.0.0.0.0.3.1.1.1.6.3.0.1.0.0.a.0.0.9.6.0.1.0.0.2.ip6.arpa. IN PTR FCCN.PT.

Em IPv4 os operadores entregam normalmente um endereço público nas casas/empresas, mas com IPv6 é entregue uma rede inteira. O mínimo é um /64, mas alguns operadores entregam uma gama maior, como /60 ou /56. Os clientes podem assim gerir as suas subnets como entenderem:

IPv6: subnetting

À semelhança de IPv4, existem alguns endereços especiais em IPv6. Por exemplo, o ::1 é equivalente ao 127.0.0.1 ou LOCALHOST:

AddressesRangeScope
Loopback::1host
Link Localfe80::/10link
Unique Localfc00::/7global
Global Unicast2000::/3global
6to42002::/16global
Multicastff00::/8variable
Teredo2001::/32global

Em IPv4, para um dispositivo obter um endereço, utiliza DHCP (ou alternativamente configura o endereço IPv4 manualmente). Em IPv6 há várias formas de obter endereços, a maioria sem necessidade de haver um servidor que forneça endereços (Neighbour Discovery Protocol, DHCPv6, manualmente, etc.). O método mais usado é o de detectar pelos vizinhos qual o endereço público da rede (primeiros 64 bits), e utilizando o MAC Address do dispositivo para preencher os últimos 64 bits:

IPv6: MAC Address para EUI-64 address

Isto pode, no entanto, ser considerado uma falta de segurança, já que pelo MAC Address é possível obter a marca/modelo do dispositivo. No limite, seria possível detectar que o mesmo dispositivo esteve presente em redes diferentes em locais diferentes (e assim gerar um perfil da utilização online da pessoa). Por esse motivo, foram criadas as “Privacy Extensions for Stateless Address Autoconfiguration in IPv6” [10], que em vez do MAC Address utilizam dígitos aleatórios, que substituem regularmente (e.g. a cada hora) para aumentar a privacidade.

Tipicamente, cada interface de rede tem vários endereços IPv6: o endereço Link-Local (baseado no MAC Address), o endereço de auto-configuração (também baseado no MAC Address), o endereço variável com base nas Privacy Extensions, entre outros. Como habitual, os endereços podem ser consultados usando:

  • Linux
    ifconfig -a
  • Windows
    IPCONFIG /ALL

Além dos endereços IPv6, toda a infraestrutura de nomes DNS funciona com IPv6 com pequenas alterações:

  • IPv4: Um endereço é guardado usando um registo do tipo A;
  • IPv6: Um endereço é guardado usando um registo do tipo AAAA (lê-se quad-A);
  • Os registos do tipo CNAME ou MX continuam a funcionar em ambos, já que apenas apontam textualmente para outros registos do tipo A ou AAAA;
  • Os registos de SPF (tipo TXT) suportam IPv6 usando o prefixo ip6:;
  • Os registos de reverse DNS (tipo PTR) baseiam-se em IP6.ARPA.

Ao fazer um pedido pelo nome, um dispositivo dual-stack tipicamente tentará resolver o endereço para IPv6 primeiro, pedindo o registo AAAA, e apenas se não existir tentará pedir o registo A. Tentará ligar-se primeiro ao endereço IPv6. Se falhar (timeout, etc.), tentará ao fim de alguns segundos o endereço IPv4. Caso haja uma demora significativa a estabelecer a ligação, pode ser sinal de haver um problema com a ligação IPv6 que teve failover para IPv4.

Em IPv4 existe o TCP e o UDP, ambos com 65535 portas (de 1 a 65535) que estão atribuídas a serviços. Um exemplo é a porta 80 utilizada pelo protocolo HTTP. Em IPv6 existe o TCPv6 e o UDPv6, em tudo semelhantes (excepto nos endereços), e cujas portas mantêm a mesma numeração e funcionalidade. Convém apenas salientar que, para evitar ambiguidades, é necessário envolver os endereços com parêntesis rectos quando se indica o número da portas.

  • IPv4: 123.123.123:80 (HTTP)
  • IPv6: [456:789::ABCD]:80 (HTTP)

Existe muito mais informação online sobre IPv6. Recomenda-se a leitura da página da Wikipédia de IPv6 [11], cujo conteúdo é bastante acessível.

Recomendações para programadores

A maioria dos servidores web (IIS, Apache, NGINX, etc.) suporta IPv6 de forma transparente. Aqui é necessário apenas garantir que estão listening em IPv6 e que eventuais configurações (e.g. listas de acessos por IPv6, etc.) estão devidamente preenchidas e testadas.

Tirando as situações listadas de seguida, um programador web pode estar descansado que tudo funcionará em IPv6 da mesma forma que em IPv4.

A maioria dos CMS/CRM/ERP pode registar os endereços IPv4 que acederam ao respectivo site, mas só recentemente estes começaram a ser compatíveis com endereços IPv6. Afinal o que é necessário para armazenar endereços numa base de dados (relacional ou outra)?

  • Um endereço IPv4 necessita de 15 caracteres de armazenamento;
  • Um endereço IPv6 necessita de 39 (endereço) + 4 (subnet) + N (interface). Ou seja, pelo menos 48 caracteres são recomendados;
  • O mesmo campo pode ser usado para armazenar IPv4 e IPv6 (e.g. distinguir detectando se existe :, o que implica ser IPv6, ou colocando um prefixo que diga qual a versão, etc.);
  • Não é recomendado armazenar em formato binário ou numérico;
  • Podem ser armazenados em formato canónico (reduzido) ou expandido (incluindo todos os zeros, com ou sem os :);
  • É necessário escolher se são armazenados em maiúsculas ou minúsculas, sendo também recomendado que a collation do respectivo campo seja case-insensitive;
  • Não é recomendado armazenar apenas os primeiros 64 bits do cliente, já que múltiplos clientes podem estar a partilhar a mesma ligação, tendo apenas os últimos 64 bits como diferença.

Na gestão e/ou validação de acessos, é habitual garantir que pedidos sucessivos do mesmo utilizador originam do mesmo endereço de IP. Algumas implementações aceitam que o IPv4 mude, desde que na mesma subnet (aceitar qualquer número na última parte do endereço, ou seja, o endereço IPv4 pertencer à mesma /24). Já em IPv6 as coisas são bem diferentes: com as “Privacy Extensions” o endereço IPv6 dum utilizador muda regularmente (pelo menos os últimos 64 bits). Assim, a recomendação é validar usando apenas os primeiros 64 bits do endereço (parte da rede), ignorando alterações aos últimos 64 bits (parte interna do cliente). Em alguns casos, pode detectar-se que o cliente tem atribuída uma rede maior (e.g. /60) e ser necessário expandir a tolerância às respectivas subnets. Em qualquer caso, deve sempre haver um token identificador do cliente (e.g. cookie), porque tanto em IPv4 como IPv6 é possível encontrar dois clientes que partilham o mesmo endereço.

Este exemplo mostra o endereço e a versão de IP do cliente numa página web (nota: foi utilizado PHP mas noutras linguagens o código será semelhante):

<?php
$Andy_IPAddress = StrToUpper(Trim($_SERVER["REMOTE_ADDR"]));

If(PReg_Match("/\d+\.\d+\.\d+/", $Andy_IPAddress) ) {
   $Andy_IPVersion = "IPv4";
}
Else If(PReg_Match("/[0-9A-F]+\:[0-9A-f\:\.]+/ i", $Andy_IPAddress) )
{
   $Andy_IPVersion = "IPv6";
}
Else {
   $Andy_IPVersion = "?";
}
Print ("\tYour IP Address is: <STRONG>" . $Andy_IPAddress . "</STRONG><BR>\n");
Print ("\tYour IP Version is: <STRONG>" . $Andy_IPVersion . "</STRONG><BR>\n");
?>

E se tentarmos programar uma ligação a uma máquina remota, quais as recomendações?

  • Sempre que possível usar endereços DNS e nunca endereços IPv4 ou IPv6. Isto garante que o sistema operativo decidirá qual a melhor forma de efectuar a ligação;
  • Nos casos em que queremos reduzir o tempo despendido com a consulta DNS (e.g. ligação dum servidor web a uma base de dados), pode ser realmente ser necessário colocar o endereço. O recomendado é colocar o endereço IPv6, já que a latência é normalmente menor;
  • Em algumas situações raras, pode ser útil incluir a interface no endereço, para evitar que o sistema operativo demore a escolher por qual deve fazer a ligação. No entanto, uma mudança de hardware poderá implicar alterações às configurações, pelo que não é recomendado.

Se uma aplicação ou página web necessitar realmente de obter um endereço IPv4 ou IPv6 (registos A ou AAAA) a partir dum endereço DNS, pode usar funções de consulta DNS. Todas as linguagens mais utilizadas já suportam IPv6 (nota: estas funções variam muito de linguagem para linguagem). Para detectar se existe um determinado registo DNS:

<?php
$Andy_DNS_NAME = "ANDY.PT"; //Don't forget the "." in the end!

$Andy_Exists_A = (CheckDNSrr($Andy_DNS_NAME, "A" ) ? "Yes" : "No");
$Andy_Exists_AAAA = (CheckDNSrr($Andy_DNS_NAME, "AAA") ? "Yes" : "No");

Print ("\t" . $Andy_DNS_NAME . " A record exists? <STRONG>" . $Andy_Exists_A . "</STRONG><BR/>\n"); Print ("\t" . $Andy_DNS_NAME - " AAAA Record exists? <STRONG>" . $Andy_Exists_AAAA . "</STRONG><BR/>\n");
?>

Obter um registo AAAA não é muito diferente de obter um registo A:

<?php
$Andy_DNS_NAME = "ANDY.PT"; //Don't forget the "." in the end!

$Andy_Exists_A = DNS_Get_Record ( $Andy_DNS_NAME, DNS_A);
$Andy_Exists_AAAA = DNS_Get_Record ( $Andy_DNS_NAME, DNS_AAAA);

Print_R ($Andy_DNS_Get_A);
Print_R ($Andy_DNS_Get_AAAA);
?>

O resultado neste caso é:

Array
{
    [0] => Array
        {
            [host] => FCCN.PT
            [class] => IN
            [ttl] => 3600
            [type] => A
            [ip] => 193.137.196.247
        }
}
Array
{
    [0] => Array
        {
            [host] => FCCN.PT
            [class] => IN
            [ttl] => 3600
            [type] => AAAA
            [ipv6] => 2001:690:a00:1036:1113::247
        }
}

Referências e links

Referências presentes no texto

  1. https://en.wikipedia.org/wiki/Internet
  2. https://en.wikipedia.org/wiki/Internet_Protocol_Suite
  3. https://en.wikipedia.org/wiki/Transmission_Control_Protocol
  4. https://en.wikipedia.org/wiki/Network_address_translation
  5. https://en.wikipedia.org/wiki/Maximum_transmission_unit
  6. https://en.wikipedia.org/wiki/Path_MTU_Discovery
  7. https://tools.ietf.org/html/rfc1883 (IPv6, RFC inicial)
  8. https://tools.ietf.org/html/rfc2460 (IPv6, RFC actual)
  9. https://en.wikipedia.org/wiki/IPv6_transition_mechanism
  10. https://tools.ietf.org/html/rfc4941 (“Privacy Extensions for Stateless Address Autoconfiguration in IPv6”)
  11. https://en.wikipedia.org/wiki/IPv6

Dinamizadores em Portugal

Dinamizadores internacionais

Publicado na edição 51 (PDF) da Revista PROGRAMAR.