Ir para o conteúdo
Ir para o conteúdo
Logo NIC.br Logo CGI.br

php


O php não possui a função getaddrinfo, porém ele possui a função gethostbyname:

        string gethostbyname ( string $hostname );
        
	

Além disso, ele também possui outra função chamada gethostbynamel:

        array gethostbynamel ( string $hostname );
        
	

A diferença básica entre os dois é que na função gethostbyname é retornado apenas um único endereço IP. Já na funçao gethostbynamel é retornado um array contendo todos os endereços encontrados. Porém em ambos os casos só são retornados endereços IPv4. Mais informações sobre estas funções podem ser encontradas em:

  1. https://www.php.net/manual/en/function.gethostbyname.php
  2. https://www.php.net/manual/en/function.gethostbynamel.php


Por isso para obter todos os endereços IP, incluindo os endereços IPv6, devemos utilizar a função dns_get_record, que funciona como a função getaddrinfo:

        array dns_get_record ( string $hostname [, int $type = DNS_ANY [, array &$authns [, array &$addtl ]]] );
	


Apesar de parecer complicada, para a implementação do Happy Eyeballs não é necessário adicionar muitos parâmetros a função, somente o tipo de consulta dns a ser feita, que são do tipo DNS_A (para endereços IPv4) e DNS_AAAA (para endereços IPv6):

        $host = 'www.teste.com.br';
        $Arecord = dns_get_record($host, DNS_A);
        $AAAArecord = dns_get_record($host, DNS_AAAA);
	


A função dns_get_record retorna um array com várias informações, porém apenas 2 nos interessam:

  1. type: pode ser de vários tipos, mas nos interessam apenas os tipo A e AAAA para poder identificar o que é IPv6 e o que é IPv4;
  2. ip ou ipv6: dado que vem atrelado ao type quando sua resposta é A ou AAAA. Dentro dele contém qual o IP retornado.


Mais informações sobre a função dns_get_record podem ser encontradas em:

  1. https://php.net/manual/en/function.dns-get-record.php


Para se criar um socket em php, utiliza-se a função socket_create:

        resource socket_create ( int $domain , int $type , int $protocol );
	


Note que todos os parâmetros de entradas são constantes de configuração pré definidas. O parâmetro domain indica qual o protocolo do endreço utilizado (Address Family), podendo ser AF_INET no caso de IPv4 ou AF_INET6 no caso de IPv6. O parâmetro type indica o tipo de protocolo utilizado, que normalmente é do tipo SOCK_STREAM ou SOCK_RAW. O parâmetro protocol indica o tipo de protocolo IP a ser utilizado, como tcp, udp ou icmp. Abaixo temos um exemplo de como criar um socket:

        $socket = socket_create(AF_INET6, SOCK_STREAM, SOL_TCP);
	


Para se conectar a um host utilizando o socket é utilizado a função socket_connect:

        bool socket_connect ( resource $socket , string $address [, int $port = 0 ] );
	


O parâmetro socket é o socket que foi criado na função socket_create. O parâmetro address é o endereço no qual queremos nos conectar. O parâmetro port é a porta na qual o socket irá se conectar. Abaixo utilizaremos o socket criado para se conectar a um IP:

        $socket = socket_create(AF_INET6, SOCK_STREAM, SOL_TCP);
        socket_connect($socket, ‘2001:12ff:0:4::6’, 80)
	


Para setar o socket php para non-blocking basta utilizar a função socket_set_nonblock:

        bool socket_set_nonblock ( resource $socket );
	


Onde o parâmetro socket é o socket no qual queremos tornar non-blocking. Para voltar o socket a forma blocking, utilizamos a função socket_set_block:

        bool socket_set_block ( resource $socket );
	


Abaixo um exemplo de como utilizar um socket non-blocking:

        $socket = socket_create(AF_INET6, SOCK_STREAM, SOL_TCP);
        socket_set_nonblock($socket);
        while (!($connected = @socket_connect($socket,‘2001:12ff:0:4::6’, 80))) {
                // Faz alguma coisa
         }
        // Conectou-se ao servidor
        socket_set_block($socket);
	


Mais informações sobre sockets em php podem ser encontrados em:

  1. https://php.net/manual/en/book.sockets.php
  2. https://www.php.net/manual/en/function.socket-create.php
  3. https://www.php.net/manual/en/function.socket-connect.php
  4. https://www.php.net/manual/en/function.socket-set-block.php
  5. https://www.php.net/manual/en/function.socket-set-nonblock.php

python


Em python, tanto a consulta de DNS quanto as operações de sockets estão dentro da biblioteca socket. Além disso podemos verificar se o sistema utilizado possui suporte a IPv6, através da propriedade:

        socket.has_ipv6
	


Para realizar consultas DNS, temos a função gethostbyname:

        socket.gethostbyname(hostname)
	


Temos também uma versão mais detalhada, chamada gethostbyname_ex:

        socket.gethostbyname_ex(hostname)
	


A diferença básica entre as duas funções são as informações retornadas. Enquanto na função gethostbyname é retornado apenas o endereço IP na forma de string, na função gethostbyname_ex também são retornados a lista de nomes e a lista de IPs disponíveis. No entando nenhuma das duas funções tem suporte a IPv6, portanto não servem para implementar o algoritmo do Happy Eyeballs.

Para realizar consultas DNS que incluem o IPv6, usamos a função getaddrinfo:

        socket.getaddrinfo(host, port, family=0, socktype=0, proto=0, flags=0)
	


Seu funcionamento é o mesmo da linguagem C, portanto as constantes são as mesmas, com o detalhe de que essas constantes estão dentro da biblioteca socket do python. Um exemplo abaixo de como utilizar a função getaddrinfo:

        socket.getaddrinfo(“ipv6.br", 80, socket.AF_INET6, socket.SOCK_STREAM, socket.SOL_TCP)
	


A função acima irá listar os IPv6 disponíveis para uma possível conexão tcp via stream socket na porta 80 do site ipv6.br. O retorno da função getaddrinfo é do tipo:

        (family, socktype, proto, canonname, sockaddr)
	


Para o Happy Eyeballs precisamos apenas do campo sockaddr, que indicam o endereço IP, sendo do tipo (address, port) no caso do IPv4 (AF_INET) e (address, port, flow info, scope id) no caso do IPv6 (AF_INET6). Em ambos os casos utilizaremos apenas o campo address retornado, que é o que realmente precisamos. Veja o exemplo abaixo:

        >>> socket.getaddrinfo("ipv6.br", 80, socket.AF_UNSPEC, socket.SOCK_STREAM, socket.SOL_TCP)
        [(10, 1, 6, '', ('2001:12ff:0:4::22', 80, 0, 0)), (2, 1, 6, '', ('200.160.4.22', 80))]
	


Nesse caso a consulta retorna tanto os endereços IPv4 quanto os endereços IPv6, pois o parâmetro family está setado como AF_UNSPEC, o que faz com que ele aceite qualquer tipo de protocolo como resposta. Mais informações sobre a função getaddrinfo podem ser encontradas em:

  1. https://docs.python.org/library/socket.html#socket.getaddrinfo


Para criar um socket em python basta utilizar a função socket da biblioteca socket:

        socket.socket([family[, type[, proto]]])
	


Sua utilização é bem simples:

        s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
	


Nesse caso o socket criado é atribuído a variável s. É importante observar que pela definição do socket, faltam duas informações essenciais: o endereço IP e a porta na qual tentaremos conectar. Esses parâmetros são indicados quando utilizamos a função connect:

        socket.connect(address)
	



Para setar o socket como non-blocking basta setar sua propriedade setblocking(valor) para 0.

        socket.setblocking(flag)
	

perl


O perl possui um problema grave com relação ao IPv6, pois sua biblioteca padrão de sockets (IO::Socket::INET) não possui suporte a IPv6. Além disso, o perl utiliza um sistema de módulos para serem adicionados e incorporados a ele, porém não existe uma padronização oficial para isso, o que leva a existirem vários módulos diferentes que implementam uma mesma funcionalidade. É o que acontece no caso do módulo que suporta sockets IPv6. Nesta artigo vamos apenas abordar o módulo indicado no próprio site do perl (https://www.perl.org/about/whitepapers/perl-ipv6.html), a nova biblioteca de sockets  (IO::Socket::IP), que suporta tanto IPv4 quanto IPv6.

Javascript


Javascript é um caso especial, pois não é possível realizar consultas DNS diretamente utilizando apenas javascript. Uma solução possível é criar um servidor que faça a consulta em seu lugar e tentar se conectar segundo o algoritmo do Happy Eyeballs. Porém essa prática não é recomendada, pois além de necessitar fazer uma conexão extra fora do escopo, ele fica dependente dessa resposta, além de necessitar de um servidor exclusivo para isso.

Links Úteis

  1. Exemplo de Happy Eyeballs em C: https://www.ipv6forum.com/ipv6_enabled/DNS.php
  2. Happy Eyeballs no squid: https://squidproxy.wordpress.com/2012/07/14/happy-eyeballs/
  3. Hampering Eyeballs: https://labs.ripe.net/Members/emileaben/hampered-eyeballs

 

Compartilhe

Busca