Artigos aprofundados sobre a tecnologia que molda o que vem a seguir.

A configuração de DNS continua quebrando produção

DNS parece simples até quebrar. Veja como atualizações de SO, resolv.conf, mDNS e o TLD .internal causam quedas em produção que devs não veem chegando.

Cartas sendo desviadas para tubos pneumáticos errados em uma sala de triagem

A mais recente versão do macOS da Apple quebrou as configurações de DNS personalizadas de milhares de desenvolvedores. Especificamente, ela passou a interceptar consultas para o TLD .internal — que muitas empresas usam para recursos de rede privada — e a encaminhá-las para o mDNS (multicast DNS) em vez do resolvedor DNS configurado. Serviços que funcionavam bem há anos de repente ficaram inacessíveis. A solução não era óbvia. As mensagens de erro não ajudavam. E, como sempre acontece com problemas de DNS, os sintomas pareciam tudo exceto DNS.

Esta é uma história sobre configuração de DNS — um tema que todo desenvolvedor encontra, poucos entendem a fundo e todos subestimam até quebrar algo em produção às 2 da manhã.

O incidente do TLD .internal

Muitas organizações usam .internal como um TLD privado para serviços internos: api.internal, db.staging.internal, grafana.internal. Parecia uma escolha segura — não é um TLD público, sinaliza claramente “isto é interno” e vem sendo usado assim há décadas.

Então o novo SO da Apple decidiu que .internal deveria ser tratado pelo mDNS — o mesmo protocolo que resolve myprinter.local na sua rede doméstica. Quando seu Mac tenta resolver api.internal, em vez de perguntar ao servidor DNS configurado, ele envia uma consulta mDNS para a rede local. Seu servidor DNS nunca vê a consulta. A resposta é ou nada (timeout) ou o endereço errado (caso algo na rede local responda a esse nome).

Os sintomas: curl api.internal fica travado por 5 segundos e depois falha. Conexões SSH com hosts internos dão timeout. Usuários de VPN não conseguem acessar recursos internos. Contêineres Docker não conseguem resolver nomes de serviços. E como a falha aparece como um timeout genérico de conexão, a maioria dos desenvolvedores começa a depurar a VPN, o firewall, a aplicação — tudo menos o DNS.

Como a resolução de DNS realmente funciona em sistemas modernos

O modelo mental de “DNS é simples” — seu computador pergunta a um servidor DNS qual é o IP, e o servidor responde — não reflete a realidade há anos. Os sistemas modernos têm um pipeline de resolução com vários estágios, e cada um deles pode interceptar, modificar ou redirecionar consultas.

DNS resolution pipeline on a typical macOS/Linux system:
Application calls getaddrinfo("api.internal")
↓
1. /etc/hosts — checked first. Static overrides.
↓
2. NSSwitch / resolver configuration
- Linux: /etc/nsswitch.conf controls lookup order
- macOS: /etc/resolver/* for per-domain DNS servers
↓
3. System resolver (systemd-resolved, mDNSResponder)
- May intercept .local, .internal, or other special TLDs
- May apply DNSSEC validation
- May cache responses
↓
4. DNS server (from DHCP, VPN, or manual config)
- Queries sent to configured upstream resolver
- May go through a corporate DNS proxy
↓
5. Recursive resolver (8.8.8.8, 1.1.1.1, corporate)
- Walks the DNS hierarchy: root → TLD → authoritative
↓
Response flows back up the chain

Em cada estágio, algo pode dar errado. O resolvedor do sistema pode interceptar uma consulta antes que ela chegue ao servidor DNS configurado. A VPN pode sobrescrever as configurações de DNS. O DHCP pode informar servidores DNS que têm precedência sobre sua configuração manual. E o cache em todos os níveis significa que uma correção pode não surtir efeito imediatamente.

A mentira do /etc/resolv.conf

No Linux, /etc/resolv.conf era historicamente a única fonte de verdade para a configuração de DNS. Defina seu nameserver ali e o sistema o utiliza. Simples.

As distribuições Linux modernas tornaram isso bem mais complicado. Se você usa systemd-resolved (que Ubuntu, Fedora e a maioria das distros baseadas em systemd adotam por padrão), /etc/resolv.conf é um link simbólico para um stub resolver em 127.0.0.53. Sua configuração real de DNS fica no estado do systemd-resolved, gerenciada pelo resolvectl. Editar /etc/resolv.conf diretamente ou é sobrescrito na próxima mudança de rede ou quebra o stub resolver.

# What you THINK your DNS config is:
$ cat /etc/resolv.conf
nameserver 127.0.0.53  # This is systemd-resolved's stub
# What your DNS config ACTUALLY is:
$ resolvectl status
Global:
DNS Servers: 8.8.8.8 8.8.4.4
DNS Domain: ~.
Link 2 (eth0):
DNS Servers: 10.0.0.1  # From DHCP — this takes precedence
DNS Domain: corp.internal
Link 5 (wg0):  # WireGuard VPN
DNS Servers: 10.100.0.1
DNS Domain: ~internal  # VPN claims the .internal domain
# Three different DNS servers, each handling different domains.
# /etc/resolv.conf shows none of this.

O Docker adiciona mais uma camada. Contêineres Docker recebem o próprio /etc/resolv.conf, normalmente copiado da configuração do host quando o contêiner inicia. Se o DNS do host mudar (a VPN conecta, a rede troca), contêineres em execução mantêm a configuração antiga até serem reiniciados. Essa é uma fonte comum de bugs do tipo “funciona depois de reiniciar, mas falha depois de um tempo”.

Split DNS e conflitos com VPN

Split DNS — usar servidores DNS diferentes para domínios diferentes — é padrão em ambientes corporativos. Sua VPN encaminha consultas de *.corp.internal para o servidor DNS corporativo, enquanto consultas públicas vão para o resolvedor normal. Isso funciona bem quando configurado corretamente e falha de formas confusas quando não é.

Modos de falha comuns:

  • A VPN define servidores DNS como padrão global. Alguns clientes de VPN configuram o servidor DNS da VPN como resolvedor padrão para todas as consultas, não só as internas. Todas as suas consultas de DNS — inclusive a navegação pessoal — passam a ir pelo servidor corporativo. Isso é lento (porque o DNS corporativo está em outro datacenter) e um problema de privacidade.
  • Conflitos na ordem dos servidores DNS. Quando vários servidores DNS estão configurados, o sistema os tenta em ordem. Se o primeiro estiver lento ou inacessível (VPN desconectada, mas a configuração de DNS persiste), cada consulta espera um timeout antes de tentar o segundo. Isso adiciona atrasos de 5 segundos a cada conexão.
  • Domínios de busca são anexados silenciosamente. Um domínio de busca corp.internal faz com que uma consulta por api também tente api.corp.internal. Isso é útil (digite ssh api em vez de ssh api.corp.internal) até deixar de ser — quando um hostname curto colide com o nome de um serviço interno, as consultas resolvem para o IP errado.
  • O mDNS intercepta domínios internos. Como mostra o incidente com .internal, o resolvedor do sistema pode interceptar consultas para certos TLDs antes que cheguem a qualquer servidor DNS configurado. Isso é especialmente traiçoeiro porque a interceptação acontece sem aviso — nenhuma mensagem de erro, só um timeout ou uma resposta errada.

Depurando DNS: o kit de ferramentas

Quando o DNS quebra, você precisa de ferramentas que mostrem exatamente o que está acontecendo em cada estágio do pipeline de resolução.

# 1. Check what your system actually resolves:
$ dig api.internal
# Shows: query sent to which server, response received
# The 'SERVER' line tells you which DNS server answered
# 2. Query a specific DNS server directly:
$ dig @10.100.0.1 api.internal
# Bypasses the system resolver — goes directly to the specified server
# If this works but 'dig api.internal' doesn't, the problem is
# in the system resolver, not the DNS server
# 3. Check systemd-resolved state (Linux):
$ resolvectl query api.internal
# Shows which interface/server handled the query
# 4. Check macOS DNS routing:
$ scutil --dns
# Shows per-domain DNS configuration on macOS
# Look for your .internal domain — is it being routed correctly?
# 5. Monitor DNS queries in real time:
$ sudo tcpdump -i any port 53
# See actual DNS packets. If no packets go out for your query,
# the system resolver is intercepting it locally.
# 6. Flush DNS cache (when fixing config):
$ sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder  # macOS
$ resolvectl flush-caches  # Linux with systemd-resolved

O passo de diagnóstico mais importante: consulte seu servidor DNS diretamente com dig @servidor nomedohost. Se isso funcionar, mas a resolução normal não, o problema está entre sua aplicação e o servidor DNS — interceptação pelo resolvedor do sistema, cache ou roteamento. Se as consultas diretas também falharem, o problema está no próprio servidor DNS ou na conectividade de rede até ele.

Escolhendo seu TLD privado

O incidente com .internal levanta a questão prática: qual TLD usar para serviços internos? Não existe uma resposta universalmente segura, mas algumas opções são melhores que outras.

  • .internal — a RFC 6762 reserva este nome para uso interno, mas o tratamento do mDNS pela Apple no macOS o torna problemático. Pode funcionar bem no Linux.
  • .local — reservado para o mDNS (RFC 6762). Usá-lo para serviços resolvidos por DNS vai conflitar com Bonjour/Avahi. Não use.
  • .corp, .home, .mail — não são reservados. A ICANN pode atribuí-los como TLDs públicos a qualquer momento, o que quebraria sua resolução interna. Não use.
  • Subdomínio de um domínio que você possui. internal.suaempresa.com — esta é a opção mais segura. Você controla o domínio pai, então não há risco de colisão. A desvantagem: é mais longo para digitar.
  • .test, .example, .invalid, .localhost — reservados pela RFC 6761 e garantidamente nunca atribuídos como TLDs públicos. .test é a opção mais limpa para serviços internos que não são de produção.

A resposta chata, mas correta: use um subdomínio de um domínio que você possui. api.internal.suaempresa.com é inequívoco, não colide com nada e funciona corretamente em todos os sistemas operacionais e resolvedores de DNS. É mais longo, mas problemas de DNS às 2 da manhã são piores do que digitar alguns caracteres a mais.

Lições para sistemas em produção

Todo incidente de DNS ensina as mesmas lições, e continuamos reaprendendo-as.

  1. Monitore a resolução de DNS, não apenas os servidores DNS. O servidor DNS estar saudável não significa que a resolução funciona. Monitore o caminho completo: sua aplicação consegue de fato resolver os hostnames de que precisa? Uma verificação sintética que resolve hostnames críticos a cada 30 segundos detecta problemas mais rápido do que o monitoramento do servidor.
  2. Defina TTLs curtos para o DNS interno. Quando você precisa alterar um registro DNS interno, TTLs longos significam dados obsoletos em cache. TTLs de 60 segundos para serviços internos oferecem failover rápido com carga mínima nos resolvedores.
  3. Teste atualizações de SO contra sua configuração de DNS. A quebra do .internal afetou apenas usuários de macOS. Teste seu ambiente de desenvolvimento após grandes atualizações de sistema — mudanças na resolução de DNS raramente aparecem nas notas de lançamento.
  4. Documente sua arquitetura de DNS. Quais servidores DNS cuidam de quais domínios? Onde estão os pontos de split? O que acontece quando a VPN desconecta? Essa documentação é a primeira coisa de que você vai precisar durante uma queda e a última que alguém escreve.
  5. Tenha um plano B. Se a resolução de DNS falhar para um serviço interno, sua aplicação consegue usar um IP fixo? Não é elegante, mas um IP fixo que funciona é melhor do que um nome DNS que não resolve.

O DNS é um desses serviços fundamentais que é invisível quando funciona e catastrófico quando não funciona. A quebra do .internal é um lembrete de que a configuração de DNS é mais frágil do que parece — uma única atualização de SO pode mudar o comportamento de resolução de milhões de usuários. Construa seus sistemas assumindo que o DNS vai quebrar, e você ficará menos surpreso quando isso acontecer.