Rodando servidor proxy-cache DNS com Unbound


Autor: Patrick Brandão
Motivação: ao rodar qualquer software no Linux, a resolução de DNS e feita pela libresolv, que faz a leitura do /etc/host.conf e /etc/resolv.conf para obter o IP do servidor DNS.
Assim, a resolução de nomes requer envio de pacotes para fora do host e aguarda pela resposta, que pode demorar (latência alta) ou não ser respondida por problemas na rede entre o host e o servidor DNS (remoto)
A libresolv não possui suporte a cache, ou seja, se você precisar consultar um domínio (www.google.com) dezenas de vezes em um segundo, todas as vezes ela terá que enviar a pergunta ao servidor DNS para obter a mesma resposta.
Rodando um servidor proxy-cache DNS no host linux você garante que a libresolv envie os pedidos para um software rodando no mesmo host mas que ficará por conta de consultar 1 ou mais servidores, e salvando os resultados obtidos em cache, economizando banda e tempo nas próximas requisições aos mesmos nomes.
O resultado dessa implementação é uma maior velocidade no inicio das conexões do servidor.
OBS:
Você não está criando um servidor recursivo, pare resoluções de nomes para sua rede!
Mas ao final Rudimar Remontti vai explicar como tornar ele recursivo.
Distribuição utilizada:
Debian 11 (Bullseye) 64 bits instalação mínima
Instalando Unbound
# apt update; apt upgrade # apt install unbound
Configurando
A configuração abaixo visa consumir recursos mínimos e atender somente os softwares do próprio host.
# cat > /etc/unbound/unbound.conf.d/root-auto-trust-anchor-file.conf << EOF
server:
auto-trust-anchor-file: "/var/lib/unbound/root.key"
verbosity: 1
statistics-interval: 20
extended-statistics: yes
num-threads: 2
# Caso seja necessário fixar o IP de origem:
#outgoing-interface: x.x.x.x
# Abrir a porta apenas nos endereços loopback (!!segurança!!)
interface: 127.0.0.1
interface: ::1
# Permitir todos os IPs pois abrimos a porta apenas para a loopback
access-control: 127.0.0.1/8 allow
access-control: ::1 allow
outgoing-range: 512
num-queries-per-thread: 128
msg-cache-size: 2m
rrset-cache-size: 1m
msg-cache-slabs: 4
rrset-cache-slabs: 4
cache-max-ttl: 1200
infra-host-ttl: 60
infra-lame-ttl: 60
infra-cache-numhosts: 128
infra-cache-lame-size: 2k
do-ip4: yes
do-ip6: yes
do-udp: yes
do-tcp: yes
do-daemonize: yes
username: "unbound"
directory: "/etc/unbound"
logfile: "/var/log/unbound.log"
use-syslog: yes
pidfile: "/run/unbound.pid"
identity: "Unbound-LocalCache"
version: "1.0"
hide-identity: yes
hide-version: yes
harden-glue: yes
do-not-query-address: 127.0.0.1/8
do-not-query-localhost: yes
module-config: "iterator"
#zone localhost
local-zone: "localhost." static
local-data: "localhost. 10800 IN NS localhost."
local-data: "localhost. 10800 IN SOA localhost. nobody.invalid. 1 3600 1200 604800 10800"
local-data: "localhost. 10800 IN A 127.0.0.1"
local-zone: "127.in-addr.arpa." static
local-data: "127.in-addr.arpa. 10800 IN NS localhost."
local-data: "127.in-addr.arpa. 10800 IN SOA localhost. nobody.invalid. 2 3600 1200 604800 10800"
local-data: "1.0.0.127.in-addr.arpa. 10800 IN PTR localhost."
remote-control:
control-enable: yes
control-interface: 127.0.0.1
control-port: 8953
control-use-cert: "no"
# Operar 100% em modo forward, informe o ip dos servidores DNSs reais:
forward-zone:
name: "."
forward-addr: 8.8.8.8
forward-addr: 8.8.4.4
# Encaminhar dominio especifico para servidor DNS especifico:
forward-zone:
name: "slack.com"
forward-addr: 1.1.1.1
forward-addr: 1.0.0.1
EOF
Acima criamos um forward do domínio slack.com indo para um DNS diferente (1.1.1.1 e 1.0.0.1) do padrão 8.8.8.8 e 8.8.4.4
Reinicie o serviço para carregar as novas configurações
# systemctl restart unbound
Instale o pacote dnsutils para ter ferramentas de testes
# apt install dnsutils
Testando IPv4
# host google.com 127.0.0.1
Using domain server: Name: 127.0.0.1 Address: 127.0.0.1#53 Aliases: google.com has address 142.250.218.78 google.com has IPv6 address 2800:3f0:4001:81d::200e google.com mail is handled by 10 smtp.google.com.
# dig ANY google.com @127.0.0.1
; <<>> DiG 9.16.27-Debian <<>> ANY google.com @127.0.0.1 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 893 ;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 1232 ;; QUESTION SECTION: ;google.com. IN ANY ;; ANSWER SECTION: google.com. 129 IN A 142.250.218.78 google.com. 129 IN AAAA 2800:3f0:4001:81d::200e google.com. 51 IN MX 10 smtp.google.com. ;; Query time: 0 msec ;; SERVER: 127.0.0.1#53(127.0.0.1) ;; WHEN: Wed Jun 01 15:59:35 -03 2022 ;; MSG SIZE rcvd: 104
Testando IPv6
# host google.com ::1
Using domain server: Name: ::1 Address: ::1#53 Aliases: google.com has address 142.250.218.78 google.com has IPv6 address 2800:3f0:4001:81d::200e google.com mail is handled by 10 smtp.google.com.
# dig ANY google.com @::1
; <<>> DiG 9.16.27-Debian <<>> ANY google.com @::1 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56485 ;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 1232 ;; QUESTION SECTION: ;google.com. IN ANY ;; ANSWER SECTION: google.com. 106 IN A 142.250.218.78 google.com. 281 IN AAAA 2800:3f0:4001:81d::200e google.com. 281 IN MX 10 smtp.google.com. ;; Query time: 0 msec ;; SERVER: ::1#53(::1) ;; WHEN: Wed Jun 01 16:03:30 -03 2022 ;; MSG SIZE rcvd: 104
Configurando o Linux para usar o servidor DNS na loopback como servidor DNS
# echo "nameserver 127.0.0.1" > /etc/resolv.conf # echo "nameserver ::1 " >> /etc/resolv.conf
Tornando recursivo
Contribuição extra por: Rudimar Remontti
Caso deseje tornar recursivo para os demais hosts da sua rede este servidor, primeira coisa que você deve ter em mente que se este servidor conter IPs públicos o mesmo será responsivo para todo o planeta terra e alguns "aliGenigenas". Então o mínimo que você deve ter é um firewall, protegendo a porta 53 tcp/udp para responder apenas para sua rede.
# vim /etc/unbound/unbound.conf.d/root-auto-trust-anchor-file.conf
Abaixo de:
# abrir a porta apenas nos enderecos loopback (seguranca)
interface: 127.0.0.1
interface: ::1
Adicione
# abrir a porta para os ips de interface (risco)
interface: 200.200.200.200
interface: 2000:bebe:cafe::f07e
Abaixo de:
# Permitir todos os IPs pois abrimos a porta apenas para a loopback
access-control: 127.0.0.1/8 allow
access-control: ::1 allow
Adicione os prefixos da sua rede
access-control: 192.168.0.0/16 allow
access-control: 172.16.0.0/12 allow
access-control: 100.64.0.0/10 allow
access-control: 10.0.0.0/8 allow
access-control: 200.200.0.0/22 allow
access-control: 2001:db8::/32 allow
Desta forma abrindo conexão para os IPs da interface "200.200.200.200" e "2000:bebe:cafe::f07e"
Reinicie o serviço para carregar as alterações
# systemctl restart unbound
Pode consultar se as porta estão sendo ouvidas:
# ss -putan | grep LISTEN | grep :53
tcp LISTEN 0 256 200.200.200.200:53 0.0.0.0:* users:(("unbound",pid=6079,fd=16))
tcp LISTEN 0 256 127.0.0.1:53 0.0.0.0:* users:(("unbound",pid=6079,fd=12))
tcp LISTEN 0 256 200.200.200.200:53 0.0.0.0:* users:(("unbound",pid=6079,fd=8))
tcp LISTEN 0 256 127.0.0.1:53 0.0.0.0:* users:(("unbound",pid=6079,fd=4))
tcp LISTEN 0 256 [::1]:53 [::]:* users:(("unbound",pid=6079,fd=6))
tcp LISTEN 0 256 [2000:bebe:cafe::f07e]:53 [::]:* users:(("unbound",pid=6079,fd=10))
tcp LISTEN 0 256 [::1]:53 [::]:* users:(("unbound",pid=6079,fd=14))
tcp LISTEN 0 256 [2000:bebe:cafe::f07e]:53 [::]:* users:(("unbound",pid=6079,fd=18))
Firewall
Porém mesmo que você tenha setados seus prefixos em access-control a porta 53 estará respondendo para todo o mundo. Para fechar elas use o nfttables que por padrão já vem no Debian 11 no lugar do iptables. Você pode instalar o mesmo com apt se necessário.
Edite o arquivo do nftables
# vim /etc/nftables.conf
Ajuste para ficar assim e em elements insira todos seus prefixos autorizados.
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
set acesso-dns4 {
flags interval
type ipv4_addr
elements = { 127.0.0.1, 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12, 100.64.0.0/10, 200.200.200.0/22 }
}
set acesso-dns6 {
flags interval
type ipv6_addr
elements = { ::1, 2001:db8::/32 }
}
chain input {
type filter hook input priority 0;
# Permite Acesso DNS na porta 53
ip saddr @acesso-dns4 udp dport 53 counter accept
ip saddr @acesso-dns4 tcp dport 53 counter accept
ip6 saddr @acesso-dns6 udp dport 53 counter accept
ip6 saddr @acesso-dns6 tcp dport 53 counter accept
udp dport 53 counter drop
tcp dport 53 counter drop
type filter hook input priority 0;
}
chain forward {
type filter hook forward priority 0;
}
chain output {
type filter hook output priority 0;
}
}
Habilite o mesmo para iniciar com o boot e reinicie.
# systemctl enable nftables # systemctl restart nftables
Consulte se seu firewall foi carregado com o comando:
# nft list ruleset
Retorno:
table inet filter {
set acesso-dns4 {
type ipv4_addr
flags interval
elements = { 10.0.0.0/8, 100.64.0.0/10,
127.0.0.1, 172.16.0.0/12,
192.168.0.0/16, 200.200.200.0/22 }
}
set acesso-dns6 {
type ipv6_addr
flags interval
elements = { ::1,
2001:db8::/32 }
}
chain input {
type filter hook input priority filter; policy accept;
ip saddr @acesso-dns4 udp dport 53 counter packets 0 bytes 0 accept
ip saddr @acesso-dns4 tcp dport 53 counter packets 0 bytes 0 accept
ip6 saddr @acesso-dns6 udp dport 53 counter packets 0 bytes 0 accept
ip6 saddr @acesso-dns6 tcp dport 53 counter packets 0 bytes 0 accept
udp dport 53 counter packets 0 bytes 0 drop
tcp dport 53 counter packets 0 bytes 0 drop
}
chain forward {
type filter hook forward priority filter; policy accept;
}
chain output {
type filter hook output priority filter; policy accept;
}
}
Pronto espero que tenha gostado! Agradeço ao meu parceiro Patrick!
Se quiser fazer uma doação para o café ficarei muito feliz pelo seu reconhecimento!

Se não puder doar pode deixar seu agradecimento nos comentário também ficarei feliz em saber que ajudei. Se tiver qualquer pergunta deixe-a também. Se preferir entrar em Contato clique aqui.
Abraço!




Como faria para bloquear sites no unbound?
material show de bola.
Hola .. Cuando coloco
# abrir a porta para os ips de interface (risco)
interface: 200.200.200.200
interface: 2000:bebe:cafe::f07e
Tengo error al iniciar unbound, que pidria ser
creio que vc não tenha o endereço IP 200.200.200.200 configurado em nenhuma interface de rede
Pq quando dou o comando nft list ruleset no debian 12 ele retorna “comando não encontrado”, e ja no ubuntu 22.04 ele retorna as regras confome no tutorial
tenta “/sbin/nft list rulest” se der certo, precisa corrigir o PATH do seu .bash
systemctl restart unbound
Job for unbound.service failed because the control process exited with error code.
See “systemctl status unbound.service” and “journalctl -xeu unbound.service” for details.
entra no arquivo .conf do unbount e apaga o os linha repetidas no começo
eu ja fiz isso e não resolveu.
alterar no cabeçalho das configurações unbound os nome repetidos tava com es
se erro tambem
olá, em /etc/unbound/ na .conf não tem absolutamente nada repetido, porem não da restart, poderia ser mais claro, obrigado.
creio que deve haver alguma linha que esteja causando o erro , com o comando jounalctl -200 vc pode ver as ultimas 200 linhas e checar se informa algum erro
Fiquei em duvida em relação ao Tamanho do cache, pelo que vi aqui no blog, ficou no padrão
msg-cache-size: 2m
rrset-cache-size: 1m
Mas não seria interessante deixar uma quantidade maior de armazenamento ? 200mb ou 1GB ?
Se alguém puder comentar sobre agradeço.
coloca 100m em cada mais que suficiente
A adição de um DNS autoritativo melhora a latência ou a velocidade da consulta?
Como habilitar o DNSSEC?
Já fiz de tudo e não funciona.
Olá Anderson.
como proxy-cache a performance é melhor, pois alem de fazer cache local vc se aproveita do cache já alimentado nos servidores de DNS apontados no forward. Se você optar pelos hints (servidores raiz) a latência irá aumentar um pouco pois para cada nome a ser resolvido seu DNS local terá que consultar toda a árvore de DNS mundial, com acessos internacionais com latencia acima de 120ms.
Nesse link há explicações desenhadas:
http://manual.slackmini.com.br/#dns-client
Obrigado pela explicação e parabéns pelo tutorial. Já até coloquei em produção.
Patrick,
Entendi a questão do forward e tal.
Qual seria a vantagem em usar o recursivo pelo hints (servidores raiz) ? Ou não tem nenhuma vantagem?
Parabéns pelo material.
pode deixar pelo servidores raiz em vez do forward-zone?
E qual e a vantagem com e sem forward-zone?
Boa pergunta, tbm fiquei curioso
Seria esta resposta, para sua pergunta!
como proxy-cache a performance é melhor, pois alem de fazer cache local vc se aproveita do cache já alimentado nos servidores de DNS apontados no forward. Se você optar pelos hints (servidores raiz) a latência irá aumentar um pouco pois para cada nome a ser resolvido seu DNS local terá que consultar toda a árvore de DNS mundial, com acessos internacionais com latencia acima de 120ms.
Nesse link há explicações desenhadas:
http://manual.slackmini.com.br/#dns-client