Mudanças entre as edições de "DNS Recursivo Anycast Hyperlocal"

De Wiki BPF
Ir para: navegação, pesquisa
(22 revisões intermediárias pelo mesmo usuário não estão sendo mostradas)
Linha 1: Linha 1:
 
== Descrição ==
 
== Descrição ==
Um dos recursos extremamente importante para o acesso à Internet é o '''DNS (Domain Name System)''' e sem ele teríamos que decorar milhares de endereços IP para acessar sites e serviços na Internet. Basicamente temos 2 tipos de DNS, o recursivo e o autoritativo. O recursivo é um serviço que utilizamos para fazer consultas aos DNS(es) Autoritativos que são aqueles responsáveis pelas tabelas que associam o host name a um IP e no caso de resolução reversa, o IP ao host name. O exemplo mais comum de DNS reverso é o do Google, os IPs 8.8.8.8, 8.8.4.4, 2001:4860:4860::8888 e 2001:4860:4860::8844. Se você está estranhando os 2 últimos endereços, é porque provavelmente ainda não ouviu falar de IPv6 e isso não é bom. Procure estudar sobre isso e um bom lugar para começar é [http://ipv6.br/pagina/curso-basico-ead aqui]. O serviço de DNS deve ser levado muito a sério pelas empresas que o implementam, porque a sua falha pode literalmente parar a Internet para milhares de pessoas que confiam nele ou até pior, um DNS mal intencionado ou comprometido, pode ser usado para direcionar usuários a acessarem sites falsos. Esse artifício visa coletar as credenciais dos usuários e assim poderem aplicar golpes e outras formas danosas e prejudiciais à vítima. Ter um DNS recursivo é muito bom para o ISP, mas cuidar dele, mantê-lo atualizado e protegido, é mais importante ainda.
+
Um dos recursos extremamente importante para o acesso à Internet é o '''DNS (Domain Name System)''' e sem ele teríamos que decorar milhares de endereços IP para acessar sites e serviços na Internet. Basicamente temos 2 tipos de DNS, o recursivo e o autoritativo. O recursivo é um serviço que utilizamos para fazer consultas aos DNS(es) Autoritativos que são aqueles responsáveis pelas tabelas que associam o host name a um IP e no caso de resolução reversa, o IP ao host name. O exemplo mais comum de DNS recursivo é o do Google, os IPs 8.8.8.8, 8.8.4.4, 2001:4860:4860::8888 e 2001:4860:4860::8844. Se você está estranhando os 2 últimos endereços, é porque provavelmente ainda não ouviu falar de IPv6 e isso não é bom. Procure estudar sobre isso e um bom lugar para começar é [http://ipv6.br/pagina/curso-basico-ead aqui]. O serviço de DNS deve ser levado muito a sério pelas empresas que o implementam, porque a sua falha pode literalmente parar a Internet para milhares de pessoas que confiam nele ou até pior, um DNS mal intencionado ou comprometido, pode ser usado para direcionar usuários a acessarem sites falsos. Esse artifício visa coletar as credenciais dos usuários e assim poderem aplicar golpes e outras formas danosas e prejudiciais à vítima. Ter um DNS recursivo é muito bom para o ISP, mas cuidar dele, mantê-lo atualizado e protegido, é mais importante ainda.
  
Nesse artigo mostrarei a configuração de um '''DNS recursivo anycast''', diferente dos '''DNS recursivos unicast''' comumente encontrados pelos ISPs a fora. No modelo Unicast, normalmente se tem um ou mais servidores de DNS que são consultados e estão fisicamente em um local. O problema é que essa abordagem não poderia ter por exemplo, 5 servidores, e utilizar todos configurados ao mesmo tempo nos sistemas, porque muitos sistemas só aceitam até 3 servidores recursivos em suas configurações e mais que isso são ignorados. Você poderia então utilizar apenas 2 servidores, isso resolveria o problema mas eles precisariam estar em um determinado local. Mas e se lá na frente você resolver abrir seu negócio em uma outra cidade e em outro estado? Nesse caso poderia continuar usando os mesmos servidores mas aumentando um pouco a latência. Mas se acontecesse algo na interconexão desses servidores? Com o uso do DNS Anycast você poderia ter um servidor DNS recursivo em cada cidade e respondendo pelo mesmo IP. Em caso de problemas com qualquer servidor, o outro passaria a responder para todos os seus assinantes. Seria muito bom ter um cara como o "8.8.8.8" do Google, não é mesmo? Além desse recurso, usaremos o '''Hyperlocal''' que é uma técnica que faz uma cópia das tabelas dos DNS Root Servers e mantém localmente no seu servidor recursivo. Isso deixa rápida toda resposta que seria endereçada primeiramente aos DNS(es) Raiz da Internet, principalmente consultas de domínios inválidos ou digitados erradamente.
+
Nesse artigo mostrarei a configuração de um '''DNS recursivo anycast''', diferente dos '''DNS recursivos unicast''' comumente encontrados pelos ISPs a fora. No modelo Unicast, normalmente se tem um ou mais servidores de DNS que são consultados e estão fisicamente em um local. O problema é que essa abordagem não poderia ter por exemplo, 5 servidores, e utilizar todos configurados ao mesmo tempo nos sistemas, porque muitos sistemas só aceitam até 3 servidores recursivos em suas configurações e mais que isso são ignorados. Você poderia então utilizar apenas 2 servidores, isso resolveria o problema mas eles precisariam estar em um determinado local. Mas e se lá na frente você resolver abrir seu negócio em uma outra cidade e em outro estado? Nesse caso poderia continuar usando os mesmos servidores mas aumentando um pouco a latência. Mas se acontecesse algo na interconexão desses servidores? Com o uso do DNS Anycast você poderia ter um servidor DNS recursivo em cada cidade e respondendo pelo mesmo IP. Em caso de problemas com qualquer servidor, o outro passaria a responder para todos os seus assinantes. Além desse recurso, usaremos o '''Hyperlocal''' que é uma técnica que faz uma cópia das tabelas dos DNS Root Servers e mantém localmente no seu servidor recursivo. Isso deixa rápida toda resposta que seria endereçada primeiramente aos DNS(es) Raiz da Internet, principalmente consultas de domínios inválidos ou digitados erradamente.
  
 
== Diagrama ==
 
== Diagrama ==
Para que possamos visualizar nossa configuração, abaixo temos um diagrama hipotético dos nossos servidores e da rede em si:[[Arquivo:Diagrama DNS Anycast2.png|nenhum|miniaturadaimagem|807x807px]]Explicando o cenário: cada servidor DNS fechará uma sessão iBGP com o seu router através dos endereços /30 IPv4 e /64 IPv6 (usando IPs de documentação [https://datatracker.ietf.org/doc/html/rfc3849 RFC3849] e [https://datatracker.ietf.org/doc/html/rfc5737 RFC5737] representando seus IPs públicos). Nessa sessão BGP serão anunciados os IPs privados [https://datatracker.ietf.org/doc/html/rfc1918 RFC1918] e [https://datatracker.ietf.org/doc/html/rfc4193 RFC4193] configurados nas loopbacks que serão: 10.10.10.10 e fc00::10:10:10:10. Divulgando esses IPs privados para os assinantes, você esconde o real IP público dos servidores, evitando que alguém de fora envie ataques para seus servidores DNS.
+
Para que possamos visualizar nossa configuração, abaixo temos um diagrama hipotético dos nossos servidores e da rede em si:
 
+
[[Arquivo:Diagrama dns anycast2.png|nenhum|miniaturadaimagem|807x807px]]
 +
Explicando o cenário: cada servidor DNS fechará uma sessão iBGP com o seu router através dos endereços /30 IPv4 e /64 IPv6 (usando IPs de documentação [https://datatracker.ietf.org/doc/html/rfc3849 RFC3849] e [https://datatracker.ietf.org/doc/html/rfc5737 RFC5737] representando seus IPs públicos). Nessa sessão BGP serão anunciados os IPs privados [https://datatracker.ietf.org/doc/html/rfc1918 RFC1918] e [https://datatracker.ietf.org/doc/html/rfc4193 RFC4193] configurados nas loopbacks que serão: 10.10.10.10 e fc00::10:10:10:10. Divulgando esses IPs privados para os assinantes, você esconde o real IP público dos servidores, evitando que alguém de fora envie ataques para seus servidores DNS.
 
== Servidores utilizados ==
 
== Servidores utilizados ==
 
* VM com 4 cores (Intel(R) Xeon(R) Silver 4214R CPU @ 2.40GHz).
 
* VM com 4 cores (Intel(R) Xeon(R) Silver 4214R CPU @ 2.40GHz).
Linha 84: Linha 85:
  
 
=== Configurando a rede ===
 
=== Configurando a rede ===
'''/etc/network/interfaces:'''<pre>
+
'''/etc/network/interfaces:'''
 +
<pre>
 
# This file describes the network interfaces available on your system
 
# This file describes the network interfaces available on your system
 
# and how to activate them. For more information, see interfaces(5).
 
# and how to activate them. For more information, see interfaces(5).
Linha 121: Linha 123:
 
  frr version 7.5
 
  frr version 7.5
 
  frr defaults traditional
 
  frr defaults traditional
  hostname unbound2
+
  hostname unbound1
 
  log syslog informational
 
  log syslog informational
 
  no ip forwarding
 
  no ip forwarding
Linha 241: Linha 243:
 
         do-tcp: yes
 
         do-tcp: yes
 
         access-control: 203.0.113.0/24 allow
 
         access-control: 203.0.113.0/24 allow
         access-control: 2001:db8:1111:/48 allow
+
         access-control: 2001:db8:1111::/48 allow
 
         chroot: ""
 
         chroot: ""
 
         username: "unbound"
 
         username: "unbound"
Linha 273: Linha 275:
 
  auth-zone:
 
  auth-zone:
 
     name: "."
 
     name: "."
    master: "a.root-servers.net"
 
 
     master: "b.root-servers.net"
 
     master: "b.root-servers.net"
 
     master: "c.root-servers.net"
 
     master: "c.root-servers.net"
    master: "d.root-servers.net"
 
    master: "e.root-servers.net"
 
 
     master: "f.root-servers.net"
 
     master: "f.root-servers.net"
 
     master: "g.root-servers.net"
 
     master: "g.root-servers.net"
    master: "h.root-servers.net"
 
    master: "i.root-servers.net"
 
    master: "j.root-servers.net"
 
 
     master: "k.root-servers.net"
 
     master: "k.root-servers.net"
     master: "l.root-servers.net"
+
     master: "lax.xfr.dns.icann.org"
     master: "m.root-servers.net"
+
     master: "iad.xfr.dns.icann.org"
 
     fallback-enabled: yes
 
     fallback-enabled: yes
 
     for-downstream: no
 
     for-downstream: no
Linha 312: Linha 308:
 
  Libera a consulta DNS para origem desses prefixos, troque pelos prefixos reais do seu ASN:  
 
  Libera a consulta DNS para origem desses prefixos, troque pelos prefixos reais do seu ASN:  
 
         access-control: 203.0.113.0/24 allow  
 
         access-control: 203.0.113.0/24 allow  
         access-control: 2001:db8:1111:/48 allow
+
         access-control: 2001:db8:1111::/48 allow
 
   
 
   
 
  Esse trecho abaixo é referente à configuração do Hyperlocal:
 
  Esse trecho abaixo é referente à configuração do Hyperlocal:
Linha 318: Linha 314:
 
  auth-zone:
 
  auth-zone:
 
     name: "."
 
     name: "."
    master: "a.root-servers.net"
 
 
     master: "b.root-servers.net"
 
     master: "b.root-servers.net"
 
     master: "c.root-servers.net"
 
     master: "c.root-servers.net"
    master: "d.root-servers.net"
 
    master: "e.root-servers.net"
 
 
     master: "f.root-servers.net"
 
     master: "f.root-servers.net"
 
     master: "g.root-servers.net"
 
     master: "g.root-servers.net"
    master: "h.root-servers.net"
 
    master: "i.root-servers.net"
 
    master: "j.root-servers.net"
 
 
     master: "k.root-servers.net"
 
     master: "k.root-servers.net"
     master: "l.root-servers.net"
+
     master: "lax.xfr.dns.icann.org"
     master: "m.root-servers.net"
+
     master: "iad.xfr.dns.icann.org"
 
     fallback-enabled: yes
 
     fallback-enabled: yes
 
     for-downstream: no
 
     for-downstream: no
 
     for-upstream: yes
 
     for-upstream: yes
 
     zonefile: "/var/lib/unbound/root.zone"
 
     zonefile: "/var/lib/unbound/root.zone"
+
 
 
Após a configuração do Unbound basta reiniciar o serviço unbound e verificar se o arquivo '''/var/lib/unbound/root.zone''' foi criado com o conteúdo dos Root Servers.
 
Após a configuração do Unbound basta reiniciar o serviço unbound e verificar se o arquivo '''/var/lib/unbound/root.zone''' foi criado com o conteúdo dos Root Servers.
  
Linha 342: Linha 332:
 
nameserver ::1
 
nameserver ::1
 
options timeout:1 attempts:1
 
options timeout:1 attempts:1
</pre>Feito isso teste se seu servidor está resolvendo os hosts na Internet por exemplo:
+
</pre>
 +
Feito isso teste se seu servidor está resolvendo os hosts na Internet por exemplo:
 
  # host www.uol.com.br 127.0.0.1
 
  # host www.uol.com.br 127.0.0.1
 
  Using domain server:
 
  Using domain server:
Linha 427: Linha 418:
 
  ;; WHEN: qua jun 30 10:10:00 -03 2021
 
  ;; WHEN: qua jun 30 10:10:00 -03 2021
 
  ;; MSG SIZE  rcvd: 153
 
  ;; MSG SIZE  rcvd: 153
 +
 +
Vamos testar se nosso Hyperlocal está funcionando? Vamos fazer uma consulta de um host com nome absurdo e que não existe na Internet, sem o Hyperlocal habilitado:
 +
# dig @127.0.0.1 wws.sssss.ssss
 +
 +
; <<>> DiG 9.16.15-Debian <<>> @127.0.0.1 wws.sssss.ssss
 +
; (1 server found)
 +
;; global options: +cmd
 +
;; Got answer:
 +
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 51541
 +
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
 +
 +
;; OPT PSEUDOSECTION:
 +
; EDNS: version: 0, flags:; udp: 1232
 +
;; QUESTION SECTION:
 +
;wws.sssss.ssss.                        IN      A
 +
 +
;; AUTHORITY SECTION:
 +
.                      3600    IN      SOA    a.root-servers.net. nstld.verisign-grs.com. 2021063000 1800 900 604800 86400
 +
 +
;; Query time: 312 msec
 +
;; SERVER: 127.0.0.1#53(127.0.0.1)
 +
;; WHEN: qua jun 30 10:49:24 -03 2021
 +
;; MSG SIZE  rcvd: 118
 +
 +
Repare que a resposta do Root Server levou 312 msec. Agora vamos fazer a mesma consulta com o Hyperlocal habilitado e unbound reiniciado:
 +
# dig @127.0.0.1 wws.sssss.ssss
 +
 +
; <<>> DiG 9.16.15-Debian <<>> @127.0.0.1 wws.sssss.ssss
 +
; (1 server found)
 +
;; global options: +cmd
 +
;; Got answer:
 +
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 48429
 +
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
 +
 +
;; OPT PSEUDOSECTION:
 +
; EDNS: version: 0, flags:; udp: 1232
 +
;; QUESTION SECTION:
 +
;wws.sssss.ssss.                        IN      A
 +
 +
;; AUTHORITY SECTION:
 +
.                      86397  IN      SOA    a.root-servers.net. nstld.verisign-grs.com. 2021063000 1800 900 604800 86400
 +
 +
;; Query time: 0 msec
 +
;; SERVER: 127.0.0.1#53(127.0.0.1)
 +
;; WHEN: qua jun 30 10:52:21 -03 2021
 +
;; MSG SIZE  rcvd: 118
 +
Com as tabelas locais, a mesma consulta levou 0 msec. Muito bom não é mesmo?
 +
 +
Próximo passo é configurar os IPs '''10.10.10.10''' e '''fc00::10:10:10:10''' em algum dispositivo ou estação da rede e testar se está funcionando a resolução de nomes. Se chegamos até aqui com tudo funcionando então perfeito.
 +
 +
Vamos configurar agora um script que vai checar se o nosso DNS parou de resolver nomes e se isso ocorrer, ele deixará de anunciar os IPs de DNS para o router. Nesse caso o outro DNS continuará respondendo com os mesmos IPs.
 +
 +
=== Script do Servidor 1 ===
 +
'''/root/teste_dns.sh'''
 +
#!/usr/bin/env bash
 +
<nowiki>#</nowiki>Script para teste de DNS v1.2
 +
<nowiki>#</nowiki>-----------------------------------------------------------------------
 +
<nowiki>#</nowiki>Informe um domínio por linha:
 +
dominios_testar=(
 +
www.google.com
 +
www.terra.com.br
 +
www.uol.com.br
 +
www.globo.com
 +
www.facebook.com
 +
www.youtube.com
 +
www.twitch.com
 +
www.discord.com
 +
www.debian.org
 +
www.redhat.com
 +
)
 +
corte_taxa_falha=100 #Porcentagem de falha para executar uma ação
 +
<nowiki>#</nowiki>-----------------------------------------------------------------------
 +
qt_falhas=0
 +
qt_total="${#dominios_testar[@]}"
 +
echo "total_dominios: $qt_total"
 +
for site in "${dominios_testar[@]}"
 +
do
 +
<nowiki> </nowiki> resp=<nowiki>''</nowiki>
 +
<nowiki> </nowiki> resolver="127.0.0.1"
 +
<nowiki> </nowiki> echo " - dominio $site - $resolver"
 +
<nowiki> </nowiki> resp=$( host $site $resolver | grep "connection timed out" )
 +
<nowiki> </nowiki> if [ ! -z "$resp" ]; then
 +
<nowiki> </nowiki>    ((qt_falhas++))
 +
<nowiki> </nowiki>    echo "[$resp]"
 +
<nowiki> </nowiki> fi
 +
done
 +
 +
taxa_falha=$((qt_falhas*100/qt_total))
 +
echo "Falhas $qt_falhas/$qt_total ($taxa_falha%)"
 +
 +
if [ "$taxa_falha" -ge "$corte_taxa_falha" ]; then
 +
<nowiki> </nowiki>  habilitado="`vtysh -c 'show run' | grep \"neighbor 192.0.2.1 prefix-list BLOQUEIA-TUDO out\"`"
 +
<nowiki> </nowiki>  if [ "$habilitado" == "" ]; then
 +
<nowiki> </nowiki>    vtysh -c 'conf t' -c 'router bgp 65000' -c 'address-family ipv4 unicast' -c 'no neighbor 192.0.2.1 prefix-list RECURSIVO out' -c 'neighbor 192.0.2.1 prefix-list BLOQUEIA-TUDO out' -c 'end' -c 'wr'
 +
<nowiki> </nowiki>    vtysh -c 'conf t' -c 'router bgp 65000' -c 'address-family ipv6 unicast' -c 'no neighbor 2001:db8::192:0:2:1 prefix-list RECURSIVO_V6 out' -c 'neighbor 2001:db8::192:0:2:1 prefix-list BLOQUEIA-TUDO out' -c 'end' -c 'wr'
 +
<nowiki> </nowiki>    echo "caiu: `date`" >> /root/dnsreport.log
 +
<nowiki> </nowiki>  fi
 +
<nowiki> </nowiki>  exit
 +
fi
 +
 +
habilitado="`vtysh -c 'show run' | grep \"neighbor 192.0.2.1 prefix-list RECURSIVO out\"`"
 +
if [ "$habilitado" == "" ]; then
 +
<nowiki> </nowiki>  vtysh -c 'conf t' -c 'router bgp 65000' -c 'address-family ipv4 unicast' -c 'no neighbor 192.0.2.1 prefix-list BLOQUEIA-TUDO out' -c 'neighbor 192.0.2.1 prefix-list RECURSIVO out' -c 'end' -c 'wr'
 +
<nowiki> </nowiki>  vtysh -c 'conf t' -c 'router bgp 65000' -c 'address-family ipv6 unicast' -c 'no neighbor 2001:db8::192:0:2:1 prefix-list BLOQUEIA-TUDO out' -c 'neighbor 2001:db8::192:0:2:1 prefix-list RECURSIVO_V6 out' -c 'end' -c 'wr'
 +
<nowiki> </nowiki>  echo "voltou: `date`" >> /root/dnsreport.log
 +
fi
 +
 +
Sim. Para entender o que está escrito acima você precisa conhecer um pouco de linguagem de shell script em bash. Fique à vontade em melhorar ou até mesmo criar seu próprio script em outra linguagem. O conceito é bem simples e usado apenas para testar se nosso DNS está resolvendo pra fora. Porque você pode não estar conseguindo, por algum motivo, consultar na Internet pelas portas '''53/udp''' e/ou '''53/tcp''' e que poderia ser causado por algum bloqueio ou problema de fato na rede. Caso is aconteça usaremos os comandos '''vtysh''' via shell, para alterar a nossa configuração no FRR e bloquear os anúncios. Uma outra coisa que fica como dever de casa: no script ele gera um relatório de quando tem problema no DNS e quando volta a funcionar. Você pode pesquisar e utilizar os pacotes do Debian '''msmtp''' e '''msmtp-mta''', configurar ele e o script para enviar um e-mail em caso de problemas. Como não sou mau, você pode achar informação sobre isso, nos slides de uma palestra que apresentei no '''[https://www.youtube.com/watch?v=Wz2IAg6MMlU FiqueEmCasaUseDebian]''' bem [https://debianbrasil.gitlab.io/FiqueEmCasaUseDebian/arquivos/2020-05-29-sysadmin-apps-ferramentas-uteis-para-sysadmins.pdf aqui].
 +
 +
Vamos agora colocar o script para rodar no cron adicionando a seguinte linha em /etc/crontab:<pre>
 +
*/1 *  * * *  root    /root/teste_dns.sh
 +
</pre>Terminamos aqui o Servidor 1 de DNS Anycast com Hyperlocal. Para configurar o servidor 2, basta fazer os mesmos procedimentos usados no servidor 1 mas mudando os dados de conexão. Vou colocar abaixo apenas as configurações que serão diferentes.
 +
 +
== Instalação e configuração do Servidor 2 - apenas as diferenças ==
 +
 +
=== Configurando a rede ===
 +
'''/etc/network/interfaces:'''
 +
# This file describes the network interfaces available on your system
 +
# and how to activate them. For more information, see interfaces(5).
 +
 +
source /etc/network/interfaces.d/*
 +
 +
# The loopback network interface
 +
auto lo
 +
iface lo inet loopback
 +
 +
auto lo:0
 +
iface lo:0 inet static
 +
      address 10.10.10.10/32
 +
 +
iface lo:0 inet6 static
 +
      address fc00::10:10:10:10
 +
      netmask 128
 +
 +
# The primary network interface
 +
auto ens160
 +
iface ens160 inet static
 +
        address 192.0.2.6/30
 +
        gateway 192.0.2.5
 +
 +
iface ens160 inet6 static
 +
        address 2001:db8:aaaa::192:0:2:6
 +
        netmask 64
 +
        gateway 2001:db8:aaaa::192:0:2:5
 +
 
 +
 +
=== Configurando o FRR e a sessão BGP com o router ===
 +
Em '''/etc/frr/daemons''' modifique o valor '''bgpd=no''' para '''bgpd=yes''', dessa forma habilitaremos o BGP no FRR. Feito isso precisaremos reiniciar o serviço frr:
 +
# systemctl restart frr.service
 +
Nosso arquivo '''/etc/frr/frr.conf''' ficará assim:
 +
frr version 7.5
 +
frr defaults traditional
 +
hostname unbound2
 +
log syslog informational
 +
no ip forwarding
 +
no ipv6 forwarding
 +
service integrated-vtysh-config
 +
!
 +
router bgp 65000
 +
  bgp router-id 192.0.2.6
 +
  no bgp ebgp-requires-policy
 +
  no bgp network import-check
 +
  neighbor 192.0.2.5 remote-as 65000
 +
  neighbor 2001:db8:aaaa::192:0:2:5 remote-as 65000
 +
 !
 +
  address-family ipv4 unicast
 +
  network 10.10.10.10/32
 +
  neighbor 192.0.2.5 prefix-list BLOQUEIA-TUDO in
 +
  neighbor 192.0.2.5 prefix-list RECURSIVO out
 +
  exit-address-family
 +
 !
 +
  address-family ipv6 unicast
 +
  network fc00::10:10:10:10/128
 +
  neighbor 2001:db8:aaaa::192:0:2:5 activate
 +
  neighbor 2001:db8:aaaa::192:0:2:5 prefix-list BLOQUEIA-TUDO_V6 in
 +
  neighbor 2001:db8:aaaa::192:0:2:5 prefix-list RECURSIVO_V6 out
 +
  exit-address-family
 +
!
 +
ip prefix-list BLOQUEIA-TUDO seq 5 deny any
 +
ip prefix-list RECURSIVO seq 5 permit 10.10.10.10/32
 +
!
 +
ipv6 prefix-list BLOQUEIA-TUDO_V6 seq 5 deny any
 +
ipv6 prefix-list RECURSIVO_V6 seq 5 permit fc00::10:10:10:10/128
 +
!
 +
line vty
 +
!
 +
 +
=== Configurando o Unbound ===
 +
Não entraremos em detalhes sobre cada parâmetro da configuração do Unbound, porque isso fugiria bastante do objetivo deste artigo. Ao invés disso, criaremos o arquivo '''/etc/unbound/unbound.conf.d/local.conf''' e dentro dele teremos o seguinte:
 +
server:
 +
        verbosity: 1
 +
        statistics-interval: 0
 +
        statistics-cumulative: no
 +
        extended-statistics: yes
 +
        num-threads: 4
 +
        interface: 127.0.0.1
 +
        interface: 10.10.10.10
 +
        interface: fc00::10:10:10:10
 +
        interface: ::1
 +
        interface-automatic: no
 +
        outgoing-interface: 192.0.2.6
 +
        outgoing-interface: 2001:db8:aaaa::192:0:2:6
 +
        outgoing-range: 8192
 +
        outgoing-num-tcp: 20
 +
        incoming-num-tcp: 20
 +
        so-rcvbuf: 4m
 +
        so-sndbuf: 4m
 +
        edns-buffer-size: 1232
 +
        msg-cache-size: 100m
 +
        msg-cache-slabs: 4
 +
        num-queries-per-thread: 8192
 +
        rrset-cache-size: 200m
 +
        rrset-cache-slabs: 4
 +
        infra-cache-slabs: 4
 +
        do-ip4: yes
 +
        do-ip6: yes
 +
        do-udp: yes
 +
        do-tcp: yes
 +
        access-control: 203.0.113.0/24 allow
 +
        access-control: 2001:db8:1111::/48 allow
 +
        chroot: ""
 +
        username: "unbound"
 +
        directory: "/etc/unbound"
 +
        logfile: "/var/log/unbound/unbound.log"
 +
        use-syslog: no
 +
        log-time-ascii: yes
 +
        log-queries: no
 +
        pidfile: "/var/run/unbound.pid"
 +
        root-hints: "/etc/unbound/named.cache"
 +
        hide-identity: yes
 +
        hide-version: yes
 +
        unwanted-reply-threshold: 10000000
 +
        prefetch: yes
 +
        prefetch-key: yes
 +
        rrset-roundrobin: yes
 +
        minimal-responses: yes
 +
        val-clean-additional: yes
 +
        val-log-level: 1
 +
        key-cache-slabs: 4
 +
 +
python:
 +
 +
remote-control:
 +
        control-enable: yes
 +
        server-key-file: "/etc/unbound/unbound_server.key"
 +
        server-cert-file: "/etc/unbound/unbound_server.pem"
 +
        control-key-file: "/etc/unbound/unbound_control.key"
 +
        control-cert-file: "/etc/unbound/unbound_control.pem"
 +
 +
auth-zone:
 +
    name: "."
 +
    master: "b.root-servers.net"
 +
    master: "c.root-servers.net"
 +
    master: "f.root-servers.net"
 +
    master: "g.root-servers.net"
 +
    master: "k.root-servers.net"
 +
    master: "lax.xfr.dns.icann.org"
 +
    master: "iad.xfr.dns.icann.org"
 +
    fallback-enabled: yes
 +
    for-downstream: no
 +
    for-upstream: yes
 +
    zonefile: "/var/lib/unbound/root.zone"
 +
=== Script do Servidor 2 ===
 +
'''/root/teste_dns.sh'''
 +
#!/usr/bin/env bash
 +
<nowiki>#</nowiki>Script para teste de DNS v1.2
 +
<nowiki>#</nowiki>-----------------------------------------------------------------------
 +
<nowiki>#</nowiki>Informe um domínio por linha:
 +
dominios_testar=(
 +
www.google.com
 +
www.terra.com.br
 +
www.uol.com.br
 +
www.globo.com
 +
www.facebook.com
 +
www.youtube.com
 +
www.twitch.com
 +
www.discord.com
 +
www.debian.org
 +
www.redhat.com
 +
)
 +
corte_taxa_falha=100 #Porcentagem de falha para executar uma ação
 +
<nowiki>#</nowiki>-----------------------------------------------------------------------
 +
qt_falhas=0
 +
qt_total="${#dominios_testar[@]}"
 +
echo "total_dominios: $qt_total"
 +
for site in "${dominios_testar[@]}"
 +
do
 +
<nowiki> </nowiki> resp=<nowiki>''</nowiki>
 +
<nowiki> </nowiki> resolver="127.0.0.1"
 +
<nowiki> </nowiki> echo " - dominio $site - $resolver"
 +
<nowiki> </nowiki> resp=$( host $site $resolver | grep "connection timed out" )
 +
<nowiki> </nowiki> if [ ! -z "$resp" ]; then
 +
<nowiki> </nowiki>    ((qt_falhas++))
 +
<nowiki> </nowiki>    echo "[$resp]"
 +
<nowiki> </nowiki> fi
 +
done
 +
 +
taxa_falha=$((qt_falhas*100/qt_total))
 +
echo "Falhas $qt_falhas/$qt_total ($taxa_falha%)"
 +
 +
if [ "$taxa_falha" -ge "$corte_taxa_falha" ]; then
 +
<nowiki> </nowiki>  habilitado="`vtysh -c 'show run' | grep \"neighbor 192.0.2.5 prefix-list BLOQUEIA-TUDO out\"`"
 +
<nowiki> </nowiki>  if [ "$habilitado" == "" ]; then
 +
<nowiki> </nowiki>    vtysh -c 'conf t' -c 'router bgp 65000' -c 'address-family ipv4 unicast' -c 'no neighbor 192.0.2.5 prefix-list RECURSIVO out' -c 'neighbor 192.0.2.5 prefix-list BLOQUEIA-TUDO out' -c 'end' -c 'wr'
 +
<nowiki> </nowiki>    vtysh -c 'conf t' -c 'router bgp 65000' -c 'address-family ipv6 unicast' -c 'no neighbor 2001:db8:aaaa::192:0:2:5 prefix-list RECURSIVO_V6 out' -c 'neighbor 2001:db8:aaaa::192:0:2:5 prefix-list BLOQUEIA-TUDO out' -c 'end' -c 'wr'
 +
<nowiki> </nowiki>    echo "caiu: `date`" >> /root/dnsreport.log
 +
<nowiki> </nowiki>  fi
 +
<nowiki> </nowiki>  exit
 +
fi
 +
 +
habilitado="`vtysh -c 'show run' | grep \"neighbor 192.0.2.5 prefix-list RECURSIVO out\"`"
 +
if [ "$habilitado" == "" ]; then
 +
<nowiki> </nowiki>  vtysh -c 'conf t' -c 'router bgp 65000' -c 'address-family ipv4 unicast' -c 'no neighbor 192.0.2.5 prefix-list BLOQUEIA-TUDO out' -c 'neighbor 192.0.2.5 prefix-list RECURSIVO out' -c 'end' -c 'wr'
 +
<nowiki> </nowiki>  vtysh -c 'conf t' -c 'router bgp 65000' -c 'address-family ipv6 unicast' -c 'no neighbor 2001:db8:aaaa::192:0:2:5 prefix-list BLOQUEIA-TUDO out' -c 'neighbor 2001:db8:aaaa::192:0:2:5 prefix-list RECURSIVO_V6 out' -c 'end' -c 'wr'
 +
<nowiki> </nowiki>  echo "voltou: `date`" >> /root/dnsreport.log
 +
fi
 +
Chegamos ao final deste artigo e espero que tenha sido útil para a comunidade. Lembre-se que temos que pensar no futuro da Internet e é muito importante que usemos IPv6 em todas as nossas implementações de rede, sejam servidores, equipamentos ou aplicações.
  
 +
Autor: [[Usuário:Gondim|Marcelo Gondim]]
 
[[Categoria:Infraestrutura]]
 
[[Categoria:Infraestrutura]]
 
__FORCARTDC__
 
__FORCARTDC__

Edição das 17h21min de 19 de junho de 2022

Descrição

Um dos recursos extremamente importante para o acesso à Internet é o DNS (Domain Name System) e sem ele teríamos que decorar milhares de endereços IP para acessar sites e serviços na Internet. Basicamente temos 2 tipos de DNS, o recursivo e o autoritativo. O recursivo é um serviço que utilizamos para fazer consultas aos DNS(es) Autoritativos que são aqueles responsáveis pelas tabelas que associam o host name a um IP e no caso de resolução reversa, o IP ao host name. O exemplo mais comum de DNS recursivo é o do Google, os IPs 8.8.8.8, 8.8.4.4, 2001:4860:4860::8888 e 2001:4860:4860::8844. Se você está estranhando os 2 últimos endereços, é porque provavelmente ainda não ouviu falar de IPv6 e isso não é bom. Procure estudar sobre isso e um bom lugar para começar é aqui. O serviço de DNS deve ser levado muito a sério pelas empresas que o implementam, porque a sua falha pode literalmente parar a Internet para milhares de pessoas que confiam nele ou até pior, um DNS mal intencionado ou comprometido, pode ser usado para direcionar usuários a acessarem sites falsos. Esse artifício visa coletar as credenciais dos usuários e assim poderem aplicar golpes e outras formas danosas e prejudiciais à vítima. Ter um DNS recursivo é muito bom para o ISP, mas cuidar dele, mantê-lo atualizado e protegido, é mais importante ainda.

Nesse artigo mostrarei a configuração de um DNS recursivo anycast, diferente dos DNS recursivos unicast comumente encontrados pelos ISPs a fora. No modelo Unicast, normalmente se tem um ou mais servidores de DNS que são consultados e estão fisicamente em um local. O problema é que essa abordagem não poderia ter por exemplo, 5 servidores, e utilizar todos configurados ao mesmo tempo nos sistemas, porque muitos sistemas só aceitam até 3 servidores recursivos em suas configurações e mais que isso são ignorados. Você poderia então utilizar apenas 2 servidores, isso resolveria o problema mas eles precisariam estar em um determinado local. Mas e se lá na frente você resolver abrir seu negócio em uma outra cidade e em outro estado? Nesse caso poderia continuar usando os mesmos servidores mas aumentando um pouco a latência. Mas se acontecesse algo na interconexão desses servidores? Com o uso do DNS Anycast você poderia ter um servidor DNS recursivo em cada cidade e respondendo pelo mesmo IP. Em caso de problemas com qualquer servidor, o outro passaria a responder para todos os seus assinantes. Além desse recurso, usaremos o Hyperlocal que é uma técnica que faz uma cópia das tabelas dos DNS Root Servers e mantém localmente no seu servidor recursivo. Isso deixa rápida toda resposta que seria endereçada primeiramente aos DNS(es) Raiz da Internet, principalmente consultas de domínios inválidos ou digitados erradamente.

Diagrama

Para que possamos visualizar nossa configuração, abaixo temos um diagrama hipotético dos nossos servidores e da rede em si:

Diagrama dns anycast2.png

Explicando o cenário: cada servidor DNS fechará uma sessão iBGP com o seu router através dos endereços /30 IPv4 e /64 IPv6 (usando IPs de documentação RFC3849 e RFC5737 representando seus IPs públicos). Nessa sessão BGP serão anunciados os IPs privados RFC1918 e RFC4193 configurados nas loopbacks que serão: 10.10.10.10 e fc00::10:10:10:10. Divulgando esses IPs privados para os assinantes, você esconde o real IP público dos servidores, evitando que alguém de fora envie ataques para seus servidores DNS.

Servidores utilizados

  • VM com 4 cores (Intel(R) Xeon(R) Silver 4214R CPU @ 2.40GHz).
  • 4Gb memória.
  • 20Gb disco.

Softwares utilizados

Para instalação e configuração dos Servidores DNS Recursivos utilizaremos Software Livre, o que nos permite uma economia em licenças de sistemas fechados e proprietários. Abaixo a descrição deles:

  • Debian Linux Buster (10.x).
  • FRRouting 7.5.1.
  • Unbound 1.9.0 (pacote da distribuição Debian). Obs.: essa versão do Unbound já possui suporte ao Hyperlocal nativo.
  • IRQBalance (pacote do Debian).
  • OpenNTPd (também pacote do Debian).
  • Shell script em bash, para checar se o DNS está OK e se não tiver retirar ele do anúncio.

Gráfico de utilização desse sistema em produção

Dns Anycast Grafico.png

Instalação e configuração do Servidor 1

Instale um sistema Debian 10 com o mínimo necessário, uma versão que costumo utilizar bastante é a que vem com firmwares e pode ser encontrado aqui. Atualmente está na versão 10.10, mas caso lancem uma versão mais recente, basta alterar o link. Não cobriremos a instalação do Debian, pois existem diversos vídeos no Youtube ensinando como proceder. Após a instalação faremos os ajustes na configuração para que possa então acomodar nosso serviço de DNS.

Instalação dos pacotes

FRR

Vamos configurar o repositório oficial do FRR e instalar os pacotes. O FRR é um fork do Quagga e será o responsável pela sessão BGP entre o servidor DNS e o router:

# echo "deb https://deb.frrouting.org/frr buster frr-stable" > /etc/apt/sources.list.d/frr.list
# curl -s https://deb.frrouting.org/frr/keys.asc | apt-key add -
# apt update
# apt install frr frr-doc frr-pythontools

Unbound

O Unbound é exatamente o serviço de DNS recursivo que vamos utilizar nesse artigo. Por que o Unbound? Porque ele só faz recursividade, que é o que desejamos e faz isso com uma excelente performance e segurança. Ele é desenvolvido pela NLNet Labsmesma empresa que desenvolve o Krill e Routinator, utilizados na implantação do RPKI e o NSD (servidor DNS autoritativo) e todos sempre pensando em segurança.

# apt install unbound

IRQBalance

O IRQBalance é um programa bem conhecido por distribuir o processamento entre os cores do servidor.

# apt install irqbalance
# systemctl enable irqbalance

OpenNTPd

Para manter o sistema sempre com o horário correto, usaremos o OpenNTPd configurado para usar o Pool do Nic.BR.

# apt install openntpd

Deixe o arquivo /etc/openntpd/ntpd.conf conforme abaixo e reinicie o serviço openntpd:

# $OpenBSD: ntpd.conf,v 1.14 2015/07/15 20:28:37 ajacoutot Exp $
# sample ntpd configuration file, see ntpd.conf(5)

# Addresses to listen on (ntpd does not listen by default)
#listen on *
#listen on 127.0.0.1
#listen on ::1

# sync to a single server
#server ntp.example.org
servers pool.ntp.br

# use a random selection of NTP Pool Time Servers
# see http://support.ntp.org/bin/view/Servers/NTPPoolServers
#servers pool.ntp.org

# Choose servers announced from Debian NTP Pool
#servers 0.debian.pool.ntp.org
#servers 1.debian.pool.ntp.org
#servers 2.debian.pool.ntp.org
#servers 3.debian.pool.ntp.org

# use a specific local timedelta sensor (radio clock, etc)
#sensor nmea0

# use all detected timedelta sensors
#sensor *

Configurando a rede

/etc/network/interfaces:

# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

auto lo:0
iface lo:0 inet static
      address 10.10.10.10/32

iface lo:0 inet6 static
      address fc00::10:10:10:10
      netmask 128

# The primary network interface
auto ens160
iface ens160 inet static
        address 192.0.2.2/30
        gateway 192.0.2.1

iface ens160 inet6 static
        address 2001:db8::192:0:2:2
        netmask 64
        gateway 2001:db8::192:0:2:1

Configurando o FRR e a sessão BGP com o router

Em /etc/frr/daemons modifique o valor bgpd=no para bgpd=yes, dessa forma habilitaremos o BGP no FRR. Feito isso precisaremos reiniciar o serviço frr:

# systemctl restart frr.service

Nosso arquivo /etc/frr/frr.conf ficará assim:

frr version 7.5
frr defaults traditional
hostname unbound1
log syslog informational
no ip forwarding
no ipv6 forwarding
service integrated-vtysh-config
!
router bgp 65000
 bgp router-id 192.0.2.2
 no bgp ebgp-requires-policy
 no bgp network import-check
 neighbor 192.0.2.1 remote-as 65000
 neighbor 2001:db8::192:0:2:1 remote-as 65000
 !
 address-family ipv4 unicast
  network 10.10.10.10/32
  neighbor 192.0.2.1 prefix-list BLOQUEIA-TUDO in
  neighbor 192.0.2.1 prefix-list RECURSIVO out
 exit-address-family
 !
 address-family ipv6 unicast
  network fc00::10:10:10:10/128
  neighbor 2001:db8::192:0:2:1 activate
  neighbor 2001:db8::192:0:2:1 prefix-list BLOQUEIA-TUDO_V6 in
  neighbor 2001:db8::192:0:2:1 prefix-list RECURSIVO_V6 out
 exit-address-family
!
ip prefix-list BLOQUEIA-TUDO seq 5 deny any
ip prefix-list RECURSIVO seq 5 permit 10.10.10.10/32
!
ipv6 prefix-list BLOQUEIA-TUDO_V6 seq 5 deny any
ipv6 prefix-list RECURSIVO_V6 seq 5 permit fc00::10:10:10:10/128
!
line vty
!

Após configurar a sessão BGP no lado do router, verifique se as sessões foram estabelecidas IPv4 e IPv6. No nosso servidor podemos checar assim:

# vtysh -c 'show bgp summary'

Deve exibir algo parecido assim:

IPv4 Unicast Summary:
BGP router identifier 192.0.2.2, local AS number 65000 vrf-id 0
BGP table version 1
RIB entries 1, using 192 bytes of memory
Peers 2, using 43 KiB of memory

Neighbor         V         AS   MsgRcvd   MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd   PfxSnt
192.0.2.1       4      65000    427529    407165        0    0    0 20w1d08h            0        1
2001:db8::192:0:2:1 4      65000    427517    407160        0    0    0 20w1d08h NoNeg

Total number of neighbors 2

IPv6 Unicast Summary:
BGP router identifier 192.0.2.2, local AS number 65000 vrf-id 0
BGP table version 1
RIB entries 1, using 192 bytes of memory
Peers 1, using 21 KiB of memory

Neighbor         V         AS   MsgRcvd   MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd   PfxSnt
2001:db8::192:0:2:1 4      65000    427517    407160        0    0    0 20w1d08h            0        1

Total number of neighbors 1

Podemos observar que não estamos recebendo nenhum prefixo do router e estamos apenas anunciando 1 prefixo IPv4 e 1 IPv6. Vejamos quais são:

# vtysh -c 'show ip bgp neighbors 192.0.2.1 advertised-routes'
BGP table version is 1, local router ID is 192.0.2.2, vrf id 0
Default local pref 100, local AS 65000
Status codes:  s suppressed, d damped, h history, * valid, > best, = multipath,
               i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes:  i - IGP, e - EGP, ? - incomplete

   Network          Next Hop            Metric LocPrf Weight Path
*> 10.10.10.10/32   0.0.0.0                  0    100  32768 i

Total number of prefixes 1
# vtysh -c 'show ip bgp ipv6 neighbors 2001:db8::192:0:2:1 advertised-routes'
BGP table version is 1, local router ID is 192.0.2.2, vrf id 0
Default local pref 100, local AS 65000
Status codes:  s suppressed, d damped, h history, * valid, > best, = multipath,
               i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes:  i - IGP, e - EGP, ? - incomplete

   Network          Next Hop            Metric LocPrf Weight Path
*> fc00::10:10:10:10/128
                    ::                       0    100  32768 i

Total number of prefixes 1

Podemos observar que nossos IPs já estão sendo anunciados para o router e vocês devem checar se estão sendo recebidos pelo router. Não estamos entrando em detalhes na parte do router pois este pode ser de qualquer fabricante como por exemplo: Cisco, Huawei, Juniper, Mikrotik, outro FRR, etc.

Configurando o Unbound

Não entraremos em detalhes sobre cada parâmetro da configuração do Unbound, porque isso fugiria bastante do objetivo deste artigo. Ao invés disso, criaremos o arquivo /etc/unbound/unbound.conf.d/local.conf e dentro dele teremos o seguinte:

server:
        verbosity: 1
        statistics-interval: 0
        statistics-cumulative: no
        extended-statistics: yes
        num-threads: 4
        interface: 127.0.0.1
        interface: 10.10.10.10
        interface: fc00::10:10:10:10
        interface: ::1 
        interface-automatic: no
        outgoing-interface: 192.0.2.2
        outgoing-interface: 2001:db8::192:0:2:2
        outgoing-range: 8192
        outgoing-num-tcp: 20
        incoming-num-tcp: 20
        so-rcvbuf: 4m
        so-sndbuf: 4m
        edns-buffer-size: 1232
        msg-cache-size: 100m
        msg-cache-slabs: 4
        num-queries-per-thread: 8192
        rrset-cache-size: 200m
        rrset-cache-slabs: 4
        infra-cache-slabs: 4
        do-ip4: yes
        do-ip6: yes
        do-udp: yes
        do-tcp: yes
        access-control: 203.0.113.0/24 allow
        access-control: 2001:db8:1111::/48 allow
        chroot: ""
        username: "unbound"
        directory: "/etc/unbound"
        logfile: "/var/log/unbound/unbound.log"
        use-syslog: no
        log-time-ascii: yes
        log-queries: no
        pidfile: "/var/run/unbound.pid"
        root-hints: "/etc/unbound/named.cache"
        hide-identity: yes
        hide-version: yes
        unwanted-reply-threshold: 10000000
        prefetch: yes
        prefetch-key: yes
        rrset-roundrobin: yes
        minimal-responses: yes
        val-clean-additional: yes
        val-log-level: 1
        key-cache-slabs: 4

python:

remote-control:
        control-enable: yes
        server-key-file: "/etc/unbound/unbound_server.key"
        server-cert-file: "/etc/unbound/unbound_server.pem"
        control-key-file: "/etc/unbound/unbound_control.key"
        control-cert-file: "/etc/unbound/unbound_control.pem"

auth-zone:
    name: "."
    master: "b.root-servers.net"
    master: "c.root-servers.net"
    master: "f.root-servers.net"
    master: "g.root-servers.net"
    master: "k.root-servers.net"
    master: "lax.xfr.dns.icann.org"
    master: "iad.xfr.dns.icann.org"
    fallback-enabled: yes
    for-downstream: no
    for-upstream: yes
    zonefile: "/var/lib/unbound/root.zone"

Os parâmetros relevantes acima são:

Como nosso servidor possui 4 cores, colocamos 4 em num-threads também:
        num-threads: 4

O interface indica quais IPs ficarão escutando o serviço na porta 53/udp/tcp para serem consultados pelo servidor e assinantes:
        interface: 127.0.0.1
        interface: 10.10.10.10
        interface: fc00::10:10:10:10
        interface: ::1 

O outgoing-interface indica por quais IPs serão feitas as consultas de DNS para o mundo:
        outgoing-interface: 192.0.2.2
        outgoing-interface: 2001:db8::192:0:2:2

Habilita consultas IPv4 e IPv6, udp e tcp:
        do-ip4: yes
        do-ip6: yes
        do-udp: yes
        do-tcp: yes

Libera a consulta DNS para origem desses prefixos, troque pelos prefixos reais do seu ASN: 
        access-control: 203.0.113.0/24 allow 
        access-control: 2001:db8:1111::/48 allow

Esse trecho abaixo é referente à configuração do Hyperlocal:

auth-zone:
    name: "."
    master: "b.root-servers.net"
    master: "c.root-servers.net"
    master: "f.root-servers.net"
    master: "g.root-servers.net"
    master: "k.root-servers.net"
    master: "lax.xfr.dns.icann.org"
    master: "iad.xfr.dns.icann.org"
    fallback-enabled: yes
    for-downstream: no
    for-upstream: yes
    zonefile: "/var/lib/unbound/root.zone"

Após a configuração do Unbound basta reiniciar o serviço unbound e verificar se o arquivo /var/lib/unbound/root.zone foi criado com o conteúdo dos Root Servers.

Vamos alterar o /etc/resolv.conf para acertar as consultas locais e diminuir o timeout que precisaremos mais a frente no script que fará o teste se o DNS continua funcionando e em caso negativo, retirar o anúncio dos IPs:

nameserver 127.0.0.1
nameserver ::1
options timeout:1 attempts:1

Feito isso teste se seu servidor está resolvendo os hosts na Internet por exemplo:

# host www.uol.com.br 127.0.0.1
Using domain server:
Name: 127.0.0.1
Address: 127.0.0.1#53
Aliases: 

www.uol.com.br is an alias for dftex7xfha8fh.cloudfront.net.
dftex7xfha8fh.cloudfront.net has address 99.84.22.115
dftex7xfha8fh.cloudfront.net has address 99.84.22.71
dftex7xfha8fh.cloudfront.net has address 99.84.22.8
dftex7xfha8fh.cloudfront.net has address 99.84.22.27
dftex7xfha8fh.cloudfront.net has IPv6 address 2600:9000:21ed:6200:1:5a19:8b40:93a1
dftex7xfha8fh.cloudfront.net has IPv6 address 2600:9000:21ed:f000:1:5a19:8b40:93a1
dftex7xfha8fh.cloudfront.net has IPv6 address 2600:9000:21ed:f400:1:5a19:8b40:93a1
dftex7xfha8fh.cloudfront.net has IPv6 address 2600:9000:21ed:7800:1:5a19:8b40:93a1
dftex7xfha8fh.cloudfront.net has IPv6 address 2600:9000:21ed:ac00:1:5a19:8b40:93a1
dftex7xfha8fh.cloudfront.net has IPv6 address 2600:9000:21ed:8a00:1:5a19:8b40:93a1
dftex7xfha8fh.cloudfront.net has IPv6 address 2600:9000:21ed:f200:1:5a19:8b40:93a1
dftex7xfha8fh.cloudfront.net has IPv6 address 2600:9000:21ed:fc00:1:5a19:8b40:93a1

# host www.terra.com.br ::1
Using domain server:
Name: ::1
Address: ::1#53
Aliases: 

www.terra.com.br is an alias for www.terra.com.br.edgesuite.net.
www.terra.com.br.edgesuite.net is an alias for a1799.dscb.akamai.net.
a1799.dscb.akamai.net has address 23.73.211.226
a1799.dscb.akamai.net has address 23.73.211.186
a1799.dscb.akamai.net has IPv6 address 2600:1419:d400::1749:d78a
a1799.dscb.akamai.net has IPv6 address 2600:1419:d400::1749:d7d9

Ok funcionando e resolvendo tanto via IPv4 quanto via IPv6. Caso queira testar localmente com os IPs 10.10.10.10 e fc00::10:10:10:10 você terá que adicioná-los no nosso local.conf do Unbound no parâmetro access-control liberando o 10.10.10.10/32 e fc00::10:10:10:10/128. Você também pode usar o programa dig para testar seu DNS recursivo:

# apt install bind9-dnsutils
# dig @127.0.0.1 www.terra.com.br

; <<>> DiG 9.16.15-Debian <<>> @127.0.0.1 www.terra.com.br
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33258
;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;www.terra.com.br.              IN      A

;; ANSWER SECTION:
www.terra.com.br.       58      IN      CNAME   www.terra.com.br.edgesuite.net.
www.terra.com.br.edgesuite.net. 21512 IN CNAME  a1799.dscb.akamai.net.
a1799.dscb.akamai.net.  18      IN      A       23.196.224.219
a1799.dscb.akamai.net.  18      IN      A       23.196.225.9

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: qua jun 30 10:09:19 -03 2021
;; MSG SIZE  rcvd: 153
# dig @::1 www.terra.com.br

; <<>> DiG 9.16.15-Debian <<>> @::1 www.terra.com.br
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 63261
;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;www.terra.com.br.              IN      A

;; ANSWER SECTION:
www.terra.com.br.       17      IN      CNAME   www.terra.com.br.edgesuite.net.
www.terra.com.br.edgesuite.net. 21471 IN CNAME  a1799.dscb.akamai.net.
a1799.dscb.akamai.net.  17      IN      A       23.196.225.9
a1799.dscb.akamai.net.  17      IN      A       23.196.224.219

;; Query time: 0 msec
;; SERVER: ::1#53(::1)
;; WHEN: qua jun 30 10:10:00 -03 2021
;; MSG SIZE  rcvd: 153

Vamos testar se nosso Hyperlocal está funcionando? Vamos fazer uma consulta de um host com nome absurdo e que não existe na Internet, sem o Hyperlocal habilitado:

# dig @127.0.0.1 wws.sssss.ssss

; <<>> DiG 9.16.15-Debian <<>> @127.0.0.1 wws.sssss.ssss
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 51541
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;wws.sssss.ssss.                        IN      A

;; AUTHORITY SECTION:
.                       3600    IN      SOA     a.root-servers.net. nstld.verisign-grs.com. 2021063000 1800 900 604800 86400

;; Query time: 312 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: qua jun 30 10:49:24 -03 2021
;; MSG SIZE  rcvd: 118

Repare que a resposta do Root Server levou 312 msec. Agora vamos fazer a mesma consulta com o Hyperlocal habilitado e unbound reiniciado:

# dig @127.0.0.1 wws.sssss.ssss

; <<>> DiG 9.16.15-Debian <<>> @127.0.0.1 wws.sssss.ssss
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 48429
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;wws.sssss.ssss.                        IN      A

;; AUTHORITY SECTION:
.                       86397   IN      SOA     a.root-servers.net. nstld.verisign-grs.com. 2021063000 1800 900 604800 86400

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: qua jun 30 10:52:21 -03 2021
;; MSG SIZE  rcvd: 118

Com as tabelas locais, a mesma consulta levou 0 msec. Muito bom não é mesmo?

Próximo passo é configurar os IPs 10.10.10.10 e fc00::10:10:10:10 em algum dispositivo ou estação da rede e testar se está funcionando a resolução de nomes. Se chegamos até aqui com tudo funcionando então perfeito.

Vamos configurar agora um script que vai checar se o nosso DNS parou de resolver nomes e se isso ocorrer, ele deixará de anunciar os IPs de DNS para o router. Nesse caso o outro DNS continuará respondendo com os mesmos IPs.

Script do Servidor 1

/root/teste_dns.sh

#!/usr/bin/env bash
#Script para teste de DNS v1.2
#-----------------------------------------------------------------------
#Informe um domínio por linha:
dominios_testar=(
www.google.com
www.terra.com.br
www.uol.com.br
www.globo.com
www.facebook.com
www.youtube.com
www.twitch.com
www.discord.com
www.debian.org
www.redhat.com
)
corte_taxa_falha=100 #Porcentagem de falha para executar uma ação
#-----------------------------------------------------------------------
qt_falhas=0
qt_total="${#dominios_testar[@]}"
echo "total_dominios: $qt_total"
for site in "${dominios_testar[@]}"
do
  resp=''
  resolver="127.0.0.1"
  echo " - dominio $site - $resolver"
  resp=$( host $site $resolver | grep "connection timed out" )
  if [ ! -z "$resp" ]; then
     ((qt_falhas++))
     echo "[$resp]"
  fi
done

taxa_falha=$((qt_falhas*100/qt_total))
echo "Falhas $qt_falhas/$qt_total ($taxa_falha%)"

if [ "$taxa_falha" -ge "$corte_taxa_falha" ]; then
   habilitado="`vtysh -c 'show run' | grep \"neighbor 192.0.2.1 prefix-list BLOQUEIA-TUDO out\"`"
   if [ "$habilitado" == "" ]; then
      vtysh -c 'conf t' -c 'router bgp 65000' -c 'address-family ipv4 unicast' -c 'no neighbor 192.0.2.1 prefix-list RECURSIVO out' -c 'neighbor 192.0.2.1 prefix-list BLOQUEIA-TUDO out' -c 'end' -c 'wr'
      vtysh -c 'conf t' -c 'router bgp 65000' -c 'address-family ipv6 unicast' -c 'no neighbor 2001:db8::192:0:2:1 prefix-list RECURSIVO_V6 out' -c 'neighbor 2001:db8::192:0:2:1 prefix-list BLOQUEIA-TUDO out' -c 'end' -c 'wr'
      echo "caiu: `date`" >> /root/dnsreport.log
   fi
   exit
fi

habilitado="`vtysh -c 'show run' | grep \"neighbor 192.0.2.1 prefix-list RECURSIVO out\"`"
if [ "$habilitado" == "" ]; then
   vtysh -c 'conf t' -c 'router bgp 65000' -c 'address-family ipv4 unicast' -c 'no neighbor 192.0.2.1 prefix-list BLOQUEIA-TUDO out' -c 'neighbor 192.0.2.1 prefix-list RECURSIVO out' -c 'end' -c 'wr'
   vtysh -c 'conf t' -c 'router bgp 65000' -c 'address-family ipv6 unicast' -c 'no neighbor 2001:db8::192:0:2:1 prefix-list BLOQUEIA-TUDO out' -c 'neighbor 2001:db8::192:0:2:1 prefix-list RECURSIVO_V6 out' -c 'end' -c 'wr'
   echo "voltou: `date`" >> /root/dnsreport.log
fi

Sim. Para entender o que está escrito acima você precisa conhecer um pouco de linguagem de shell script em bash. Fique à vontade em melhorar ou até mesmo criar seu próprio script em outra linguagem. O conceito é bem simples e usado apenas para testar se nosso DNS está resolvendo pra fora. Porque você pode não estar conseguindo, por algum motivo, consultar na Internet pelas portas 53/udp e/ou 53/tcp e que poderia ser causado por algum bloqueio ou problema de fato na rede. Caso is aconteça usaremos os comandos vtysh via shell, para alterar a nossa configuração no FRR e bloquear os anúncios. Uma outra coisa que fica como dever de casa: no script ele gera um relatório de quando tem problema no DNS e quando volta a funcionar. Você pode pesquisar e utilizar os pacotes do Debian msmtp e msmtp-mta, configurar ele e o script para enviar um e-mail em caso de problemas. Como não sou mau, você pode achar informação sobre isso, nos slides de uma palestra que apresentei no FiqueEmCasaUseDebian bem aqui.

Vamos agora colocar o script para rodar no cron adicionando a seguinte linha em /etc/crontab:

*/1 *   * * *   root    /root/teste_dns.sh

Terminamos aqui o Servidor 1 de DNS Anycast com Hyperlocal. Para configurar o servidor 2, basta fazer os mesmos procedimentos usados no servidor 1 mas mudando os dados de conexão. Vou colocar abaixo apenas as configurações que serão diferentes.

Instalação e configuração do Servidor 2 - apenas as diferenças

Configurando a rede

/etc/network/interfaces:

# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

auto lo:0
iface lo:0 inet static
      address 10.10.10.10/32

iface lo:0 inet6 static
      address fc00::10:10:10:10
      netmask 128

# The primary network interface
auto ens160
iface ens160 inet static
        address 192.0.2.6/30
        gateway 192.0.2.5

iface ens160 inet6 static
        address 2001:db8:aaaa::192:0:2:6
        netmask 64
        gateway 2001:db8:aaaa::192:0:2:5
  

Configurando o FRR e a sessão BGP com o router

Em /etc/frr/daemons modifique o valor bgpd=no para bgpd=yes, dessa forma habilitaremos o BGP no FRR. Feito isso precisaremos reiniciar o serviço frr:

# systemctl restart frr.service

Nosso arquivo /etc/frr/frr.conf ficará assim:

frr version 7.5
frr defaults traditional
hostname unbound2
log syslog informational
no ip forwarding
no ipv6 forwarding
service integrated-vtysh-config
!
router bgp 65000
 bgp router-id 192.0.2.6
 no bgp ebgp-requires-policy
 no bgp network import-check
 neighbor 192.0.2.5 remote-as 65000
 neighbor 2001:db8:aaaa::192:0:2:5 remote-as 65000
 !
 address-family ipv4 unicast
  network 10.10.10.10/32
  neighbor 192.0.2.5 prefix-list BLOQUEIA-TUDO in
  neighbor 192.0.2.5 prefix-list RECURSIVO out
 exit-address-family
 !
 address-family ipv6 unicast
  network fc00::10:10:10:10/128
  neighbor 2001:db8:aaaa::192:0:2:5 activate
  neighbor 2001:db8:aaaa::192:0:2:5 prefix-list BLOQUEIA-TUDO_V6 in
  neighbor 2001:db8:aaaa::192:0:2:5 prefix-list RECURSIVO_V6 out
 exit-address-family
!
ip prefix-list BLOQUEIA-TUDO seq 5 deny any
ip prefix-list RECURSIVO seq 5 permit 10.10.10.10/32
!
ipv6 prefix-list BLOQUEIA-TUDO_V6 seq 5 deny any
ipv6 prefix-list RECURSIVO_V6 seq 5 permit fc00::10:10:10:10/128
!
line vty
!

Configurando o Unbound

Não entraremos em detalhes sobre cada parâmetro da configuração do Unbound, porque isso fugiria bastante do objetivo deste artigo. Ao invés disso, criaremos o arquivo /etc/unbound/unbound.conf.d/local.conf e dentro dele teremos o seguinte:

server:
        verbosity: 1
        statistics-interval: 0
        statistics-cumulative: no
        extended-statistics: yes
        num-threads: 4
        interface: 127.0.0.1
        interface: 10.10.10.10
        interface: fc00::10:10:10:10
        interface: ::1 
        interface-automatic: no
        outgoing-interface: 192.0.2.6
        outgoing-interface: 2001:db8:aaaa::192:0:2:6
        outgoing-range: 8192
        outgoing-num-tcp: 20
        incoming-num-tcp: 20
        so-rcvbuf: 4m
        so-sndbuf: 4m
        edns-buffer-size: 1232
        msg-cache-size: 100m
        msg-cache-slabs: 4
        num-queries-per-thread: 8192
        rrset-cache-size: 200m
        rrset-cache-slabs: 4
        infra-cache-slabs: 4
        do-ip4: yes
        do-ip6: yes
        do-udp: yes
        do-tcp: yes
        access-control: 203.0.113.0/24 allow
        access-control: 2001:db8:1111::/48 allow
        chroot: ""
        username: "unbound"
        directory: "/etc/unbound"
        logfile: "/var/log/unbound/unbound.log"
        use-syslog: no
        log-time-ascii: yes
        log-queries: no
        pidfile: "/var/run/unbound.pid"
        root-hints: "/etc/unbound/named.cache"
        hide-identity: yes
        hide-version: yes
        unwanted-reply-threshold: 10000000
        prefetch: yes
        prefetch-key: yes
        rrset-roundrobin: yes
        minimal-responses: yes
        val-clean-additional: yes
        val-log-level: 1
        key-cache-slabs: 4

python:

remote-control:
        control-enable: yes
        server-key-file: "/etc/unbound/unbound_server.key"
        server-cert-file: "/etc/unbound/unbound_server.pem"
        control-key-file: "/etc/unbound/unbound_control.key"
        control-cert-file: "/etc/unbound/unbound_control.pem"

auth-zone:
    name: "."
    master: "b.root-servers.net"
    master: "c.root-servers.net"
    master: "f.root-servers.net"
    master: "g.root-servers.net"
    master: "k.root-servers.net"
    master: "lax.xfr.dns.icann.org"
    master: "iad.xfr.dns.icann.org"
    fallback-enabled: yes
    for-downstream: no
    for-upstream: yes
    zonefile: "/var/lib/unbound/root.zone"

Script do Servidor 2

/root/teste_dns.sh

#!/usr/bin/env bash
#Script para teste de DNS v1.2
#-----------------------------------------------------------------------
#Informe um domínio por linha:
dominios_testar=(
www.google.com
www.terra.com.br
www.uol.com.br
www.globo.com
www.facebook.com
www.youtube.com
www.twitch.com
www.discord.com
www.debian.org
www.redhat.com
)
corte_taxa_falha=100 #Porcentagem de falha para executar uma ação
#-----------------------------------------------------------------------
qt_falhas=0
qt_total="${#dominios_testar[@]}"
echo "total_dominios: $qt_total"
for site in "${dominios_testar[@]}"
do
  resp=''
  resolver="127.0.0.1"
  echo " - dominio $site - $resolver"
  resp=$( host $site $resolver | grep "connection timed out" )
  if [ ! -z "$resp" ]; then
     ((qt_falhas++))
     echo "[$resp]"
  fi
done

taxa_falha=$((qt_falhas*100/qt_total))
echo "Falhas $qt_falhas/$qt_total ($taxa_falha%)"

if [ "$taxa_falha" -ge "$corte_taxa_falha" ]; then
   habilitado="`vtysh -c 'show run' | grep \"neighbor 192.0.2.5 prefix-list BLOQUEIA-TUDO out\"`"
   if [ "$habilitado" == "" ]; then
      vtysh -c 'conf t' -c 'router bgp 65000' -c 'address-family ipv4 unicast' -c 'no neighbor 192.0.2.5 prefix-list RECURSIVO out' -c 'neighbor 192.0.2.5 prefix-list BLOQUEIA-TUDO out' -c 'end' -c 'wr'
      vtysh -c 'conf t' -c 'router bgp 65000' -c 'address-family ipv6 unicast' -c 'no neighbor 2001:db8:aaaa::192:0:2:5 prefix-list RECURSIVO_V6 out' -c 'neighbor 2001:db8:aaaa::192:0:2:5 prefix-list BLOQUEIA-TUDO out' -c 'end' -c 'wr'
      echo "caiu: `date`" >> /root/dnsreport.log
   fi
   exit
fi

habilitado="`vtysh -c 'show run' | grep \"neighbor 192.0.2.5 prefix-list RECURSIVO out\"`"
if [ "$habilitado" == "" ]; then
   vtysh -c 'conf t' -c 'router bgp 65000' -c 'address-family ipv4 unicast' -c 'no neighbor 192.0.2.5 prefix-list BLOQUEIA-TUDO out' -c 'neighbor 192.0.2.5 prefix-list RECURSIVO out' -c 'end' -c 'wr'
   vtysh -c 'conf t' -c 'router bgp 65000' -c 'address-family ipv6 unicast' -c 'no neighbor 2001:db8:aaaa::192:0:2:5 prefix-list BLOQUEIA-TUDO out' -c 'neighbor 2001:db8:aaaa::192:0:2:5 prefix-list RECURSIVO_V6 out' -c 'end' -c 'wr'
   echo "voltou: `date`" >> /root/dnsreport.log
fi

Chegamos ao final deste artigo e espero que tenha sido útil para a comunidade. Lembre-se que temos que pensar no futuro da Internet e é muito importante que usemos IPv6 em todas as nossas implementações de rede, sejam servidores, equipamentos ou aplicações.

Autor: Marcelo Gondim