Seu notebook está na VPN, dig service.internal.example responde com um endereço 10.x e o curl ainda termina com Could not resolve host. O túnel não é o problema: ele transportou a consulta do dig sem reclamar. O que muda é quem faz a pergunta. O dig envia uma consulta a um servidor que você indica, enquanto o curl passa pela cadeia de resolução do sistema operacional, e essa cadeia tem regras próprias sobre qual servidor é consultado.

Duas resoluções para o mesmo nome

O dig é um stub resolver próprio. Ele lê /etc/resolv.conf, escolhe um servidor de nomes, envia uma única consulta A ou AAAA e imprime a resposta. Ele ignora o nsswitch por completo e não sabe nada do estado por link que o systemd-resolved ou o NetworkManager mantêm fora desse arquivo, e é por isso que uma resposta do dig pode estar correta e mesmo assim não dizer nada sobre o que sua aplicação verá.

As aplicações chamam getaddrinfo, e getaddrinfo percorre uma cadeia mais longa: a ordem dos módulos do nsswitch, depois o módulo que trata o nome e então o resolver montado a partir da configuração de link atual. Em uma máquina com systemd a consulta vai para 127.0.0.53 e o systemd-resolved escolhe um servidor upstream por link com base no domínio de roteamento ligado à interface tun.

Dois comandos separam essas camadas sem adivinhar:

getent ahosts service.internal.example
resolvectl query service.internal.example

O getent usa o mesmo caminho do curl, então uma falha do getent ao lado de um dig que funciona localiza o defeito na política de resolução, não no roteamento de pacotes. O resolvectl query também imprime a interface e o upstream que forneceu a resposta, o que mostra se o link do túnel ou o link físico venceu a decisão.

Leia o resolver que a aplicação realmente usa

/etc/resolv.conf é gerado na maioria dos desktops, e um cliente VPN tem três maneiras de interagir com ele: acrescentar um servidor de nomes no início, sobrescrever o arquivo ou entregar seus servidores ao NetworkManager e deixar o daemon reescrevê-lo. Só o terceiro padrão preserva o DNS por link, porque os servidores continuam ligados a uma interface em vez de serem achatados em uma lista global.

Em sistemas NetworkManager o resultado depende do backend em /etc/NetworkManager/NetworkManager.conf:

[main]
dns=systemd-resolved

Com dns=default os servidores do cliente são fundidos no resolv.conf na ordem que vencer, e uma consulta privada ainda pode ser enviada ao resolver público. Com um backend que entende de links, systemd-resolved ou dnsmasq, os servidores do túnel ficam restritos ao túnel e só os nomes que correspondem ao seu domínio de roteamento vão para lá. Essa restrição é o que significa split DNS na prática, e é a peça que mais costuma faltar quando um cliente afirma suportá-lo.

Leia o estado antes de editar qualquer coisa:

resolvectl status
resolvectl dns tun0

Você quer ver a interface tun listada com um servidor DNS e um domínio de roteamento para o sufixo privado, exibido como ~internal.example. Nenhum servidor no link significa que o cliente não enviou nada. Um servidor sem domínio significa que as consultas vão todas para lá ou nenhuma, dependendo do cliente, e nenhuma das duas coisas é split DNS.

Onde o nsswitch encerra a resolução cedo demais

Uma linha padrão de desktop se parece com isto:

hosts: files mdns4_minimal [NOTFOUND=return] resolve [!UNAVAIL=return] dns myhostname

mdns4_minimal cuida do DNS multicast e reivindica todo nome que termina em .local. Um serviço Kubernetes como api.infra.svc.cluster.local também termina em .local. Quando o módulo mDNS relata NOTFOUND, a ação [NOTFOUND=return] encerra toda a resolução em vez de continuar para o módulo dns, então o nome nunca é enviado ao resolver da VPN. O dig contorna o arquivo inteiro, e é exatamente por isso que as duas ferramentas discordam.

Esse é o contraste mais nítido deste problema, e ele se resume a uma palavra em um arquivo de configuração mais antigo que sua VPN. Mudar a ação para [NOTFOUND=continue] mantém o mDNS para impressoras e dispositivos locais enquanto deixa o DNS ver o nome. Substituir a linha por hosts: files dns também funciona e é mais grosseiro: elimina a resolução .local da impressora que você realmente usa.

Nomes que vivem em exatamente uma rede

Zonas privadas são autoritativas em um único lugar. Um nome da AWS como ip-10-0-4-31.eu-west-1.compute.internal é respondido pelo resolver da VPC daquela região, e só enquanto o endpoint da VPN estiver na mesma região do recurso. Conecte-se a um endpoint de Frankfurt, consulte um nome compute.internal da Irlanda e nenhum ajuste local vai ajudar: a zona que guarda o registro não é alcançável a partir dali.

Os domínios de busca produzem a imagem espelhada. Um service puro é completado com o sufixo que o resolver achar aplicável, e com um link de VPN o domínio local pode vencer o corporativo. Consulte com um ponto final para eliminar o palpite, getent ahosts service.internal.example., e se isso funcionar enquanto o nome curto falha, a correção é o domínio de busca no túnel, não o endereço do servidor.

Clientes gerenciados acrescentam uma terceira camada acima do resolver do sistema. Um perfil de VPN do Windows pode trazer sua própria política de resolução de nomes, regras por aplicativo e uma tabela NRPT que se aplica mesmo com o túnel desligado. Aplicações com cache de DNS próprio, comuns em runtimes .NET e Java, mantêm uma falha antiga muito depois de a cadeia ser corrigida. Clientes da Apple configuram o split DNS por meio de domínios de correspondência nas configurações de DNS em vez do resolv.conf, e Chromium ou Firefox em modo DNS seguro podem ignorar o resolver do sistema para nomes públicos. A referência da Microsoft sobre resolução de nomes de VPN descreve o lado Windows dessa camada de política.

Decidir qual camada corrigir

Vá do sintoma para a camada em vez de tentar correções em sequência:

SymptomWhat it meansCheck first
dig answers, getent failslookup chain, not the packet pathnsswitch line and resolvectl status
Timeout rather than NXDOMAINprivate resolver unreachable through the tunnelresolvectl dns tun0, route to that address
NXDOMAINan authority answered and does not know the namezone owner, endpoint region
FQDN works, short name failssearch suffix mismatchresolvectl domain on the tun link
getent works, app failsapp cache or its own resolverrestart the app, check secure DNS

Duas linhas carregam quase todo o peso. Um timeout é um problema de alcançabilidade: o resolver privado não responde pelo túnel, então verifique a rota até o endereço dele e se o servidor DNS no link é o que você pensa. NXDOMAIN é um problema de autoridade: algo respondeu e não conhece o nome, o que aponta para a zona, para a região ou para um resolver que nunca deveria ter recebido a consulta.

A última linha é a que as pessoas deixam passar porque as duas metades parecem sucesso. Um nome curto que resolve de forma diferente do FQDN é um descompasso de sufixo, e reconectar o túnel não mudará qual sufixo o cliente envia.

Capture o estado antes de editar um arquivo de configuração, para poder dizer se a edição fez algo:

resolvectl status > before.txt
getent ahosts service.internal.example >> before.txt

Execute as verificações nesta ordem e pare na primeira que falhar. getent e resolvectl query devem concordar; se o getent falha enquanto o dig responde, fique na cadeia de resolução e não mexa no roteamento. resolvectl status deve mostrar um servidor DNS e um domínio de roteamento na interface tun. O nsswitch não pode retornar cedo em NOTFOUND para o sufixo que você está testando. O nome deve ser autoritativo na rede à qual seu endpoint está ligado, testado com um ponto final. A aplicação não pode manter cache próprio nem uma sobreposição de DNS seguro.

Corrija só a primeira camada que falha e então rode os mesmos comandos de novo. Duas mudanças ao mesmo tempo deixam você sem saber qual importou, e a próxima falha começa a investigação do zero.

Artigos relacionados