Linux

DNS recursivo com Unbound para provedor: instalação e DNSSEC

Árvore DNS estilizada em roxo e verde-limão, da raiz ao domínio, ligada ao servidor recursivo

Todo acesso do cliente começa com uma consulta de nome. Antes do vídeo, do jogo ou do aplicativo do banco, alguém precisa transformar o nome em endereço. Quem faz esse trabalho é o DNS recursivo, e no provedor ele pode ser seu ou de terceiros. Este guia monta um DNS recursivo próprio com Unbound no Debian, pronto para atender os clientes da rede, com validação DNSSEC, IPv6 e os ajustes de cache que fazem diferença com milhares de assinantes.

O Unbound é o resolvedor da NLnet Labs. Ele só faz recursão e cache, não hospeda zonas autoritativas, e por isso a configuração fica curta. Os exemplos usam o endereço de serviço 198.51.100.53 e 2001:db8:53::53, clientes em CGNAT na faixa 100.64.0.0/10, um bloco público 203.0.113.0/24 e clientes IPv6 em 2001:db8:100::/40. Troque pelos seus endereços.

Resposta rápida: o mínimo para um DNS recursivo seguro

  1. Instale com apt install unbound. O pacote do Debian já liga a validação DNSSEC e o unbound-control.
  2. Escute só nos endereços de serviço, com uma linha interface: para cada um.
  3. Recuse todo mundo com access-control: 0.0.0.0/0 refuse e libere apenas os blocos dos clientes. Resolvedor aberto vira arma de ataque por amplificação.
  4. Ajuste threads e cache ao tamanho do servidor e ligue prefetch.
  5. Teste com dig +dnssec: a flag ad na resposta prova que a validação funciona.

Por que ter um DNS recursivo próprio no provedor

Muito provedor pequeno entrega aos clientes o resolvedor público de uma grande empresa e esquece o assunto. Funciona, mas cada consulta sai da rede, cruza o trânsito e volta. Com um DNS recursivo local, a resposta mais pedida (os domínios das plataformas de vídeo, das redes sociais e das lojas de aplicativos) já está em cache e volta em um ou dois milissegundos.

Há também o efeito sobre as CDNs. O servidor autoritativo de uma CDN decide qual nó entregar olhando o endereço de quem perguntou, que é o resolvedor. Com o recursivo dentro da sua rede, a resposta tende a apontar para o cache mais próximo de você, inclusive os que ficam no IX ou dentro do próprio provedor.

PontoDNS recursivo próprioResolvedor público
LatênciaConsulta respondida dentro da sua rede, em poucos milissegundos quando está em cacheConsulta atravessa o trânsito até o resolvedor público
CDN e cachesO autoritativo da CDN enxerga o seu endereço de saída e indica o nó mais perto da sua redeA CDN pode indicar um nó que não é o melhor para o cliente
ControleVocê vê os logs, mede o volume e aplica bloqueios exigidos por ordem judicialNenhuma visibilidade nem controle
DependênciaFunciona mesmo com o trânsito instável, para tudo que já está em cacheSe o caminho até o resolvedor cair, o cliente fica sem nome nenhum
CustoUm servidor, monitoramento e atualizaçãoNenhum custo direto

O argumento contra é operacional: o servidor passa a ser seu problema. Se ele travar, todos os clientes ficam sem internet, mesmo com a rota funcionando. Por isso o mínimo são dois servidores em máquinas diferentes, entregues aos clientes como primário e secundário pelo PPPoE, pelo DHCP ou pelo RA do IPv6.

Como o DNS recursivo resolve um nome

O cliente faz uma única pergunta, com a flag RD (recursão desejada), e espera a resposta pronta. O recursivo faz o resto. Sem nada em cache, ele pergunta à raiz quem cuida do .br, pergunta aos servidores do .br quem cuida do domínio e, por fim, pergunta ao servidor autoritativo do domínio pelo registro pedido.

Diagrama: cliente pergunta ao recursivo, que consulta raiz, TLD .br e servidor autoritativo
Uma pergunta do cliente vira até três perguntas do recursivo. Com o cache cheio, quase todas as respostas saem direto do passo 1 para o passo 6.

Cada resposta guardada vale pelo TTL definido pelo dono do domínio. Os servidores do .br e da raiz quase nunca precisam ser consultados de novo, porque esses registros têm TTL longo. Na prática, a maior parte do trabalho é a última etapa e a validação das assinaturas.

Com DNSSEC, cada nível assina os próprios registros e publica a impressão da chave do nível de baixo (o registro DS). O recursivo parte de uma chave da raiz em que confia, a âncora de confiança, e confere a cadeia até o domínio. Se uma assinatura não fecha, a resposta é tratada como falsa e o cliente recebe SERVFAIL.

Instalar o Unbound no Debian

Use uma máquina dedicada ou uma VM com dois núcleos e 2 GB de RAM para começar. O pacote dnsutils traz o dig, que vamos usar nos testes.

apt update
apt install unbound dnsutils

O serviço sobe sozinho escutando só em localhost. Antes de mexer, veja o que o pacote do Debian já deixou pronto:

ls /etc/unbound/unbound.conf.d/
remote-control.conf  root-auto-trust-anchor-file.conf

O unbound.conf principal só inclui os arquivos de unbound.conf.d. O remote-control.conf habilita o unbound-control por um socket local, sem precisar gerar certificados. O outro arquivo é o que mais interessa:

server:
    # The following line will configure unbound to perform cryptographic
    # DNSSEC validation using the root trust anchor.
    auto-trust-anchor-file: "/var/lib/unbound/root.key"

Ou seja, a validação DNSSEC já vem ligada. Na partida do serviço, um script do pacote copia a chave da raiz para /var/lib/unbound/root.key, e o Unbound mantém esse arquivo atualizado sozinho, seguindo a RFC 5011 quando a raiz troca de chave.

A chave vem do pacote dns-root-data, que o apt instala junto por ser recomendado. Se a instalação foi feita sem os pacotes recomendados e o root.key não existir, crie o arquivo com sudo -u unbound unbound-anchor -a /var/lib/unbound/root.key antes de reiniciar o serviço.

Não repita o auto-trust-anchor-file. Muitos tutoriais mandam colocar essa linha no arquivo de configuração. No Debian ela já existe em outro arquivo, e a âncora declarada duas vezes faz o unbound-checkconf acusar erro e o serviço não subir.

Configuração do DNS recursivo para os clientes

Crie o arquivo /etc/unbound/unbound.conf.d/provedor.conf com o conteúdo abaixo. Tudo fica dentro de server:, com quatro espaços de recuo.

server:
    interface: 127.0.0.1
    interface: ::1
    interface: 198.51.100.53
    interface: 2001:db8:53::53
    do-ip4: yes
    do-ip6: yes
    do-udp: yes
    do-tcp: yes

    access-control: 0.0.0.0/0 refuse
    access-control: ::/0 refuse
    access-control: 127.0.0.0/8 allow
    access-control: ::1/128 allow
    access-control: 100.64.0.0/10 allow
    access-control: 203.0.113.0/24 allow
    access-control: 2001:db8:100::/40 allow

    num-threads: 2
    so-reuseport: yes
    so-rcvbuf: 4m
    so-sndbuf: 4m
    msg-cache-size: 128m
    rrset-cache-size: 256m

    prefetch: yes
    prefetch-key: yes
    serve-expired: yes
    serve-expired-ttl: 86400

    hide-identity: yes
    hide-version: yes
    qname-minimisation: yes
    harden-dnssec-stripped: yes
    unwanted-reply-threshold: 10000000
    val-log-level: 1

Interfaces: escute nos endereços de serviço

Sem nenhuma linha interface:, o Unbound escuta só em localhost. Daria para usar 0.0.0.0 e ::0, mas num servidor com vários endereços a resposta pode sair por um IP diferente daquele que o cliente consultou, e o cliente descarta. Listar cada endereço de serviço evita esse problema. Endereço novo exige restart, porque o reload não reabre os sockets.

Access-control: o recursivo não pode ser aberto

As duas primeiras regras recusam qualquer origem. As seguintes liberam localhost e os blocos dos clientes. Vale a regra do prefixo mais específico, então a ordem não muda o resultado, mas deixar o refuse no topo deixa a intenção clara para quem ler depois.

A ação refuse devolve REFUSED; deny simplesmente descarta. Para clientes que configuraram o seu DNS por engano, o REFUSED avisa na hora em vez de deixar a consulta esperando o timeout. Lembre de incluir todos os blocos: o pool do CGNAT, os IPs públicos fixos dos clientes corporativos e os prefixos IPv6 entregues por DHCPv6-PD ou SLAAC.

Desempenho: threads, buffers e cache

  • num-threads: um por núcleo de CPU. Os parâmetros *-slabs ficam no automático, que escolhe uma potência de 2 próxima do número de threads.
  • so-reuseport: abre um socket por thread no Linux e distribui melhor as consultas UDP. Já é o padrão; fica explícito para documentar a escolha.
  • so-rcvbuf e so-sndbuf: buffers maiores seguram picos de consultas sem perder pacotes. O kernel limita o tamanho, por isso o sysctl logo abaixo.
  • msg-cache-size e rrset-cache-size: a documentação recomenda o cache de RRsets com cerca do dobro do cache de mensagens. Por causa da sobra de alocação, o processo chega a usar de duas a duas vezes e meia a soma dos dois. Com 128 MB e 256 MB, conte com cerca de 1 GB de RAM para o Unbound; numa máquina com 4 GB, dá para dobrar os dois valores.
cat > /etc/sysctl.d/90-unbound.conf <<'EOF'
net.core.rmem_max = 8388608
net.core.wmem_max = 8388608
EOF
sysctl --system

Prefetch e respostas vencidas

Com prefetch: yes, quando um registro popular é consultado nos últimos 10% do TTL, o Unbound busca a versão nova antes de vencer. O custo é cerca de 10% a mais de tráfego, e o ganho é que os nomes mais pedidos nunca saem do cache. O prefetch-key busca as chaves DNSKEY assim que encontra o registro DS, em vez de esperar a etapa de validação, o que reduz a latência da primeira consulta a um domínio assinado.

O serve-expired responde com o dado vencido quando a resolução falha ou demora, por até serve-expired-ttl segundos (um dia, no exemplo, valor sugerido pela RFC 8767). Se o autoritativo de um site cair, quem já tinha o nome em cache continua chegando ao endereço antigo.

Privacidade e proteção

  • hide-identity e hide-version: recusam as consultas que revelam o nome do servidor e a versão do Unbound.
  • qname-minimisation: o recursivo manda para a raiz e para o TLD só a parte do nome que cada um precisa ver. Já é o padrão; deixá-lo explícito documenta a escolha.
  • harden-dnssec-stripped: se a zona deveria ser assinada e a assinatura sumiu no caminho, a resposta é tratada como falsa.
  • unwanted-reply-threshold: conta respostas que ninguém pediu, sinal de tentativa de envenenamento. Ao passar do limite, o cache é limpo e um aviso vai para o log. O valor de 10 milhões é o sugerido pela documentação.
  • val-log-level: 1: registra no log cada consulta que falhou na validação DNSSEC.
  • ip-ratelimit: limita as consultas por segundo de cada endereço de origem (padrão 0, desligado). Ajuda contra cliente infectado que dispara consultas, mas cuidado com clientes corporativos que saem por um único IP público: comece com valor alto e acompanhe o log antes de apertar.

Validar e aplicar a configuração

Nunca reinicie o serviço sem conferir a sintaxe. Num DNS recursivo que atende a rede inteira, um erro de digitação derruba a navegação de todos.

unbound-checkconf
unbound-checkconf -o auto-trust-anchor-file
ls -l /var/lib/unbound/root.key
systemctl restart unbound
systemctl status unbound --no-pager
ss -lntup 'sport = :53'

O primeiro comando valida a configuração inteira, incluindo os arquivos do pacote. O segundo mostra o valor efetivo da âncora de confiança, e o ls confirma que o arquivo existe. Depois do restart, o ss deve listar o Unbound escutando na porta 53, em UDP e TCP, em cada endereço de serviço. Saída esperada dos dois primeiros:

unbound-checkconf: no errors in /etc/unbound/unbound.conf
/var/lib/unbound/root.key

DNSSEC e IPv6 no DNS recursivo

Como o DNSSEC aparece para o cliente

O cliente comum não valida nada: ele confia no recursivo. Quando a validação dá certo, o Unbound liga a flag ad (dados autenticados) na resposta. Quando falha, devolve SERVFAIL, e o site simplesmente não abre. Isso protege contra resposta forjada, mas também quer dizer que um erro de assinatura do dono do domínio vira chamado no seu suporte.

Antes de desligar a validação para “resolver” um site que não abre, confira com a flag +cd do dig, que pede a resposta sem validar. Se com +cd o nome resolve e sem ela dá SERVFAIL, o problema é a assinatura do domínio, e o certo é avisar o responsável por ele.

IPv6 nos dois sentidos

No DNS recursivo, o IPv6 aparece em dois lugares. Do lado do cliente, o recursivo escuta em 2001:db8:53::53 e libera o prefixo dos assinantes no access-control. Do lado da internet, com do-ip6: yes, o Unbound também consulta os autoritativos por IPv6.

Se o servidor tem endereço IPv6 mas não tem rota IPv6 para fora, as consultas por IPv6 vão esperar timeout antes de cair para o IPv4, e a resolução fica lenta sem erro aparente. Confirme que o servidor alcança a internet em IPv6 antes de ligar a opção. Se precisar de uma revisão, veja o que é IPv6 e como ele funciona.

Testes com dig: flag ad, SERVFAIL e REFUSED

Rode os testes de uma máquina que está num bloco liberado, por exemplo um roteador de cliente de laboratório.

dig @198.51.100.53 registro.br A +dnssec
dig @2001:db8:53::53 registro.br AAAA
dig @198.51.100.53 dnssec-failed.org A
dig @198.51.100.53 dnssec-failed.org A +cd

Linha a linha:

  • A primeira consulta pede um domínio assinado com DNSSEC. A resposta precisa trazer a flag ad.
  • A segunda faz a mesma pergunta pelo endereço IPv6 do serviço, pedindo o registro AAAA.
  • O dnssec-failed.org é um domínio de teste mantido com a assinatura quebrada de propósito. Um recursivo que valida precisa devolver SERVFAIL.
  • A última repete a consulta com +cd. Agora o nome resolve, o que prova que o SERVFAIL anterior veio da validação, e não de falha de rede.

Cabeçalho esperado no primeiro teste:

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 21877
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

E no teste do domínio com assinatura quebrada:

;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 40112
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

Falta o teste mais importante para a segurança: consultar a partir de um endereço que não está liberado, como uma VPS fora da sua rede. A resposta precisa ser REFUSED. Se vier a resposta normal, o seu DNS recursivo está aberto para a internet.

;; ->>HEADER<<- opcode: QUERY, status: REFUSED, id: 5310
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

Operação no dia a dia

unbound-control status
unbound-control stats_noreset | grep total.num
unbound-control flush_zone exemplo.com.br
journalctl -u unbound --since "1 hour ago"
  • unbound-control status mostra versão, threads, módulos (validator e iterator) e há quanto tempo o processo está no ar.
  • stats_noreset lê os contadores sem zerá-los. O total.num.queries e o total.num.cachehits dão a taxa de acerto do cache. Use a variante sem reset quando outra ferramenta, como o Zabbix, também coleta esses números.
  • flush_zone apaga do cache tudo que está abaixo de um domínio. Útil quando um cliente mudou o apontamento do site e não quer esperar o TTL.
  • O journalctl mostra os erros de validação registrados pelo val-log-level.

Para entregar o DNS recursivo aos clientes, coloque os dois servidores no profile do concentrador. No Mikrotik é o campo dns-server do profile PPP, como mostrado no guia de PPPoE server no Mikrotik RouterOS v7. Em redes com o que é CGNAT, o DNS local tem uma vantagem extra: a consulta não passa pelo NAT, o que economiza portas da faixa de cada cliente.

Erros comuns ao montar o DNS recursivo

  • Resolvedor aberto. Um access-control: 0.0.0.0/0 allow esquecido de um teste transforma o servidor em refletor de ataques DDoS. Faça o teste de fora da rede depois de qualquer mudança.
  • Âncora de confiança duplicada. Copiar o auto-trust-anchor-file de um tutorial genérico para dentro do arquivo do provedor quebra a configuração no Debian.
  • Relógio errado. As assinaturas DNSSEC têm data de início e de fim. Um servidor com a hora errada recusa respostas válidas e tudo dá SERVFAIL. Mantenha o NTP funcionando.
  • Bloco de cliente faltando. Pool novo do CGNAT ou prefixo IPv6 novo sem a linha correspondente no access-control gera chamados de “internet sem DNS” só para uma parte dos clientes.
  • Um servidor só. Recursivo único é ponto único de falha. Dois servidores, de preferência em racks ou POPs diferentes.
  • Firewall barrando TCP 53. Respostas grandes, comuns com DNSSEC, caem para TCP. Libere UDP e TCP na porta 53 para os clientes.

Perguntas frequentes

Qual a diferença entre DNS recursivo e DNS autoritativo?

O autoritativo guarda as zonas e responde só pelos domínios que hospeda. O recursivo não hospeda nada: ele busca a resposta nos autoritativos, valida e guarda em cache para os clientes. O Unbound faz só o papel de recursivo.

Quanto de hardware o Unbound precisa?

Pouco. Um DNS recursivo com Unbound numa VM com dois núcleos e 2 GB de RAM atende com folga um provedor de alguns milhares de clientes. Ajuste o num-threads ao número de núcleos e o cache à memória disponível, e acompanhe a taxa de acerto do cache para saber se vale crescer.

Por que o site abre no resolvedor público e não no meu?

A causa mais comum é DNSSEC quebrado no domínio. Alguns resolvedores públicos criam exceções temporárias para domínios conhecidos com assinatura errada, e o seu servidor não tem essas exceções. Teste com dig +cd: se resolve com a flag e dá SERVFAIL sem ela, a assinatura do domínio está errada.

Devo usar forward para um resolvedor público?

Para um provedor, não costuma valer a pena. O forward devolve a dependência externa e faz as CDNs enxergarem o endereço do resolvedor público, e não o seu. Recursão completa é o que dá o ganho de latência e de localização de cache.

Preciso abrir a porta 53 para a internet?

Não. A porta 53 do recursivo só precisa receber consultas dos clientes. As respostas dos autoritativos chegam em portas altas aleatórias, como retorno das conexões que o próprio servidor abriu. Num firewall com estado, basta permitir o tráfego de saída e o de retorno.

Conclusão

Um DNS recursivo próprio com Unbound cabe em poucas linhas no Debian: escutar nos endereços certos, recusar quem não é cliente, dimensionar o cache e deixar a validação DNSSEC que o pacote já traz ligada. O resultado é menos latência, CDNs entregando conteúdo de mais perto e controle sobre um serviço do qual todos os clientes dependem.

Monte dois servidores, teste de fora da rede para garantir que não estão abertos e acompanhe os contadores do unbound-control. Com isso o recursivo deixa de ser uma dependência externa e passa a ser parte da sua rede.

Leitura recomendada: Servidor DNS recursivo com IPv6 e DNSSEC e Porque usar um DNS local, na wiki do Brasil Peering Forum (CC BY-NC 4.0).

Compartilhar:

Sobre o autor

Ivan Alves

Especialista em redes de provedores (ISP)

Ivan Alves trabalha há mais de 15 anos com redes de provedores de internet, do NOC ao backbone e à borda BGP. Coordena infraestrutura e tecnologia em um provedor regional e escreve aqui os tutoriais que gostaria de ter encontrado quando começou: comandos testados, cenário explicado e o porquê de cada linha.

1 Comentário

  1. DNS anycast com BGP e FRR: recursivo resiliente em dois nós – IA Tecnologia Responder

    […] o anúncio quando o Unbound para. A instalação e o ajuste do recursivo em si estão no post sobre DNS recursivo com Unbound para provedor. Os endereços e ASNs são de […]

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *