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
1 2 |
# 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# 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
1 |
# systemctl restart unbound |
Instale o pacote dnsutils para ter ferramentas de testes
1 |
# apt install dnsutils |
Testando IPv4
1 |
# host google.com 127.0.0.1 |
1 2 3 4 5 6 7 8 |
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. |
1 |
# dig ANY google.com @127.0.0.1 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
; <<>> 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
1 |
# host google.com ::1 |
1 2 3 4 5 6 7 8 |
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. |
1 |
# dig ANY google.com @::1 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
; <<>> 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
1 2 |
# 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.
1 |
# vim /etc/unbound/unbound.conf.d/root-auto-trust-anchor-file.conf |
Abaixo de:
1 2 3 |
# abrir a porta apenas nos enderecos loopback (seguranca) interface: 127.0.0.1 interface: ::1 |
Adicione
1 2 3 |
# abrir a porta para os ips de interface (risco) interface: 200.200.200.200 interface: 2000:bebe:cafe::f07e |
Abaixo de:
1 2 3 |
# 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
1 2 3 4 5 6 |
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
1 |
# systemctl restart unbound |
Pode consultar se as porta estão sendo ouvidas:
1 |
# ss -putan | grep LISTEN | grep :53 |
1 2 3 4 5 6 7 8 |
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
1 |
# vim /etc/nftables.conf |
Ajuste para ficar assim e em elements insira todos seus prefixos autorizados.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#!/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.
1 2 |
# systemctl enable nftables # systemctl restart nftables |
Consulte se seu firewall foi carregado com o comando:
1 |
# nft list ruleset |
Retorno:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
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
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.
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