Debugging de inconsistência DNS: split-horizon e race conditions no Linux
Voltar para blog

Debugging de inconsistência DNS: split-horizon e race conditions no Linux

30/09/2026 · 4 min · Infraestrutura

O fantasma do IP antigo: quando split-horizon e race conditions corrompem a resolução DNS#

O DNS costuma ser o primeiro suspeito em comportamentos estranhos de rede. Recentemente, enfrentei um caso curioso: um sintoma de "Split-Horizon" às avessas em um servidor Linux rodando DirectAdmin e BIND.

Neste artigo, detalho o passo a passo da investigação, do sintoma de latência e rota errada até a solução na camada do sistema operacional.


O problema: o fantasma do IP antigo#

O cenário era o seguinte: o domínio meudominio.com.br havia mudado para o IP local do servidor (203.0.113.50). A internet inteira já estava enxergando o IP novo. Porém, ao acessar o terminal do próprio servidor (srv-core) e disparar um simples ping, o ICMP echo request teimava em ser roteado para o IP antigo e externo (198.51.100.10).

Veja o comportamento primário no terminal:

[root@srv-core ~]# ping meudominio.com.br
PING meudominio.com.br (198.51.100.10) 56(84) bytes of data.
64 bytes from srv-old.provedor.com (198.51.100.10): icmp_seq=1 ttl=49 time=27.7 ms

O tráfego estava saindo da máquina e indo buscar o domínio na internet, gerando latência desnecessária e quebrando a comunicação interna entre serviços locais.


Análise detalhada: onde mora a resolução?#

Para entender por que o kernel estava despachando os pacotes para o gateway externo, precisei olhar a cadeia de resolução. O comando ping não consulta o DNS diretamente; ele delega a resolução de nomes para a biblioteca C padrão do sistema (invocando getaddrinfo() na glibc).

A primeira parada foi o arquivo de hosts:

cat /etc/hosts

O arquivo estava limpo, contendo apenas as entradas de loopback (127.0.0.1) e o hostname do servidor. Não havia nada forçando o IP antigo.

Em seguida, verifiquei a zona DNS local do BIND no DirectAdmin:

cat /var/named/meudominio.com.br.db

Ao inspecionar a zona, o serial do SOA estava atualizado e todos os registros A (www, mail, ftp) apontavam corretamente para o IP local 203.0.113.50. O BIND local estava autoritativo e correto.

O ponto de divergência estava no resolvedor do sistema operacional:

cat /etc/resolv.conf
nameserver 8.8.8.8
nameserver 203.0.113.99
nameserver 1.1.1.1

O servidor estava configurado para ignorar o próprio daemon local: o 127.0.0.1 não estava listado. Ele abria sockets UDP diretamente para resolvers públicos externos.


Hipóteses descartadas#

Antes de alterar configurações, isolei os componentes:

  1. Atraso de Propagação Global:

Usando o dig (que ignora a glibc e o nsswitch e consulta os servidores diretamente):

   dig @8.8.8.8 meudominio.com.br +short
   # Retorno: 203.0.113.50

Tanto o Google (8.8.8.8) quanto a Cloudflare (1.1.1.1) retornaram o IP novo instantaneamente. A propagação pública já estava 100% concluída (diferente de cenários onde há falha de glue records no BIND).

  1. Daemons de Cache Locais (nscd / systemd-resolved):

Verifiquei os serviços de cache em memória, mas nem o nscd nem o systemd-resolved estavam ativos. A resolução passava de forma direta pela biblioteca de sistema.


Rastreabilidade e a race condition#

Para garantir que não havia registros residuais na tabela de rotas do kernel, apliquei um flush no cache de rotas:

ip route flush cache

Ao rodar o ping novamente logo após o flush, o sistema revelou o comportamento real: uma race condition na resolução de nomes alternando entre resolvers:

[root@srv-core ~]# ping meudominio.com.br
PING meudominio.com.br (203.0.113.50) ... time=0.024 ms
...
[root@srv-core ~]# ping www.meudominio.com.br
PING www.meudominio.com.br (198.51.100.10) ... time=27.9 ms

As respostas oscilavam: quando a consulta batia no resolvedor local ou no cache rápido da rede, vinha o IP correto com latência de 0.024ms. Quando ocorria timeout ou rotação para o segundo nameserver da lista (203.0.113.99), ele recebia a resposta antiga de um forwarder intermediário com latência de 27.9ms.


A solução prática#

Em servidores com DirectAdmin e BIND local, a prática recomendada é manter nameserver 127.0.0.1 na primeira linha do /etc/resolv.conf.

Para eliminar qualquer dependência de timeout de rede externa e blindar a comunicação local das aplicações, utilizei a prioridade de resolução do /etc/nsswitch.conf. No Linux, a diretiva padrão hosts: files dns instrui o sistema a consultar o arquivo estático antes de disparar queries na rede.

Fixei o apontamento estático no host:

echo "203.0.113.50 meudominio.com.br www.meudominio.com.br" >> /etc/hosts

Ao adicionar a entrada estática no /etc/hosts:

  1. O getaddrinfo() lê o arquivo estático e retorna o IP local em microssegundos.
  2. A oscilação parou imediatamente e o tráfego permaneceu confinado à interface de loopback e rede local.

Considerações práticas de resolução DNS#

Diagnosticar falhas de DNS exige separar a ferramenta de teste da chamada de sistema executada pela aplicação:

Este artigo foi útil?

Deixe uma reação rápida para apoiar o conteúdo:

CC BY-NC

Este post está licenciado sob CC BY-NC.

Comentários

Participe da discussão abaixo.

0 comentários