<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="pt-BR">
	<id>https://wiki.brasilpeeringforum.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Gondim</id>
	<title>Wiki BPF - Contribuições do(a) usuário(a) [pt-br]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.brasilpeeringforum.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Gondim"/>
	<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/w/Especial:Contribui%C3%A7%C3%B5es/Gondim"/>
	<updated>2026-05-30T15:15:14Z</updated>
	<subtitle>Contribuições do(a) usuário(a)</subtitle>
	<generator>MediaWiki 1.35.14</generator>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4099</id>
		<title>Usuário:Gondim</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4099"/>
		<updated>2026-04-28T21:42:19Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Marcelo Gondim da Cunha'''&lt;br /&gt;
[[Arquivo:Gondim perfil2026.png|alt=|esquerda|miniaturadaimagem|252x252px]]&lt;br /&gt;
'''Contribuições e trabalhos:'''&lt;br /&gt;
&lt;br /&gt;
* Administração de Sistemas Unix-Like desde 1996.&lt;br /&gt;
* Consultor na Conectiva S/A - Unidade Rio em 2000.&lt;br /&gt;
** Autor do projeto TuxFrw - https://github.com/gondimcodes/tuxfrw e https://github.com/gondimcodes/tuxfrw-nft&lt;br /&gt;
* Administração de sistemas BSD pela FreeBSD Brasil em 2010.&lt;br /&gt;
* Direção do AS53135 - Nettel Telecomunicações entre 2003 e 2021 atingindo a marca de 41.000 assinantes. Gerando qualidade na entrega de serviços e implantando boas práticas como: &lt;br /&gt;
&lt;br /&gt;
a) IPv6.&lt;br /&gt;
&lt;br /&gt;
b) MANRS.&lt;br /&gt;
&lt;br /&gt;
c) RPKI.&lt;br /&gt;
&lt;br /&gt;
d) CPEs com firmware baseada na BCOP &amp;lt;nowiki&amp;gt;https://www.m3aawg.org/sites/default/files/lac-bcop-1-m3aawg-v1-portuguese-final.pdf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** SOC Specialist na Brasil TecPar (AS262907) de 2022 a 2025. Um milhão de clientes. Responsável pelas estratégias de mitigação anti-DDoS atendendo as Operações de RJ, SP, RS, SC, MT e MS.&lt;br /&gt;
'''Palestras ministradas:'''&lt;br /&gt;
&lt;br /&gt;
* Semana da Informática UERJ 2002 - TuxFrw.&lt;br /&gt;
* CONISLI 2003 - TuxFrw.&lt;br /&gt;
* CONISLI 2004 - Fazendo compras com Gentoo Linux - Palestra sobre a distribuição Linux e suas ferramentas fantásticas.&lt;br /&gt;
* CONISLI 2004 - OpenVPN - Palestra sobre como criar VPNs seguras com OpenVPN e diferenças entre ele e o IPSec.&lt;br /&gt;
* CONISLI 2005 - SPoP (Security Point of Presence) com OpenVPN - Como utilizar túneis encriptados do OpenVPN para acessar a Internet de forma segura, onde quer que esteja.&lt;br /&gt;
* SECOMP 2005 UNIFEI - TuxFrw.&lt;br /&gt;
&lt;br /&gt;
* Debconf19 2019 - [https://debconf19.debconf.org/talks/4-debian-na-vida-de-uma-operadora-de-telecom/ Debian na vida de uma operadora de Telecom], [https://www.youtube.com/watch?v=vQSTslUZy8k&amp;amp;list=PLYUtdmpYPTTJDtwgD8AtxzFJ9t_URhFMK&amp;amp;index=35 vídeo] e [https://salsa.debian.org/debconf-team/public/share/debconf19/raw/master/slides/4-debian-na-vida-de-uma-operadora-de-telecom.pdf?inline=false pdf].&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=5uOFtkplDts FiqueEmCasaUseDebian - CGNAT com NFTables] e [https://www.youtube.com/watch?v=Wz2IAg6MMlU SysAdmin apps].&lt;br /&gt;
&lt;br /&gt;
'''Artigos desenvolvidos para a comunidade do Brasil Peering Fórum:'''&lt;br /&gt;
&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_na_pratica CGNAT na pratica].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Acesso_via_IPv6_Link-Local Acesso via IPv6 Link-Local].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/MANRS MANRS].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_Bulk_Port_Allocation_com_DPDK CGNAT Bulk Port Allocation com DPDK].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Servidor_de_Logs Servidor de Logs].&lt;br /&gt;
* [[DNS Recursivo Anycast Hyperlocal|DNS Anycast com Hyperlocal]].&lt;br /&gt;
* [[Recomendações sobre Mitigação DDoS]]&lt;br /&gt;
* [[Portas de Amplificação DDoS e Botnets]]&lt;br /&gt;
* [[Static Loop - um erro que pode matar seu ISP/ITP]]&lt;br /&gt;
* [[Identificando e neutralizando uma Botnet]]&lt;br /&gt;
&lt;br /&gt;
'''Tutorial:'''&lt;br /&gt;
&lt;br /&gt;
* [https://bit.ly/2saumHK Segurança de roteamento: MANRS (Mutually Agreed Norms for Routing Security) - Tutoriais NIC.br em 09/12/2019].&lt;br /&gt;
&lt;br /&gt;
'''[https://www.manrs.org/about/advisory-group/members/ MANRS Advisory Group Member (2020-2021)]'''.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=oahQkGx8urY '''Live sobre MANRS com Leonardo Furtado'''].&lt;br /&gt;
&lt;br /&gt;
Criação da Wiki ISPUP! em 24/12/2022.&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 6 do NIC.br 28/04/2023''' - &amp;quot;'''CONCEITOS E IMPLEMENTAÇÃO DE CGNAT'''&amp;quot;. Material [https://semanacap.bcp.nic.br/6-online/ aqui] e vídeo aula [https://www.youtube.com/watch?v=1q7J3NkQVSc aqui].&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 10 do NIC.br 01/07/2025''' - &amp;quot;'''Teste para padrões técnicos modernos de Internet e segurança: IPv6, DNSSEC, TLS, HTTPS e HSTS'''&amp;quot;'''.''' Material [https://semanacap.bcp.nic.br/semana-de-capacitacao-online-edicao-10-2025/ aqui] e vídeo aula [https://www.youtube.com/watch?v=55RBnGQhi2o aqui].&lt;br /&gt;
&lt;br /&gt;
'''IX Fórum Regional Sudeste (Rio de Janeiro) 24/10/2025''' com a palestra &amp;quot;'''Segurança com o pé direito'''&amp;quot; pode ser baixada [https://regional.forum.ix.br/files/apresentacao/arquivo/2307/gondim.pdf aqui].&lt;br /&gt;
&lt;br /&gt;
'''Fórum BCOP-ICANN Edição Especial DNS''' com o painel &amp;quot;'''DNS em Ação: Como os provedores estão implantando as Boas Práticas&amp;quot;''' com '''apresentação''' [https://forumbcop.nic.br/files/apresentacao/arquivo/2428/DNS_KINDNS_Reduzido.pdf aqui] e vídeo [https://www.youtube.com/live/GnYK9UOLXr4?t=10257s aqui].&lt;br /&gt;
&lt;br /&gt;
'''Fórum BCOP Fortaleza''' com a palestra: &amp;quot;'''Recomendações de segurança para provedores&amp;quot;''' com apresentação [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2487/Marcelo_Gondim_Recomendacoes_seguranca_provedores.pdf aqui] e vídeo [https://youtu.be/Qjgb7P3cG8k?t=9237 aqui]'''.''' Os arquivos anexos de configuração: [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2489/Marcelo_Gondim_filtros_edge_huawei.pdf filtros_edge_huawei], [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2490/spoofer.pdf spoofer] e [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2491/filtros_bng_huawei.pdf filtros_bng_huawei].  &lt;br /&gt;
&lt;br /&gt;
'''Moeda recebida pelo NIC.br por contribuir com conhecimento palestrando na Semana de Infraestrutura da Internet no Brasil em 2025:'''&lt;br /&gt;
[[Arquivo:Moeda1.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
'''Moeda comemorativa de 5 anos recebida pelo NIC.br em 2025 por contribuir com conhecimento para a Semana de Capacitação e Camada 8:'''&lt;br /&gt;
[[Arquivo:Moeda2.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
'''Moeda IX Fórum Fortaleza 2026:'''&lt;br /&gt;
[[Arquivo:Frum-bcop-fortaleza-2026 55178462504 o.jpg|esquerda|miniaturadaimagem]]&lt;br /&gt;
[[Arquivo:Frum-bcop-fortaleza-2026 55178206816 o.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
'''Webinar:'''&lt;br /&gt;
&lt;br /&gt;
Proteção e Mitigação de ataques DDoS em 10/09/2024 às 20:00 UTC -3. Site da chamada [https://gdg.community.dev/events/details/google-gdg-sinop-presents-webinar-ao-vivo-protecao-e-mitigacao-de-ataques-ddos/ aqui] e o vídeo da live no Youtube [https://www.youtube.com/live/7VIaoDQaLQE aqui].&lt;br /&gt;
&lt;br /&gt;
'''Podcast:'''&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/live/x4fxtma4eyQ Segurança de Rede e Infraestrutura para 2025: Preparando os ISPs para o futuro!]&lt;br /&gt;
&lt;br /&gt;
'''Contatos:'''&lt;br /&gt;
&lt;br /&gt;
Telegram: '''@Marcelo_Gondim'''&lt;br /&gt;
&lt;br /&gt;
WhatsApp: +55 (22) 99743-9060&lt;br /&gt;
&lt;br /&gt;
E-mail: '''gondim at ispup.com.br'''&lt;br /&gt;
&lt;br /&gt;
Linkedin: https://www.linkedin.com/in/marcelo-gondim-sysadmin/&lt;br /&gt;
&lt;br /&gt;
Meu Github: https://github.com/gondimcodes&lt;br /&gt;
&lt;br /&gt;
== Mini-CV ==&lt;br /&gt;
'''Marcelo Gondim''' começou sua carreira como desenvolvedor de software em COBOL e Clipper entre 1992 e 1995. Em 1996 foi responsável por desenvolver um sistema concorrente com o RENPAC da Embratel para acesso ao SISCOMEX e implantou a Internet para fins comerciais na empresa DATABRAS. Trabalhou como consultor e instrutor de GNU/Linux na Conectiva S/A em 2000. Em 2003 se tornou consultor de diversos Provedores de Internet na Região dos Lagos - RJ e onde acabou se tornando CTO da Nettel Telecomunicações (AS53135) com 42.000 assinantes. Implantou IPv6 iniciando em 2013 e se tornou participante do MANRS com diversas contribuições com artigos e palestras. Trabalhou como Especialista em Redes e SOC (Security Operations Center) na Brasil TecPar AS262907 entre 2022 e 2025, onde implementou boas práticas, tratamentos de incidentes relacionados ao ASN, desenvolveu as estratégias de Mitigação DDoS e uma Rede de DNS Recursivo Anycast espalhada pelo RS, RJ, SP, SC MT e MS, também certificada KINDNS. Fundador da empresa ISPFocus especializada em Tecnologia da Informação e boas práticas para ISPs.&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4098</id>
		<title>Usuário:Gondim</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4098"/>
		<updated>2026-04-28T21:41:59Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Marcelo Gondim da Cunha'''&lt;br /&gt;
[[Arquivo:Gondim perfil2026.png|alt=|esquerda|miniaturadaimagem|263x263px]]&lt;br /&gt;
'''Contribuições e trabalhos:'''&lt;br /&gt;
&lt;br /&gt;
* Administração de Sistemas Unix-Like desde 1996.&lt;br /&gt;
* Consultor na Conectiva S/A - Unidade Rio em 2000.&lt;br /&gt;
** Autor do projeto TuxFrw - https://github.com/gondimcodes/tuxfrw e https://github.com/gondimcodes/tuxfrw-nft&lt;br /&gt;
* Administração de sistemas BSD pela FreeBSD Brasil em 2010.&lt;br /&gt;
* Direção do AS53135 - Nettel Telecomunicações entre 2003 e 2021 atingindo a marca de 41.000 assinantes. Gerando qualidade na entrega de serviços e implantando boas práticas como: &lt;br /&gt;
&lt;br /&gt;
a) IPv6.&lt;br /&gt;
&lt;br /&gt;
b) MANRS.&lt;br /&gt;
&lt;br /&gt;
c) RPKI.&lt;br /&gt;
&lt;br /&gt;
d) CPEs com firmware baseada na BCOP &amp;lt;nowiki&amp;gt;https://www.m3aawg.org/sites/default/files/lac-bcop-1-m3aawg-v1-portuguese-final.pdf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** SOC Specialist na Brasil TecPar (AS262907) de 2022 a 2025. Um milhão de clientes. Responsável pelas estratégias de mitigação anti-DDoS atendendo as Operações de RJ, SP, RS, SC, MT e MS.&lt;br /&gt;
'''Palestras ministradas:'''&lt;br /&gt;
&lt;br /&gt;
* Semana da Informática UERJ 2002 - TuxFrw.&lt;br /&gt;
* CONISLI 2003 - TuxFrw.&lt;br /&gt;
* CONISLI 2004 - Fazendo compras com Gentoo Linux - Palestra sobre a distribuição Linux e suas ferramentas fantásticas.&lt;br /&gt;
* CONISLI 2004 - OpenVPN - Palestra sobre como criar VPNs seguras com OpenVPN e diferenças entre ele e o IPSec.&lt;br /&gt;
* CONISLI 2005 - SPoP (Security Point of Presence) com OpenVPN - Como utilizar túneis encriptados do OpenVPN para acessar a Internet de forma segura, onde quer que esteja.&lt;br /&gt;
* SECOMP 2005 UNIFEI - TuxFrw.&lt;br /&gt;
&lt;br /&gt;
* Debconf19 2019 - [https://debconf19.debconf.org/talks/4-debian-na-vida-de-uma-operadora-de-telecom/ Debian na vida de uma operadora de Telecom], [https://www.youtube.com/watch?v=vQSTslUZy8k&amp;amp;list=PLYUtdmpYPTTJDtwgD8AtxzFJ9t_URhFMK&amp;amp;index=35 vídeo] e [https://salsa.debian.org/debconf-team/public/share/debconf19/raw/master/slides/4-debian-na-vida-de-uma-operadora-de-telecom.pdf?inline=false pdf].&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=5uOFtkplDts FiqueEmCasaUseDebian - CGNAT com NFTables] e [https://www.youtube.com/watch?v=Wz2IAg6MMlU SysAdmin apps].&lt;br /&gt;
&lt;br /&gt;
'''Artigos desenvolvidos para a comunidade do Brasil Peering Fórum:'''&lt;br /&gt;
&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_na_pratica CGNAT na pratica].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Acesso_via_IPv6_Link-Local Acesso via IPv6 Link-Local].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/MANRS MANRS].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_Bulk_Port_Allocation_com_DPDK CGNAT Bulk Port Allocation com DPDK].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Servidor_de_Logs Servidor de Logs].&lt;br /&gt;
* [[DNS Recursivo Anycast Hyperlocal|DNS Anycast com Hyperlocal]].&lt;br /&gt;
* [[Recomendações sobre Mitigação DDoS]]&lt;br /&gt;
* [[Portas de Amplificação DDoS e Botnets]]&lt;br /&gt;
* [[Static Loop - um erro que pode matar seu ISP/ITP]]&lt;br /&gt;
* [[Identificando e neutralizando uma Botnet]]&lt;br /&gt;
&lt;br /&gt;
'''Tutorial:'''&lt;br /&gt;
&lt;br /&gt;
* [https://bit.ly/2saumHK Segurança de roteamento: MANRS (Mutually Agreed Norms for Routing Security) - Tutoriais NIC.br em 09/12/2019].&lt;br /&gt;
&lt;br /&gt;
'''[https://www.manrs.org/about/advisory-group/members/ MANRS Advisory Group Member (2020-2021)]'''.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=oahQkGx8urY '''Live sobre MANRS com Leonardo Furtado'''].&lt;br /&gt;
&lt;br /&gt;
Criação da Wiki ISPUP! em 24/12/2022.&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 6 do NIC.br 28/04/2023''' - &amp;quot;'''CONCEITOS E IMPLEMENTAÇÃO DE CGNAT'''&amp;quot;. Material [https://semanacap.bcp.nic.br/6-online/ aqui] e vídeo aula [https://www.youtube.com/watch?v=1q7J3NkQVSc aqui].&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 10 do NIC.br 01/07/2025''' - &amp;quot;'''Teste para padrões técnicos modernos de Internet e segurança: IPv6, DNSSEC, TLS, HTTPS e HSTS'''&amp;quot;'''.''' Material [https://semanacap.bcp.nic.br/semana-de-capacitacao-online-edicao-10-2025/ aqui] e vídeo aula [https://www.youtube.com/watch?v=55RBnGQhi2o aqui].&lt;br /&gt;
&lt;br /&gt;
'''IX Fórum Regional Sudeste (Rio de Janeiro) 24/10/2025''' com a palestra &amp;quot;'''Segurança com o pé direito'''&amp;quot; pode ser baixada [https://regional.forum.ix.br/files/apresentacao/arquivo/2307/gondim.pdf aqui].&lt;br /&gt;
&lt;br /&gt;
'''Fórum BCOP-ICANN Edição Especial DNS''' com o painel &amp;quot;'''DNS em Ação: Como os provedores estão implantando as Boas Práticas&amp;quot;''' com '''apresentação''' [https://forumbcop.nic.br/files/apresentacao/arquivo/2428/DNS_KINDNS_Reduzido.pdf aqui] e vídeo [https://www.youtube.com/live/GnYK9UOLXr4?t=10257s aqui].&lt;br /&gt;
&lt;br /&gt;
'''Fórum BCOP Fortaleza''' com a palestra: &amp;quot;'''Recomendações de segurança para provedores&amp;quot;''' com apresentação [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2487/Marcelo_Gondim_Recomendacoes_seguranca_provedores.pdf aqui] e vídeo [https://youtu.be/Qjgb7P3cG8k?t=9237 aqui]'''.''' Os arquivos anexos de configuração: [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2489/Marcelo_Gondim_filtros_edge_huawei.pdf filtros_edge_huawei], [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2490/spoofer.pdf spoofer] e [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2491/filtros_bng_huawei.pdf filtros_bng_huawei].  &lt;br /&gt;
&lt;br /&gt;
'''Moeda recebida pelo NIC.br por contribuir com conhecimento palestrando na Semana de Infraestrutura da Internet no Brasil em 2025:'''&lt;br /&gt;
[[Arquivo:Moeda1.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
'''Moeda comemorativa de 5 anos recebida pelo NIC.br em 2025 por contribuir com conhecimento para a Semana de Capacitação e Camada 8:'''&lt;br /&gt;
[[Arquivo:Moeda2.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
'''Moeda IX Fórum Fortaleza 2026:'''&lt;br /&gt;
[[Arquivo:Frum-bcop-fortaleza-2026 55178462504 o.jpg|esquerda|miniaturadaimagem]]&lt;br /&gt;
[[Arquivo:Frum-bcop-fortaleza-2026 55178206816 o.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
'''Webinar:'''&lt;br /&gt;
&lt;br /&gt;
Proteção e Mitigação de ataques DDoS em 10/09/2024 às 20:00 UTC -3. Site da chamada [https://gdg.community.dev/events/details/google-gdg-sinop-presents-webinar-ao-vivo-protecao-e-mitigacao-de-ataques-ddos/ aqui] e o vídeo da live no Youtube [https://www.youtube.com/live/7VIaoDQaLQE aqui].&lt;br /&gt;
&lt;br /&gt;
'''Podcast:'''&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/live/x4fxtma4eyQ Segurança de Rede e Infraestrutura para 2025: Preparando os ISPs para o futuro!]&lt;br /&gt;
&lt;br /&gt;
'''Contatos:'''&lt;br /&gt;
&lt;br /&gt;
Telegram: '''@Marcelo_Gondim'''&lt;br /&gt;
&lt;br /&gt;
WhatsApp: +55 (22) 99743-9060&lt;br /&gt;
&lt;br /&gt;
E-mail: '''gondim at ispup.com.br'''&lt;br /&gt;
&lt;br /&gt;
Linkedin: https://www.linkedin.com/in/marcelo-gondim-sysadmin/&lt;br /&gt;
&lt;br /&gt;
Meu Github: https://github.com/gondimcodes&lt;br /&gt;
&lt;br /&gt;
== Mini-CV ==&lt;br /&gt;
'''Marcelo Gondim''' começou sua carreira como desenvolvedor de software em COBOL e Clipper entre 1992 e 1995. Em 1996 foi responsável por desenvolver um sistema concorrente com o RENPAC da Embratel para acesso ao SISCOMEX e implantou a Internet para fins comerciais na empresa DATABRAS. Trabalhou como consultor e instrutor de GNU/Linux na Conectiva S/A em 2000. Em 2003 se tornou consultor de diversos Provedores de Internet na Região dos Lagos - RJ e onde acabou se tornando CTO da Nettel Telecomunicações (AS53135) com 42.000 assinantes. Implantou IPv6 iniciando em 2013 e se tornou participante do MANRS com diversas contribuições com artigos e palestras. Trabalhou como Especialista em Redes e SOC (Security Operations Center) na Brasil TecPar AS262907 entre 2022 e 2025, onde implementou boas práticas, tratamentos de incidentes relacionados ao ASN, desenvolveu as estratégias de Mitigação DDoS e uma Rede de DNS Recursivo Anycast espalhada pelo RS, RJ, SP, SC MT e MS, também certificada KINDNS. Fundador da empresa ISPFocus especializada em Tecnologia da Informação e boas práticas para ISPs.&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4097</id>
		<title>Usuário:Gondim</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4097"/>
		<updated>2026-04-28T21:41:34Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Marcelo Gondim da Cunha'''&lt;br /&gt;
[[Arquivo:Gondim perfil2026.png|alt=|esquerda|miniaturadaimagem|275x275px]]&lt;br /&gt;
'''Contribuições e trabalhos:'''&lt;br /&gt;
&lt;br /&gt;
* Administração de Sistemas Unix-Like desde 1996.&lt;br /&gt;
* Consultor na Conectiva S/A - Unidade Rio em 2000.&lt;br /&gt;
** Autor do projeto TuxFrw - https://github.com/gondimcodes/tuxfrw e https://github.com/gondimcodes/tuxfrw-nft&lt;br /&gt;
* Administração de sistemas BSD pela FreeBSD Brasil em 2010.&lt;br /&gt;
* Direção do AS53135 - Nettel Telecomunicações entre 2003 e 2021 atingindo a marca de 41.000 assinantes. Gerando qualidade na entrega de serviços e implantando boas práticas como: &lt;br /&gt;
&lt;br /&gt;
a) IPv6.&lt;br /&gt;
&lt;br /&gt;
b) MANRS.&lt;br /&gt;
&lt;br /&gt;
c) RPKI.&lt;br /&gt;
&lt;br /&gt;
d) CPEs com firmware baseada na BCOP &amp;lt;nowiki&amp;gt;https://www.m3aawg.org/sites/default/files/lac-bcop-1-m3aawg-v1-portuguese-final.pdf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** SOC Specialist na Brasil TecPar (AS262907) de 2022 a 2025. Um milhão de clientes. Responsável pelas estratégias de mitigação anti-DDoS atendendo as Operações de RJ, SP, RS, SC, MT e MS.&lt;br /&gt;
'''Palestras ministradas:'''&lt;br /&gt;
&lt;br /&gt;
* Semana da Informática UERJ 2002 - TuxFrw.&lt;br /&gt;
* CONISLI 2003 - TuxFrw.&lt;br /&gt;
* CONISLI 2004 - Fazendo compras com Gentoo Linux - Palestra sobre a distribuição Linux e suas ferramentas fantásticas.&lt;br /&gt;
* CONISLI 2004 - OpenVPN - Palestra sobre como criar VPNs seguras com OpenVPN e diferenças entre ele e o IPSec.&lt;br /&gt;
* CONISLI 2005 - SPoP (Security Point of Presence) com OpenVPN - Como utilizar túneis encriptados do OpenVPN para acessar a Internet de forma segura, onde quer que esteja.&lt;br /&gt;
* SECOMP 2005 UNIFEI - TuxFrw.&lt;br /&gt;
&lt;br /&gt;
* Debconf19 2019 - [https://debconf19.debconf.org/talks/4-debian-na-vida-de-uma-operadora-de-telecom/ Debian na vida de uma operadora de Telecom], [https://www.youtube.com/watch?v=vQSTslUZy8k&amp;amp;list=PLYUtdmpYPTTJDtwgD8AtxzFJ9t_URhFMK&amp;amp;index=35 vídeo] e [https://salsa.debian.org/debconf-team/public/share/debconf19/raw/master/slides/4-debian-na-vida-de-uma-operadora-de-telecom.pdf?inline=false pdf].&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=5uOFtkplDts FiqueEmCasaUseDebian - CGNAT com NFTables] e [https://www.youtube.com/watch?v=Wz2IAg6MMlU SysAdmin apps].&lt;br /&gt;
&lt;br /&gt;
'''Artigos desenvolvidos para a comunidade do Brasil Peering Fórum:'''&lt;br /&gt;
&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_na_pratica CGNAT na pratica].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Acesso_via_IPv6_Link-Local Acesso via IPv6 Link-Local].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/MANRS MANRS].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_Bulk_Port_Allocation_com_DPDK CGNAT Bulk Port Allocation com DPDK].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Servidor_de_Logs Servidor de Logs].&lt;br /&gt;
* [[DNS Recursivo Anycast Hyperlocal|DNS Anycast com Hyperlocal]].&lt;br /&gt;
* [[Recomendações sobre Mitigação DDoS]]&lt;br /&gt;
* [[Portas de Amplificação DDoS e Botnets]]&lt;br /&gt;
* [[Static Loop - um erro que pode matar seu ISP/ITP]]&lt;br /&gt;
* [[Identificando e neutralizando uma Botnet]]&lt;br /&gt;
&lt;br /&gt;
'''Tutorial:'''&lt;br /&gt;
&lt;br /&gt;
* [https://bit.ly/2saumHK Segurança de roteamento: MANRS (Mutually Agreed Norms for Routing Security) - Tutoriais NIC.br em 09/12/2019].&lt;br /&gt;
&lt;br /&gt;
'''[https://www.manrs.org/about/advisory-group/members/ MANRS Advisory Group Member (2020-2021)]'''.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=oahQkGx8urY '''Live sobre MANRS com Leonardo Furtado'''].&lt;br /&gt;
&lt;br /&gt;
Criação da Wiki ISPUP! em 24/12/2022.&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 6 do NIC.br 28/04/2023''' - &amp;quot;'''CONCEITOS E IMPLEMENTAÇÃO DE CGNAT'''&amp;quot;. Material [https://semanacap.bcp.nic.br/6-online/ aqui] e vídeo aula [https://www.youtube.com/watch?v=1q7J3NkQVSc aqui].&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 10 do NIC.br 01/07/2025''' - &amp;quot;'''Teste para padrões técnicos modernos de Internet e segurança: IPv6, DNSSEC, TLS, HTTPS e HSTS'''&amp;quot;'''.''' Material [https://semanacap.bcp.nic.br/semana-de-capacitacao-online-edicao-10-2025/ aqui] e vídeo aula [https://www.youtube.com/watch?v=55RBnGQhi2o aqui].&lt;br /&gt;
&lt;br /&gt;
'''IX Fórum Regional Sudeste (Rio de Janeiro) 24/10/2025''' com a palestra &amp;quot;'''Segurança com o pé direito'''&amp;quot; pode ser baixada [https://regional.forum.ix.br/files/apresentacao/arquivo/2307/gondim.pdf aqui].&lt;br /&gt;
&lt;br /&gt;
'''Fórum BCOP-ICANN Edição Especial DNS''' com o painel &amp;quot;'''DNS em Ação: Como os provedores estão implantando as Boas Práticas&amp;quot;''' com '''apresentação''' [https://forumbcop.nic.br/files/apresentacao/arquivo/2428/DNS_KINDNS_Reduzido.pdf aqui] e vídeo [https://www.youtube.com/live/GnYK9UOLXr4?t=10257s aqui].&lt;br /&gt;
&lt;br /&gt;
'''Fórum BCOP Fortaleza''' com a palestra: &amp;quot;'''Recomendações de segurança para provedores&amp;quot;''' com apresentação [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2487/Marcelo_Gondim_Recomendacoes_seguranca_provedores.pdf aqui] e vídeo [https://youtu.be/Qjgb7P3cG8k?t=9237 aqui]'''.''' Os arquivos anexos de configuração: [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2489/Marcelo_Gondim_filtros_edge_huawei.pdf filtros_edge_huawei], [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2490/spoofer.pdf spoofer] e [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2491/filtros_bng_huawei.pdf filtros_bng_huawei].  &lt;br /&gt;
&lt;br /&gt;
'''Moeda recebida pelo NIC.br por contribuir com conhecimento palestrando na Semana de Infraestrutura da Internet no Brasil em 2025:'''&lt;br /&gt;
[[Arquivo:Moeda1.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
'''Moeda comemorativa de 5 anos recebida pelo NIC.br em 2025 por contribuir com conhecimento para a Semana de Capacitação e Camada 8:'''&lt;br /&gt;
[[Arquivo:Moeda2.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
'''Moeda IX Fórum Fortaleza 2026:'''&lt;br /&gt;
[[Arquivo:Frum-bcop-fortaleza-2026 55178462504 o.jpg|esquerda|miniaturadaimagem]]&lt;br /&gt;
[[Arquivo:Frum-bcop-fortaleza-2026 55178206816 o.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
'''Webinar:'''&lt;br /&gt;
&lt;br /&gt;
Proteção e Mitigação de ataques DDoS em 10/09/2024 às 20:00 UTC -3. Site da chamada [https://gdg.community.dev/events/details/google-gdg-sinop-presents-webinar-ao-vivo-protecao-e-mitigacao-de-ataques-ddos/ aqui] e o vídeo da live no Youtube [https://www.youtube.com/live/7VIaoDQaLQE aqui].&lt;br /&gt;
&lt;br /&gt;
'''Podcast:'''&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/live/x4fxtma4eyQ Segurança de Rede e Infraestrutura para 2025: Preparando os ISPs para o futuro!]&lt;br /&gt;
&lt;br /&gt;
'''Contatos:'''&lt;br /&gt;
&lt;br /&gt;
Telegram: '''@Marcelo_Gondim'''&lt;br /&gt;
&lt;br /&gt;
WhatsApp: +55 (22) 99743-9060&lt;br /&gt;
&lt;br /&gt;
E-mail: '''gondim at ispup.com.br'''&lt;br /&gt;
&lt;br /&gt;
Linkedin: https://www.linkedin.com/in/marcelo-gondim-sysadmin/&lt;br /&gt;
&lt;br /&gt;
Meu Github: https://github.com/gondimcodes&lt;br /&gt;
&lt;br /&gt;
== Mini-CV ==&lt;br /&gt;
'''Marcelo Gondim''' começou sua carreira como desenvolvedor de software em COBOL e Clipper entre 1992 e 1995. Em 1996 foi responsável por desenvolver um sistema concorrente com o RENPAC da Embratel para acesso ao SISCOMEX e implantou a Internet para fins comerciais na empresa DATABRAS. Trabalhou como consultor e instrutor de GNU/Linux na Conectiva S/A em 2000. Em 2003 se tornou consultor de diversos Provedores de Internet na Região dos Lagos - RJ e onde acabou se tornando CTO da Nettel Telecomunicações (AS53135) com 42.000 assinantes. Implantou IPv6 iniciando em 2013 e se tornou participante do MANRS com diversas contribuições com artigos e palestras. Trabalhou como Especialista em Redes e SOC (Security Operations Center) na Brasil TecPar AS262907 entre 2022 e 2025, onde implementou boas práticas, tratamentos de incidentes relacionados ao ASN, desenvolveu as estratégias de Mitigação DDoS e uma Rede de DNS Recursivo Anycast espalhada pelo RS, RJ, SP, SC MT e MS, também certificada KINDNS. Fundador da empresa ISPFocus especializada em Tecnologia da Informação e boas práticas para ISPs.&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Gondim_perfil2026.png&amp;diff=4096</id>
		<title>Arquivo:Gondim perfil2026.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Gondim_perfil2026.png&amp;diff=4096"/>
		<updated>2026-04-28T21:41:04Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Gondim_perfil2026&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4095</id>
		<title>Debian Cluster CEPH</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4095"/>
		<updated>2026-04-25T16:31:46Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introdução ==&lt;br /&gt;
Este artigo tem como foco explicar como adicionar um Debian GNU/Linux em um Proxmox Cluster + HA com 2 nodes. Como muitos sabem, um '''Cluster''' deve ser composto de no '''mínimo 3 nodes''' para que possa dar segurança, existir '''quorum''' e quando usamos '''CEPH''' também precisamos de pelo menos 3 nodes com '''OSDs''' para termos uma estabilidade e segurança no sistema. O problema é quando se quer fazer  isso com apenas 2 servidores Proxmox. Comprar um terceiro servidor às vezes ainda não está nos planos mas você tem uma máquina parada, onde você pode adicionar 2 SSDs e com 4G de ram você pode adicionar ela no '''Cluster''' para servir de quorum e de disco '''CEPH'''.  Dessa maneira você consegue com 2 servidores '''Proxmox''' e uma máquina que chamei de '''Quorum Device''', colocar em produção um Cluster com HA funcional.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
O diagrama abaixo será o ambiente de exemplo mas não falaremos de como construir um Cluster + HA com Proxmox. Nesse caso você precisará ter os 2 servidores já instalados e configurados em '''Cluster''' com '''CEPH'''. Aqui vamos apenas mostrar como adicionar um Debian GNU/Linux nesse Cluster e no CEPH.&lt;br /&gt;
[[Arquivo:Diagrama ceph.png|nenhum|miniaturadaimagem|483x483px]]&lt;br /&gt;
&lt;br /&gt;
== Pré-requisitos ==&lt;br /&gt;
&lt;br /&gt;
* Debian GNU/Linux 13 (Trixie).&lt;br /&gt;
* Uma máquina com 4G ou 8G de ram.&lt;br /&gt;
* 1 SSD para instalar o sistema.&lt;br /&gt;
* 1 SSD para servir de '''OSD''' no '''CEPH'''.&lt;br /&gt;
*3 interfaces de rede. Uma para o acesso, outra para o '''Cluster''' e outra para o '''CEPH'''. &lt;br /&gt;
&lt;br /&gt;
== Configurando o Qdevice no Debian ==&lt;br /&gt;
Uma vez instalado o Debian, precisamos configurar as 3 interfaces para a comunicação com seu Cluster Proxmox. Por exemplo:&lt;br /&gt;
&lt;br /&gt;
* ens18 - IP 10.254.254.27/24 GW 10.254.254.1 (essa seria a interface com acesso à Internet para instalar os programas).&lt;br /&gt;
* ens19 - IP 192.168.1.3/24 (interface que deve se comunicar com a rede do Cluster, com os IPs dos nodes 192.168.1.1 e 192.168.1.2.&lt;br /&gt;
* ens20 - IP 192.168.2.3/24 (interface que se comunica com a rede CEPH, com os IPs 192.168.2.1 e 192.168.2.2.&lt;br /&gt;
&lt;br /&gt;
Precisamos configurar o serviço SSHD para permitir conexão com root, pois o Proxmox vai precisar acessar o Debian. Para isso altere o arquivo '''/etc/ssh/sshd_config''' o parâmetro abaixo:&lt;br /&gt;
 PermitRootLogin yes&lt;br /&gt;
Reinicie o serviço:&lt;br /&gt;
 # systemctl restart sshd&lt;br /&gt;
No Debian vamos instalar o pacote '''corosync-qnetd''':&lt;br /&gt;
 # apt install corosync-qnetd&lt;br /&gt;
Nos dois servidores Proxmox, no nosso exemplo PVE01 e PVE02 instalaremos o pacote '''corosync-qdevice''':&lt;br /&gt;
 # apt install corosync-qdevice&lt;br /&gt;
Agora vá para o shell do seu '''Proxmox principal''', no meu caso o '''PVE01''' e adicione o Debian ao Cluster com o seguinte comando: &lt;br /&gt;
 # pvecm qdevice setup 192.168.1.3&lt;br /&gt;
Com o comando '''pvecm status''' podemos ver como está o quorum e se tudo ocorreu bem, verá que agora temos 3 votos no lugar de 2 e um '''Qdevice''' no membership:&lt;br /&gt;
[[Arquivo:Qdevice.png|nenhum|miniaturadaimagem|748x748px]]&lt;br /&gt;
Agora em se tratando de Cluster, você tem o mínimo de votantes para o bom funcionamento e usando uma máquina simples com Debian.&lt;br /&gt;
&lt;br /&gt;
== Adicionando um CEPH monitor e OSD ==&lt;br /&gt;
Agora precisamos tornar nosso '''CEPH''' saudável também e para isso vamos instalar os pacotes do CEPH do Proxmox no Debian. O CEPH precisa ser da mesma versão usada no Cluster Proxmox. Para os meus testes utilizei um '''Cluster Proxmox 9''' no '''PVE01''' e '''PVE02''' que utiliza o '''CEPH Squid 19.2'''. Então vamos adicionar o repositório:&lt;br /&gt;
 # echo &amp;quot;deb &amp;lt;nowiki&amp;gt;http://download.proxmox.com/debian/ceph-squid&amp;lt;/nowiki&amp;gt; trixie no-subscription&amp;quot; &amp;gt; /etc/apt/sources.list.d/ceph.list&lt;br /&gt;
 # wget &amp;lt;nowiki&amp;gt;https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg&amp;lt;/nowiki&amp;gt; -O /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg&lt;br /&gt;
Instalando os pacotes do CEPH:&lt;br /&gt;
 # apt update&lt;br /&gt;
 # apt install ceph ceph-common&lt;br /&gt;
Antes de prosseguir adicione no '''/etc/hosts''' do Debian:&lt;br /&gt;
 192.168.2.1 node1&lt;br /&gt;
 192.168.2.2 node2&lt;br /&gt;
 192.168.2.3 nodeq&lt;br /&gt;
Estou chamando nosso '''Quorum Device''' com o hostname '''nodeq'''.&lt;br /&gt;
&lt;br /&gt;
Agora precisaremos executar algumas tarefas no nosso '''PVE01''':&lt;br /&gt;
 # ceph mon getmap -o /tmp/monmap&lt;br /&gt;
 &lt;br /&gt;
 # monmaptool \&lt;br /&gt;
   --add nodeq 192.168.2.3:6789 \&lt;br /&gt;
   /tmp/monmap&lt;br /&gt;
Vamos checar se adicionamos o '''nodeq''' ao '''monmap''' com o comando: '''monmaptool --print /tmp/monmap'''&lt;br /&gt;
[[Arquivo:Monmap.png|nenhum|miniaturadaimagem|722x722px]]&lt;br /&gt;
Vamos gerar o '''keyring''' para usarmos no Debian:&lt;br /&gt;
 # ceph auth get mon. -o /tmp/ceph.mon.keyring&lt;br /&gt;
Agora precisamos copiar todos os arquivos necessários do '''PVE01''' para o nosso Debian:&lt;br /&gt;
 # scp /tmp/monmap root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /tmp/ceph.mon.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/ceph.conf root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/priv/ceph.client.admin.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 &lt;br /&gt;
 # scp /var/lib/ceph/bootstrap-osd/ceph.keyring \&lt;br /&gt;
 root@192.168.2.3:/var/lib/ceph/bootstrap-osd/&lt;br /&gt;
'''Atenção''' '''agora''' pois vamos no nosso Debian alterar o arquivo '''/etc/ceph/ceph.conf'''. Primeiro modifique  o parâmetro abaixo para incluir o IP '''192.168.2.3''':&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
Modifique os dois parâmetros abaixo e deixe eles iguais a estes:&amp;lt;pre&amp;gt;&lt;br /&gt;
[client]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&lt;br /&gt;
[client.crash]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&amp;lt;/pre&amp;gt;Adicione no final deste mesmo arquivo a configuração abaixo:&amp;lt;pre&amp;gt;&lt;br /&gt;
[mon.nodeq]&lt;br /&gt;
	public_addr = 192.168.2.3&lt;br /&gt;
&amp;lt;/pre&amp;gt;Ainda no '''Debian''' execute os comandos abaixo para prepararmos o ambiente pro '''CEPH''':&lt;br /&gt;
 # mkdir -p /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown ceph:ceph /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chmod 750 /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
Vamos criar o monitor:&lt;br /&gt;
 # ceph-mon --mkfs \&lt;br /&gt;
 -i nodeq \&lt;br /&gt;
 --monmap /etc/ceph/monmap \&lt;br /&gt;
 --keyring /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 &lt;br /&gt;
 # chown -R ceph: /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown -R ceph: /etc/ceph/&lt;br /&gt;
 # chmod 640 /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 # chmod 640 /etc/ceph/monmap&lt;br /&gt;
Este é o momento crucial para que tenhamos mais um monitor no nosso CEPH do Proxmox:&lt;br /&gt;
 # systemctl enable ceph-mon@nodeq&lt;br /&gt;
 # systemctl start ceph-mon@nodeq&lt;br /&gt;
Precisamos checar se o serviço subiu com o comando: '''systemctl status ceph-mon@nodeq'''&lt;br /&gt;
&lt;br /&gt;
Se aparecer algo assim então parabéns, até aqui foi tudo OK:&lt;br /&gt;
[[Arquivo:Nodeq ceph.png|nenhum|miniaturadaimagem|894x894px]]&lt;br /&gt;
Volte no Proxmox PVE01 e altere o '''/etc/pve/ceph.conf''' modificando para:&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
E adicionando no final do arquivo:&lt;br /&gt;
 [mon.nodeq]&lt;br /&gt;
         public_addr = 192.168.2.3&lt;br /&gt;
Agora ativamos, ainda no '''Proxmox PVE01''', o '''msgr2''':&lt;br /&gt;
 # ceph mon enable-msgr2&lt;br /&gt;
No Debian reinicie o serviço:&lt;br /&gt;
 # systemctl restart ceph-mon@nodeq&lt;br /&gt;
No '''Proxmox''' em '''CEPH''' verá um novo Monitor adicionado:&lt;br /&gt;
[[Arquivo:Mon ceph.png|nenhum|miniaturadaimagem|598x598px]]&lt;br /&gt;
&lt;br /&gt;
== Adicionando o OSD no Debian ==&lt;br /&gt;
Agora vamos aos procedimentos para usarmos aquele SSD como OSD no CEPH. Vamos supor que o '''SSD livre''' seja o '''/dev/sdb''':&lt;br /&gt;
 # apt install gdisk util-linux&lt;br /&gt;
 &lt;br /&gt;
 # wipefs -a /dev/sdb&lt;br /&gt;
 # sgdisk --zap-all /dev/sdb&lt;br /&gt;
&lt;br /&gt;
Feito isso só precisamos criar o volume CEPH com o comando:&lt;br /&gt;
 # ceph-volume lvm create --data /dev/sdb&lt;br /&gt;
Se tudo foi bem, nesse momento verá o '''OSD''' no seu '''Cluster Proxmox''':&lt;br /&gt;
[[Arquivo:Proxmox osd.png|nenhum|miniaturadaimagem|1234x1234px]]&lt;br /&gt;
Olhando a saúde do nosso Cluster veremos:&lt;br /&gt;
[[Arquivo:Proxmox osd2.png|nenhum|miniaturadaimagem|1235x1235px]]&lt;br /&gt;
&lt;br /&gt;
== Conclusão ==&lt;br /&gt;
Aqui vemos em funcionamento um '''Cluster Proxmox + HA''' com 2 nós apenas e uma máquina Debian servindo como apoio no funcionamento e segurança do Cluster.&lt;br /&gt;
&lt;br /&gt;
Gostou do artigo? Compartilhe!&lt;br /&gt;
&lt;br /&gt;
Autor: [[Usuário:Gondim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Infraestrutura]]&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4094</id>
		<title>Debian Cluster CEPH</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4094"/>
		<updated>2026-04-25T16:29:45Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introdução ==&lt;br /&gt;
Este artigo tem como foco explicar como adicionar um Debian GNU/Linux em um Proxmox Cluster + HA com 2 nodes. Como muitos sabem, um '''Cluster''' deve ser composto de no '''mínimo 3 nodes''' para que possa dar segurança, existir '''quorum''' e quando usamos '''CEPH''' também precisamos de pelo menos 3 nodes com '''OSDs''' para termos uma estabilidade e segurança no sistema. O problema é quando se quer fazer  isso com apenas 2 servidores Proxmox. Comprar um terceiro servidor às vezes ainda não está nos planos mas você tem uma máquina parada, onde você pode adicionar 2 SSDs e com 4G de ram você pode adicionar ela no '''Cluster''' para servir de quorum e de disco '''CEPH'''.  Dessa maneira você consegue com 2 servidores '''Proxmox''' e uma máquina que chamei de '''Quorum Device''', colocar em produção um Cluster com HA funcional.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
O diagrama abaixo será o ambiente de exemplo mas não falaremos de como construir um Cluster + HA com Proxmox. Nesse caso você precisará ter os 2 servidores já instalados e configurados em '''Cluster''' com '''CEPH'''. Aqui vamos apenas mostrar como adicionar um Debian GNU/Linux nesse Cluster e no CEPH.&lt;br /&gt;
[[Arquivo:Diagrama ceph.png|nenhum|miniaturadaimagem|483x483px]]&lt;br /&gt;
&lt;br /&gt;
== Pré-requisitos ==&lt;br /&gt;
&lt;br /&gt;
* Debian GNU/Linux 13 (Trixie).&lt;br /&gt;
* Uma máquina com 4G ou 8G de ram.&lt;br /&gt;
* 1 SSD para instalar o sistema.&lt;br /&gt;
* 1 SSD para servir de '''OSD''' no '''CEPH'''.&lt;br /&gt;
*3 interfaces de rede. Uma para o acesso, outra para o '''Cluster''' e outra para o '''CEPH'''. &lt;br /&gt;
&lt;br /&gt;
== Configurando o Qdevice no Debian ==&lt;br /&gt;
Uma vez instalado o Debian, precisamos configurar as 3 interfaces para a comunicação com seu Cluster Proxmox. Por exemplo:&lt;br /&gt;
&lt;br /&gt;
* ens18 - IP 10.254.254.27/24 GW 10.254.254.1 (essa seria a interface com acesso à Internet para instalar os programas).&lt;br /&gt;
* ens19 - IP 192.168.1.3/24 (interface que deve se comunicar com a rede do Cluster, com os IPs dos nodes 192.168.1.1 e 192.168.1.2.&lt;br /&gt;
* ens20 - IP 192.168.2.3/24 (interface que se comunica com a rede CEPH, com os IPs 192.168.2.1 e 192.168.2.2.&lt;br /&gt;
&lt;br /&gt;
Precisamos configurar o serviço SSHD para permitir conexão com root, pois o Proxmox vai precisar acessar o Debian. Para isso altere o arquivo '''/etc/ssh/sshd_config''' o parâmetro abaixo:&lt;br /&gt;
 PermitRootLogin yes&lt;br /&gt;
Reinicie o serviço:&lt;br /&gt;
 # systemctl restart sshd&lt;br /&gt;
No Debian vamos instalar o pacote '''corosync-qnetd''':&lt;br /&gt;
 # apt install corosync-qnetd&lt;br /&gt;
Nos dois servidores Proxmox, no nosso exemplo PVE01 e PVE02 instalaremos o pacote '''corosync-qdevice''':&lt;br /&gt;
 # apt install corosync-qdevice&lt;br /&gt;
Agora vá para o shell do seu '''Proxmox principal''', no meu caso o '''PVE01''' e adicione o Debian ao Cluster com o seguinte comando: &lt;br /&gt;
 # pvecm qdevice setup 192.168.1.3&lt;br /&gt;
Com o comando '''pvecm status''' podemos ver como está o quorum e se tudo ocorreu bem, verá que agora temos 3 votos no lugar de 2 e um '''Qdevice''' no membership:&lt;br /&gt;
[[Arquivo:Qdevice.png|nenhum|miniaturadaimagem|748x748px]]&lt;br /&gt;
Agora em se tratando de Cluster, você tem o mínimo de votantes para o bom funcionamento e usando uma máquina simples com Debian.&lt;br /&gt;
&lt;br /&gt;
== Adicionando um CEPH monitor e OSD ==&lt;br /&gt;
Agora precisamos tornar nosso '''CEPH''' saudável também e para isso vamos instalar os pacotes do CEPH do Proxmox no Debian. O CEPH precisa ser da mesma versão usada no Cluster Proxmox. Para os meus testes utilizei um '''Cluster Proxmox 9''' no '''PVE01''' e '''PVE02''' que utiliza o '''CEPH Squid 19.2'''. Então vamos adicionar o repositório:&lt;br /&gt;
 # echo &amp;quot;deb &amp;lt;nowiki&amp;gt;http://download.proxmox.com/debian/ceph-squid&amp;lt;/nowiki&amp;gt; trixie no-subscription&amp;quot; &amp;gt; /etc/apt/sources.list.d/ceph.list&lt;br /&gt;
 # wget &amp;lt;nowiki&amp;gt;https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg&amp;lt;/nowiki&amp;gt; -O /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg&lt;br /&gt;
Instalando os pacotes do CEPH:&lt;br /&gt;
 # apt update&lt;br /&gt;
 # apt install ceph ceph-common&lt;br /&gt;
Antes de prosseguir adicione no '''/etc/hosts''' do Debian:&lt;br /&gt;
 192.168.2.1 node1&lt;br /&gt;
 192.168.2.2 node2&lt;br /&gt;
 192.168.2.3 nodeq&lt;br /&gt;
Estou chamando nosso '''Quorum Device''' com o hostname '''nodeq'''.&lt;br /&gt;
&lt;br /&gt;
Agora precisaremos executar algumas tarefas no nosso '''PVE01''':&lt;br /&gt;
 # ceph mon getmap -o /tmp/monmap&lt;br /&gt;
 &lt;br /&gt;
 # monmaptool \&lt;br /&gt;
   --add nodeq 192.168.2.3:6789 \&lt;br /&gt;
   /tmp/monmap&lt;br /&gt;
Vamos checar se adicionamos o '''nodeq''' ao '''monmap''' com o comando: '''monmaptool --print /tmp/monmap'''&lt;br /&gt;
[[Arquivo:Monmap.png|nenhum|miniaturadaimagem|722x722px]]&lt;br /&gt;
Vamos gerar o '''keyring''' para usarmos no Debian:&lt;br /&gt;
 # ceph auth get mon. -o /tmp/ceph.mon.keyring&lt;br /&gt;
Agora precisamos copiar todos os arquivos necessários do '''PVE01''' para o nosso Debian:&lt;br /&gt;
 # scp /tmp/monmap root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /tmp/ceph.mon.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/ceph.conf root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/priv/ceph.client.admin.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 &lt;br /&gt;
 # scp /var/lib/ceph/bootstrap-osd/ceph.keyring \&lt;br /&gt;
 root@192.168.2.3:/var/lib/ceph/bootstrap-osd/&lt;br /&gt;
'''Atenção''' '''agora''' pois vamos no nosso Debian alterar o arquivo '''/etc/ceph/ceph.conf'''. Primeiro modifique  o parâmetro abaixo para incluir o IP '''192.168.2.3''':&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
Modifique os dois parâmetros abaixo e deixe eles iguais a estes:&amp;lt;pre&amp;gt;&lt;br /&gt;
[client]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&lt;br /&gt;
[client.crash]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&amp;lt;/pre&amp;gt;Adicione no final deste mesmo arquivo a configuração abaixo:&amp;lt;pre&amp;gt;&lt;br /&gt;
[mon.nodeq]&lt;br /&gt;
	public_addr = 192.168.2.3&lt;br /&gt;
&amp;lt;/pre&amp;gt;Ainda no '''Debian''' execute os comandos abaixo para prepararmos o ambiente pro '''CEPH''':&lt;br /&gt;
 # mkdir -p /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown ceph:ceph /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chmod 750 /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
Vamos criar o monitor:&lt;br /&gt;
 # ceph-mon --mkfs \&lt;br /&gt;
 -i nodeq \&lt;br /&gt;
 --monmap /etc/ceph/monmap \&lt;br /&gt;
 --keyring /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 &lt;br /&gt;
 # chown -R ceph: /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown -R ceph: /etc/ceph/&lt;br /&gt;
 # chmod 640 /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 # chmod 640 /etc/ceph/monmap&lt;br /&gt;
Este é o momento crucial para que tenhamos mais um monitor no nosso CEPH do Proxmox:&lt;br /&gt;
 # systemctl enable ceph-mon@nodeq&lt;br /&gt;
 # systemctl start ceph-mon@nodeq&lt;br /&gt;
Precisamos checar se o serviço subiu com o comando: '''systemctl status ceph-mon@nodeq'''&lt;br /&gt;
&lt;br /&gt;
Se aparecer algo assim então parabéns, até aqui foi tudo OK:&lt;br /&gt;
[[Arquivo:Nodeq ceph.png|nenhum|miniaturadaimagem|894x894px]]&lt;br /&gt;
Volte no Proxmox PVE01 e altere o '''/etc/pve/ceph.conf''' modificando para:&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
E adicionando no final do arquivo:&lt;br /&gt;
 [mon.nodeq]&lt;br /&gt;
         public_addr = 192.168.2.3&lt;br /&gt;
Agora ativamos, ainda no '''Proxmox PVE01''', o '''msgr2''':&lt;br /&gt;
 # ceph mon enable-msgr2&lt;br /&gt;
No Debian reinicie o serviço:&lt;br /&gt;
 # systemctl restart ceph-mon@nodeq&lt;br /&gt;
No '''Proxmox''' em '''CEPH''' verá um novo Monitor adicionado:&lt;br /&gt;
[[Arquivo:Mon ceph.png|nenhum|miniaturadaimagem|598x598px]]&lt;br /&gt;
&lt;br /&gt;
== Adicionando o OSD no Debian ==&lt;br /&gt;
Agora vamos aos procedimentos para usarmos aquele SSD como OSD no CEPH. Vamos supor que o '''SSD livre''' seja o '''/dev/sdb''':&lt;br /&gt;
 # apt install gdisk util-linux&lt;br /&gt;
 &lt;br /&gt;
 # wipefs -a /dev/sdb&lt;br /&gt;
 # sgdisk --zap-all /dev/sdb&lt;br /&gt;
&lt;br /&gt;
Feito isso só precisamos criar o volume CEPH com o comando:&lt;br /&gt;
 # ceph-volume lvm create --data /dev/sdb&lt;br /&gt;
Se tudo foi bem, nesse momento verá o '''OSD''' no seu '''Cluster Proxmox''':&lt;br /&gt;
[[Arquivo:Proxmox osd.png|nenhum|miniaturadaimagem|1234x1234px]]&lt;br /&gt;
Olhando a saúde do nosso Cluster veremos:&lt;br /&gt;
[[Arquivo:Proxmox osd2.png|nenhum|miniaturadaimagem|1235x1235px]]&lt;br /&gt;
&lt;br /&gt;
== Conclusão ==&lt;br /&gt;
Aqui vemos em funcionamento um '''Cluster Proxmox + HA''' com 2 nós apenas e uma máquina Debian servindo como apoio no funcionamento e segurança do Cluster.&lt;br /&gt;
&lt;br /&gt;
Gostou do artigo? Compartilhe!&lt;br /&gt;
&lt;br /&gt;
Autor: [[Usuário:Gondim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Artigos Técnicos]]&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4093</id>
		<title>Debian Cluster CEPH</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4093"/>
		<updated>2026-04-25T16:11:30Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introdução ==&lt;br /&gt;
Este artigo tem como foco explicar como adicionar um Debian GNU/Linux em um Proxmox Cluster + HA com 2 nodes. Como muitos sabem, um '''Cluster''' deve ser composto de no '''mínimo 3 nodes''' para que possa dar segurança, existir '''quorum''' e quando usamos '''CEPH''' também precisamos de pelo menos 3 nodes com '''OSDs''' para termos uma estabilidade e segurança no sistema. O problema é quando se quer fazer  isso com apenas 2 servidores Proxmox. Comprar um terceiro servidor às vezes ainda não está nos planos mas você tem uma máquina parada, onde você pode adicionar 2 SSDs e com 4G de ram você pode adicionar ela no '''Cluster''' para servir de quorum e de disco '''CEPH'''.  Dessa maneira você consegue com 2 servidores '''Proxmox''' e uma máquina que chamei de '''Quorum Device''', colocar em produção um Cluster com HA funcional.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
O diagrama abaixo será o ambiente de exemplo mas não falaremos de como construir um Cluster + HA com Proxmox. Nesse caso você precisará ter os 2 servidores já instalados e configurados em '''Cluster''' com '''CEPH'''. Aqui vamos apenas mostrar como adicionar um Debian GNU/Linux nesse Cluster e no CEPH.&lt;br /&gt;
[[Arquivo:Diagrama ceph.png|nenhum|miniaturadaimagem|483x483px]]&lt;br /&gt;
&lt;br /&gt;
== Pré-requisitos ==&lt;br /&gt;
&lt;br /&gt;
* Debian GNU/Linux 13 (Trixie).&lt;br /&gt;
* Uma máquina com 4G ou 8G de ram.&lt;br /&gt;
* 1 SSD para instalar o sistema.&lt;br /&gt;
* 1 SSD para servir de '''OSD''' no '''CEPH'''.&lt;br /&gt;
*3 interfaces de rede. Uma para o acesso, outra para o '''Cluster''' e outra para o '''CEPH'''. &lt;br /&gt;
&lt;br /&gt;
== Configurando o Qdevice no Debian ==&lt;br /&gt;
Uma vez instalado o Debian, precisamos configurar as 3 interfaces para a comunicação com seu Cluster Proxmox. Por exemplo:&lt;br /&gt;
&lt;br /&gt;
* ens18 - IP 10.254.254.27/24 GW 10.254.254.1 (essa seria a interface com acesso à Internet para instalar os programas).&lt;br /&gt;
* ens19 - IP 192.168.1.3/24 (interface que deve se comunicar com a rede do Cluster, com os IPs dos nodes 192.168.1.1 e 192.168.1.2.&lt;br /&gt;
* ens20 - IP 192.168.2.3/24 (interface que se comunica com a rede CEPH, com os IPs 192.168.2.1 e 192.168.2.2.&lt;br /&gt;
&lt;br /&gt;
Precisamos configurar o serviço SSHD para permitir conexão com root, pois o Proxmox vai precisar acessar o Debian. Para isso altere o arquivo '''/etc/ssh/sshd_config''' o parâmetro abaixo:&lt;br /&gt;
 PermitRootLogin yes&lt;br /&gt;
Reinicie o serviço:&lt;br /&gt;
 # systemctl restart sshd&lt;br /&gt;
No Debian vamos instalar o pacote '''corosync-qnetd''':&lt;br /&gt;
 # apt install corosync-qnetd&lt;br /&gt;
Nos dois servidores Proxmox, no nosso exemplo PVE01 e PVE02 instalaremos o pacote '''corosync-qdevice''':&lt;br /&gt;
 # apt install corosync-qdevice&lt;br /&gt;
Agora vá para o shell do seu '''Proxmox principal''', no meu caso o '''PVE01''' e adicione o Debian ao Cluster com o seguinte comando: &lt;br /&gt;
 # pvecm qdevice setup 192.168.1.3&lt;br /&gt;
Com o comando '''pvecm status''' podemos ver como está o quorum e se tudo ocorreu bem, verá que agora temos 3 votos no lugar de 2 e um '''Qdevice''' no membership:&lt;br /&gt;
[[Arquivo:Qdevice.png|nenhum|miniaturadaimagem|748x748px]]&lt;br /&gt;
Agora em se tratando de Cluster, você tem o mínimo de votantes para o bom funcionamento e usando uma máquina simples com Debian.&lt;br /&gt;
&lt;br /&gt;
== Adicionando um CEPH monitor e OSD ==&lt;br /&gt;
Agora precisamos tornar nosso '''CEPH''' saudável também e para isso vamos instalar os pacotes do CEPH do Proxmox no Debian. O CEPH precisa ser da mesma versão usada no Cluster Proxmox. Para os meus testes utilizei um '''Cluster Proxmox 9''' no '''PVE01''' e '''PVE02''' que utiliza o '''CEPH Squid 19.2'''. Então vamos adicionar o repositório:&lt;br /&gt;
 # echo &amp;quot;deb &amp;lt;nowiki&amp;gt;http://download.proxmox.com/debian/ceph-squid&amp;lt;/nowiki&amp;gt; trixie no-subscription&amp;quot; &amp;gt; /etc/apt/sources.list.d/ceph.list&lt;br /&gt;
 # wget &amp;lt;nowiki&amp;gt;https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg&amp;lt;/nowiki&amp;gt; -O /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg&lt;br /&gt;
Instalando os pacotes do CEPH:&lt;br /&gt;
 # apt update&lt;br /&gt;
 # apt install ceph ceph-common&lt;br /&gt;
Antes de prosseguir adicione no '''/etc/hosts''' do Debian:&lt;br /&gt;
 192.168.2.1 node1&lt;br /&gt;
 192.168.2.2 node2&lt;br /&gt;
 192.168.2.3 nodeq&lt;br /&gt;
Estou chamando nosso '''Quorum Device''' com o hostname '''nodeq'''.&lt;br /&gt;
&lt;br /&gt;
Agora precisaremos executar algumas tarefas no nosso '''PVE01''':&lt;br /&gt;
 # ceph mon getmap -o /tmp/monmap&lt;br /&gt;
 &lt;br /&gt;
 # monmaptool \&lt;br /&gt;
   --add nodeq 192.168.2.3:6789 \&lt;br /&gt;
   /tmp/monmap&lt;br /&gt;
Vamos checar se adicionamos o '''nodeq''' ao '''monmap''' com o comando: '''monmaptool --print /tmp/monmap'''&lt;br /&gt;
[[Arquivo:Monmap.png|nenhum|miniaturadaimagem|722x722px]]&lt;br /&gt;
Vamos gerar o '''keyring''' para usarmos no Debian:&lt;br /&gt;
 # ceph auth get mon. -o /tmp/ceph.mon.keyring&lt;br /&gt;
Agora precisamos copiar todos os arquivos necessários do '''PVE01''' para o nosso Debian:&lt;br /&gt;
 # scp /tmp/monmap root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /tmp/ceph.mon.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/ceph.conf root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/priv/ceph.client.admin.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 &lt;br /&gt;
 # scp /var/lib/ceph/bootstrap-osd/ceph.keyring \&lt;br /&gt;
 root@192.168.2.3:/var/lib/ceph/bootstrap-osd/&lt;br /&gt;
'''Atenção''' '''agora''' pois vamos no nosso Debian alterar o arquivo '''/etc/ceph/ceph.conf'''. Primeiro modifique  o parâmetro abaixo para incluir o IP '''192.168.2.3''':&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
Modifique os dois parâmetros abaixo e deixe eles iguais a estes:&amp;lt;pre&amp;gt;&lt;br /&gt;
[client]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&lt;br /&gt;
[client.crash]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&amp;lt;/pre&amp;gt;Adicione no final deste mesmo arquivo a configuração abaixo:&amp;lt;pre&amp;gt;&lt;br /&gt;
[mon.nodeq]&lt;br /&gt;
	public_addr = 192.168.2.3&lt;br /&gt;
&amp;lt;/pre&amp;gt;Ainda no '''Debian''' execute os comandos abaixo para prepararmos o ambiente pro '''CEPH''':&lt;br /&gt;
 # mkdir -p /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown ceph:ceph /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chmod 750 /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
Vamos criar o monitor:&lt;br /&gt;
 # ceph-mon --mkfs \&lt;br /&gt;
 -i nodeq \&lt;br /&gt;
 --monmap /etc/ceph/monmap \&lt;br /&gt;
 --keyring /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 &lt;br /&gt;
 # chown -R ceph: /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown -R ceph: /etc/ceph/&lt;br /&gt;
 # chmod 640 /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 # chmod 640 /etc/ceph/monmap&lt;br /&gt;
Este é o momento crucial para que tenhamos mais um monitor no nosso CEPH do Proxmox:&lt;br /&gt;
 # systemctl enable ceph-mon@nodeq&lt;br /&gt;
 # systemctl start ceph-mon@nodeq&lt;br /&gt;
Precisamos checar se o serviço subiu com o comando: '''systemctl status ceph-mon@nodeq'''&lt;br /&gt;
&lt;br /&gt;
Se aparecer algo assim então parabéns, até aqui foi tudo OK:&lt;br /&gt;
[[Arquivo:Nodeq ceph.png|nenhum|miniaturadaimagem|894x894px]]&lt;br /&gt;
Volte no Proxmox PVE01 e altere o '''/etc/pve/ceph.conf''' modificando para:&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
E adicionando no final do arquivo:&lt;br /&gt;
 [mon.nodeq]&lt;br /&gt;
         public_addr = 192.168.2.3&lt;br /&gt;
Agora ativamos, ainda no '''Proxmox PVE01''', o '''msgr2''':&lt;br /&gt;
 # ceph mon enable-msgr2&lt;br /&gt;
No Debian reinicie o serviço:&lt;br /&gt;
 # systemctl restart ceph-mon@nodeq&lt;br /&gt;
No '''Proxmox''' em '''CEPH''' verá um novo Monitor adicionado:&lt;br /&gt;
[[Arquivo:Mon ceph.png|nenhum|miniaturadaimagem|598x598px]]&lt;br /&gt;
&lt;br /&gt;
== Adicionando o OSD no Debian ==&lt;br /&gt;
Agora vamos aos procedimentos para usarmos aquele SSD como OSD no CEPH. Vamos supor que o '''SSD livre''' seja o '''/dev/sdb''':&lt;br /&gt;
 # apt install gdisk util-linux&lt;br /&gt;
 &lt;br /&gt;
 # wipefs -a /dev/sdb&lt;br /&gt;
 # sgdisk --zap-all /dev/sdb&lt;br /&gt;
&lt;br /&gt;
Feito isso só precisamos criar o volume CEPH com o comando:&lt;br /&gt;
 # ceph-volume lvm create --data /dev/sdb&lt;br /&gt;
Se tudo foi bem, nesse momento verá o '''OSD''' no seu '''Cluster Proxmox''':&lt;br /&gt;
[[Arquivo:Proxmox osd.png|nenhum|miniaturadaimagem|1234x1234px]]&lt;br /&gt;
Olhando a saúde do nosso Cluster veremos:&lt;br /&gt;
[[Arquivo:Proxmox osd2.png|nenhum|miniaturadaimagem|1235x1235px]]&lt;br /&gt;
&lt;br /&gt;
== Conclusão ==&lt;br /&gt;
Aqui vemos em funcionamento um '''Cluster Proxmox + HA''' com 2 nós apenas e uma máquina Debian servindo como apoio no funcionamento e segurança do Cluster.&lt;br /&gt;
&lt;br /&gt;
Gostou do artigo? Compartilhe!&lt;br /&gt;
&lt;br /&gt;
Autor: [[Sobre mim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Artigos Técnicos]]&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Proxmox_osd2.png&amp;diff=4092</id>
		<title>Arquivo:Proxmox osd2.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Proxmox_osd2.png&amp;diff=4092"/>
		<updated>2026-04-25T16:10:55Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;proxmox_osd2&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Proxmox_osd.png&amp;diff=4091</id>
		<title>Arquivo:Proxmox osd.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Proxmox_osd.png&amp;diff=4091"/>
		<updated>2026-04-25T16:09:00Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;proxmox_osd&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4090</id>
		<title>Debian Cluster CEPH</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4090"/>
		<updated>2026-04-25T16:08:05Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introdução ==&lt;br /&gt;
Este artigo tem como foco explicar como adicionar um Debian GNU/Linux em um Proxmox Cluster + HA com 2 nodes. Como muitos sabem, um '''Cluster''' deve ser composto de no '''mínimo 3 nodes''' para que possa dar segurança, existir '''quorum''' e quando usamos '''CEPH''' também precisamos de pelo menos 3 nodes com '''OSDs''' para termos uma estabilidade e segurança no sistema. O problema é quando se quer fazer  isso com apenas 2 servidores Proxmox. Comprar um terceiro servidor às vezes ainda não está nos planos mas você tem uma máquina parada, onde você pode adicionar 2 SSDs e com 4G de ram você pode adicionar ela no '''Cluster''' para servir de quorum e de disco '''CEPH'''.  Dessa maneira você consegue com 2 servidores '''Proxmox''' e uma máquina que chamei de '''Quorum Device''', colocar em produção um Cluster com HA funcional.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
O diagrama abaixo será o ambiente de exemplo mas não falaremos de como construir um Cluster + HA com Proxmox. Nesse caso você precisará ter os 2 servidores já instalados e configurados em '''Cluster''' com '''CEPH'''. Aqui vamos apenas mostrar como adicionar um Debian GNU/Linux nesse Cluster e no CEPH.&lt;br /&gt;
[[Arquivo:Diagrama ceph.png|nenhum|miniaturadaimagem|483x483px]]&lt;br /&gt;
&lt;br /&gt;
== Pré-requisitos ==&lt;br /&gt;
&lt;br /&gt;
* Debian GNU/Linux 13 (Trixie).&lt;br /&gt;
* Uma máquina com 4G ou 8G de ram.&lt;br /&gt;
* 1 SSD para instalar o sistema.&lt;br /&gt;
* 1 SSD para servir de '''OSD''' no '''CEPH'''.&lt;br /&gt;
*3 interfaces de rede. Uma para o acesso, outra para o '''Cluster''' e outra para o '''CEPH'''. &lt;br /&gt;
&lt;br /&gt;
== Configurando o Qdevice no Debian ==&lt;br /&gt;
Uma vez instalado o Debian, precisamos configurar as 3 interfaces para a comunicação com seu Cluster Proxmox. Por exemplo:&lt;br /&gt;
&lt;br /&gt;
* ens18 - IP 10.254.254.27/24 GW 10.254.254.1 (essa seria a interface com acesso à Internet para instalar os programas).&lt;br /&gt;
* ens19 - IP 192.168.1.3/24 (interface que deve se comunicar com a rede do Cluster, com os IPs dos nodes 192.168.1.1 e 192.168.1.2.&lt;br /&gt;
* ens20 - IP 192.168.2.3/24 (interface que se comunica com a rede CEPH, com os IPs 192.168.2.1 e 192.168.2.2.&lt;br /&gt;
&lt;br /&gt;
Precisamos configurar o serviço SSHD para permitir conexão com root, pois o Proxmox vai precisar acessar o Debian. Para isso altere o arquivo '''/etc/ssh/sshd_config''' o parâmetro abaixo:&lt;br /&gt;
 PermitRootLogin yes&lt;br /&gt;
Reinicie o serviço:&lt;br /&gt;
 # systemctl restart sshd&lt;br /&gt;
No Debian vamos instalar o pacote '''corosync-qnetd''':&lt;br /&gt;
 # apt install corosync-qnetd&lt;br /&gt;
Nos dois servidores Proxmox, no nosso exemplo PVE01 e PVE02 instalaremos o pacote '''corosync-qdevice''':&lt;br /&gt;
 # apt install corosync-qdevice&lt;br /&gt;
Agora vá para o shell do seu '''Proxmox principal''', no meu caso o '''PVE01''' e adicione o Debian ao Cluster com o seguinte comando: &lt;br /&gt;
 # pvecm qdevice setup 192.168.1.3&lt;br /&gt;
Com o comando '''pvecm status''' podemos ver como está o quorum e se tudo ocorreu bem, verá que agora temos 3 votos no lugar de 2 e um '''Qdevice''' no membership:&lt;br /&gt;
[[Arquivo:Qdevice.png|nenhum|miniaturadaimagem|748x748px]]&lt;br /&gt;
Agora em se tratando de Cluster, você tem o mínimo de votantes para o bom funcionamento e usando uma máquina simples com Debian.&lt;br /&gt;
&lt;br /&gt;
== Adicionando um CEPH monitor e OSD ==&lt;br /&gt;
Agora precisamos tornar nosso '''CEPH''' saudável também e para isso vamos instalar os pacotes do CEPH do Proxmox no Debian. O CEPH precisa ser da mesma versão usada no Cluster Proxmox. Para os meus testes utilizei um '''Cluster Proxmox 9''' no '''PVE01''' e '''PVE02''' que utiliza o '''CEPH Squid 19.2'''. Então vamos adicionar o repositório:&lt;br /&gt;
 # echo &amp;quot;deb &amp;lt;nowiki&amp;gt;http://download.proxmox.com/debian/ceph-squid&amp;lt;/nowiki&amp;gt; trixie no-subscription&amp;quot; &amp;gt; /etc/apt/sources.list.d/ceph.list&lt;br /&gt;
 # wget &amp;lt;nowiki&amp;gt;https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg&amp;lt;/nowiki&amp;gt; -O /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg&lt;br /&gt;
Instalando os pacotes do CEPH:&lt;br /&gt;
 # apt update&lt;br /&gt;
 # apt install ceph ceph-common&lt;br /&gt;
Antes de prosseguir adicione no '''/etc/hosts''' do Debian:&lt;br /&gt;
 192.168.2.1 node1&lt;br /&gt;
 192.168.2.2 node2&lt;br /&gt;
 192.168.2.3 nodeq&lt;br /&gt;
Estou chamando nosso '''Quorum Device''' com o hostname '''nodeq'''.&lt;br /&gt;
&lt;br /&gt;
Agora precisaremos executar algumas tarefas no nosso '''PVE01''':&lt;br /&gt;
 # ceph mon getmap -o /tmp/monmap&lt;br /&gt;
 &lt;br /&gt;
 # monmaptool \&lt;br /&gt;
   --add nodeq 192.168.2.3:6789 \&lt;br /&gt;
   /tmp/monmap&lt;br /&gt;
Vamos checar se adicionamos o '''nodeq''' ao '''monmap''' com o comando: '''monmaptool --print /tmp/monmap'''&lt;br /&gt;
[[Arquivo:Monmap.png|nenhum|miniaturadaimagem|722x722px]]&lt;br /&gt;
Vamos gerar o '''keyring''' para usarmos no Debian:&lt;br /&gt;
 # ceph auth get mon. -o /tmp/ceph.mon.keyring&lt;br /&gt;
Agora precisamos copiar todos os arquivos necessários do '''PVE01''' para o nosso Debian:&lt;br /&gt;
 # scp /tmp/monmap root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /tmp/ceph.mon.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/ceph.conf root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/priv/ceph.client.admin.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 &lt;br /&gt;
 # scp /var/lib/ceph/bootstrap-osd/ceph.keyring \&lt;br /&gt;
 root@192.168.2.3:/var/lib/ceph/bootstrap-osd/&lt;br /&gt;
'''Atenção''' '''agora''' pois vamos no nosso Debian alterar o arquivo '''/etc/ceph/ceph.conf'''. Primeiro modifique  o parâmetro abaixo para incluir o IP '''192.168.2.3''':&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
Modifique os dois parâmetros abaixo e deixe eles iguais a estes:&amp;lt;pre&amp;gt;&lt;br /&gt;
[client]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&lt;br /&gt;
[client.crash]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&amp;lt;/pre&amp;gt;Adicione no final deste mesmo arquivo a configuração abaixo:&amp;lt;pre&amp;gt;&lt;br /&gt;
[mon.nodeq]&lt;br /&gt;
	public_addr = 192.168.2.3&lt;br /&gt;
&amp;lt;/pre&amp;gt;Ainda no '''Debian''' execute os comandos abaixo para prepararmos o ambiente pro '''CEPH''':&lt;br /&gt;
 # mkdir -p /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown ceph:ceph /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chmod 750 /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
Vamos criar o monitor:&lt;br /&gt;
 # ceph-mon --mkfs \&lt;br /&gt;
 -i nodeq \&lt;br /&gt;
 --monmap /etc/ceph/monmap \&lt;br /&gt;
 --keyring /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 &lt;br /&gt;
 # chown -R ceph: /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown -R ceph: /etc/ceph/&lt;br /&gt;
 # chmod 640 /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 # chmod 640 /etc/ceph/monmap&lt;br /&gt;
Este é o momento crucial para que tenhamos mais um monitor no nosso CEPH do Proxmox:&lt;br /&gt;
 # systemctl enable ceph-mon@nodeq&lt;br /&gt;
 # systemctl start ceph-mon@nodeq&lt;br /&gt;
Precisamos checar se o serviço subiu com o comando: '''systemctl status ceph-mon@nodeq'''&lt;br /&gt;
&lt;br /&gt;
Se aparecer algo assim então parabéns, até aqui foi tudo OK:&lt;br /&gt;
[[Arquivo:Nodeq ceph.png|nenhum|miniaturadaimagem|894x894px]]&lt;br /&gt;
Volte no Proxmox PVE01 e altere o '''/etc/pve/ceph.conf''' modificando para:&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
E adicionando no final do arquivo:&lt;br /&gt;
 [mon.nodeq]&lt;br /&gt;
         public_addr = 192.168.2.3&lt;br /&gt;
Agora ativamos, ainda no '''Proxmox PVE01''', o '''msgr2''':&lt;br /&gt;
 # ceph mon enable-msgr2&lt;br /&gt;
No Debian reinicie o serviço:&lt;br /&gt;
 # systemctl restart ceph-mon@nodeq&lt;br /&gt;
No '''Proxmox''' em '''CEPH''' verá um novo Monitor adicionado:&lt;br /&gt;
[[Arquivo:Mon ceph.png|nenhum|miniaturadaimagem|598x598px]]&lt;br /&gt;
&lt;br /&gt;
== Adicionando o OSD no Debian ==&lt;br /&gt;
Agora vamos aos procedimentos para usarmos aquele SSD como OSD no CEPH. Vamos supor que o '''SSD livre''' seja o '''/dev/sdb''':&lt;br /&gt;
 # apt install gdisk util-linux&lt;br /&gt;
 &lt;br /&gt;
 # wipefs -a /dev/sdb&lt;br /&gt;
 # sgdisk --zap-all /dev/sdb&lt;br /&gt;
&lt;br /&gt;
Feito isso só precisamos criar o volume CEPH com o comando:&lt;br /&gt;
 # ceph-volume lvm create --data /dev/sdb&lt;br /&gt;
Se tudo foi bem, nesse momento verá o '''OSD''' no seu '''Cluster Proxmox''':&lt;br /&gt;
[[Arquivo:Osd img.png|nenhum|miniaturadaimagem|1234x1234px]]&lt;br /&gt;
Olhando a saúde do nosso Cluster veremos:&lt;br /&gt;
[[Arquivo:Resultado ceph.png|nenhum|miniaturadaimagem|1235x1235px]]&lt;br /&gt;
&lt;br /&gt;
== Conclusão ==&lt;br /&gt;
Aqui vemos em funcionamento um '''Cluster Proxmox + HA''' com 2 nós apenas e uma máquina Debian servindo como apoio no funcionamento e segurança do Cluster.&lt;br /&gt;
&lt;br /&gt;
Gostou do artigo? Compartilhe!&lt;br /&gt;
&lt;br /&gt;
Autor: [[Sobre mim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Artigos Técnicos]]&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Mon_ceph.png&amp;diff=4089</id>
		<title>Arquivo:Mon ceph.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Mon_ceph.png&amp;diff=4089"/>
		<updated>2026-04-25T16:05:35Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mon_ceph&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Nodeq_ceph.png&amp;diff=4088</id>
		<title>Arquivo:Nodeq ceph.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Nodeq_ceph.png&amp;diff=4088"/>
		<updated>2026-04-25T16:02:35Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;nodeq_ceph&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4087</id>
		<title>Debian Cluster CEPH</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4087"/>
		<updated>2026-04-25T16:00:15Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introdução ==&lt;br /&gt;
Este artigo tem como foco explicar como adicionar um Debian GNU/Linux em um Proxmox Cluster + HA com 2 nodes. Como muitos sabem, um '''Cluster''' deve ser composto de no '''mínimo 3 nodes''' para que possa dar segurança, existir '''quorum''' e quando usamos '''CEPH''' também precisamos de pelo menos 3 nodes com '''OSDs''' para termos uma estabilidade e segurança no sistema. O problema é quando se quer fazer  isso com apenas 2 servidores Proxmox. Comprar um terceiro servidor às vezes ainda não está nos planos mas você tem uma máquina parada, onde você pode adicionar 2 SSDs e com 4G de ram você pode adicionar ela no '''Cluster''' para servir de quorum e de disco '''CEPH'''.  Dessa maneira você consegue com 2 servidores '''Proxmox''' e uma máquina que chamei de '''Quorum Device''', colocar em produção um Cluster com HA funcional.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
O diagrama abaixo será o ambiente de exemplo mas não falaremos de como construir um Cluster + HA com Proxmox. Nesse caso você precisará ter os 2 servidores já instalados e configurados em '''Cluster''' com '''CEPH'''. Aqui vamos apenas mostrar como adicionar um Debian GNU/Linux nesse Cluster e no CEPH.&lt;br /&gt;
[[Arquivo:Diagrama ceph.png|nenhum|miniaturadaimagem|483x483px]]&lt;br /&gt;
&lt;br /&gt;
== Pré-requisitos ==&lt;br /&gt;
&lt;br /&gt;
* Debian GNU/Linux 13 (Trixie).&lt;br /&gt;
* Uma máquina com 4G ou 8G de ram.&lt;br /&gt;
* 1 SSD para instalar o sistema.&lt;br /&gt;
* 1 SSD para servir de '''OSD''' no '''CEPH'''.&lt;br /&gt;
*3 interfaces de rede. Uma para o acesso, outra para o '''Cluster''' e outra para o '''CEPH'''. &lt;br /&gt;
&lt;br /&gt;
== Configurando o Qdevice no Debian ==&lt;br /&gt;
Uma vez instalado o Debian, precisamos configurar as 3 interfaces para a comunicação com seu Cluster Proxmox. Por exemplo:&lt;br /&gt;
&lt;br /&gt;
* ens18 - IP 10.254.254.27/24 GW 10.254.254.1 (essa seria a interface com acesso à Internet para instalar os programas).&lt;br /&gt;
* ens19 - IP 192.168.1.3/24 (interface que deve se comunicar com a rede do Cluster, com os IPs dos nodes 192.168.1.1 e 192.168.1.2.&lt;br /&gt;
* ens20 - IP 192.168.2.3/24 (interface que se comunica com a rede CEPH, com os IPs 192.168.2.1 e 192.168.2.2.&lt;br /&gt;
&lt;br /&gt;
Precisamos configurar o serviço SSHD para permitir conexão com root, pois o Proxmox vai precisar acessar o Debian. Para isso altere o arquivo '''/etc/ssh/sshd_config''' o parâmetro abaixo:&lt;br /&gt;
 PermitRootLogin yes&lt;br /&gt;
Reinicie o serviço:&lt;br /&gt;
 # systemctl restart sshd&lt;br /&gt;
No Debian vamos instalar o pacote '''corosync-qnetd''':&lt;br /&gt;
 # apt install corosync-qnetd&lt;br /&gt;
Nos dois servidores Proxmox, no nosso exemplo PVE01 e PVE02 instalaremos o pacote '''corosync-qdevice''':&lt;br /&gt;
 # apt install corosync-qdevice&lt;br /&gt;
Agora vá para o shell do seu '''Proxmox principal''', no meu caso o '''PVE01''' e adicione o Debian ao Cluster com o seguinte comando: &lt;br /&gt;
 # pvecm qdevice setup 192.168.1.3&lt;br /&gt;
Com o comando '''pvecm status''' podemos ver como está o quorum e se tudo ocorreu bem, verá que agora temos 3 votos no lugar de 2 e um '''Qdevice''' no membership:&lt;br /&gt;
[[Arquivo:Qdevice.png|nenhum|miniaturadaimagem|748x748px]]&lt;br /&gt;
Agora em se tratando de Cluster, você tem o mínimo de votantes para o bom funcionamento e usando uma máquina simples com Debian.&lt;br /&gt;
&lt;br /&gt;
== Adicionando um CEPH monitor e OSD ==&lt;br /&gt;
Agora precisamos tornar nosso '''CEPH''' saudável também e para isso vamos instalar os pacotes do CEPH do Proxmox no Debian. O CEPH precisa ser da mesma versão usada no Cluster Proxmox. Para os meus testes utilizei um '''Cluster Proxmox 9''' no '''PVE01''' e '''PVE02''' que utiliza o '''CEPH Squid 19.2'''. Então vamos adicionar o repositório:&lt;br /&gt;
 # echo &amp;quot;deb &amp;lt;nowiki&amp;gt;http://download.proxmox.com/debian/ceph-squid&amp;lt;/nowiki&amp;gt; trixie no-subscription&amp;quot; &amp;gt; /etc/apt/sources.list.d/ceph.list&lt;br /&gt;
 # wget &amp;lt;nowiki&amp;gt;https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg&amp;lt;/nowiki&amp;gt; -O /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg&lt;br /&gt;
Instalando os pacotes do CEPH:&lt;br /&gt;
 # apt update&lt;br /&gt;
 # apt install ceph ceph-common&lt;br /&gt;
Antes de prosseguir adicione no '''/etc/hosts''' do Debian:&lt;br /&gt;
 192.168.2.1 node1&lt;br /&gt;
 192.168.2.2 node2&lt;br /&gt;
 192.168.2.3 nodeq&lt;br /&gt;
Estou chamando nosso '''Quorum Device''' com o hostname '''nodeq'''.&lt;br /&gt;
&lt;br /&gt;
Agora precisaremos executar algumas tarefas no nosso '''PVE01''':&lt;br /&gt;
 # ceph mon getmap -o /tmp/monmap&lt;br /&gt;
 &lt;br /&gt;
 # monmaptool \&lt;br /&gt;
   --add nodeq 192.168.2.3:6789 \&lt;br /&gt;
   /tmp/monmap&lt;br /&gt;
Vamos checar se adicionamos o '''nodeq''' ao '''monmap''' com o comando: '''monmaptool --print /tmp/monmap'''&lt;br /&gt;
&lt;br /&gt;
Vamos gerar o '''keyring''' para usarmos no Debian:&lt;br /&gt;
 # ceph auth get mon. -o /tmp/ceph.mon.keyring&lt;br /&gt;
Agora precisamos copiar todos os arquivos necessários do '''PVE01''' para o nosso Debian:&lt;br /&gt;
 # scp /tmp/monmap root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /tmp/ceph.mon.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/ceph.conf root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/priv/ceph.client.admin.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 &lt;br /&gt;
 # scp /var/lib/ceph/bootstrap-osd/ceph.keyring \&lt;br /&gt;
 root@192.168.2.3:/var/lib/ceph/bootstrap-osd/&lt;br /&gt;
'''Atenção''' '''agora''' pois vamos no nosso Debian alterar o arquivo '''/etc/ceph/ceph.conf'''. Primeiro modifique  o parâmetro abaixo para incluir o IP '''192.168.2.3''':&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
Modifique os dois parâmetros abaixo e deixe eles iguais a estes:&amp;lt;pre&amp;gt;&lt;br /&gt;
[client]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&lt;br /&gt;
[client.crash]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&amp;lt;/pre&amp;gt;Adicione no final deste mesmo arquivo a configuração abaixo:&amp;lt;pre&amp;gt;&lt;br /&gt;
[mon.nodeq]&lt;br /&gt;
	public_addr = 192.168.2.3&lt;br /&gt;
&amp;lt;/pre&amp;gt;Ainda no '''Debian''' execute os comandos abaixo para prepararmos o ambiente pro '''CEPH''':&lt;br /&gt;
 # mkdir -p /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown ceph:ceph /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chmod 750 /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
Vamos criar o monitor:&lt;br /&gt;
 # ceph-mon --mkfs \&lt;br /&gt;
 -i nodeq \&lt;br /&gt;
 --monmap /etc/ceph/monmap \&lt;br /&gt;
 --keyring /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 &lt;br /&gt;
 # chown -R ceph: /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown -R ceph: /etc/ceph/&lt;br /&gt;
 # chmod 640 /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 # chmod 640 /etc/ceph/monmap&lt;br /&gt;
Este é o momento crucial para que tenhamos mais um monitor no nosso CEPH do Proxmox:&lt;br /&gt;
 # systemctl enable ceph-mon@nodeq&lt;br /&gt;
 # systemctl start ceph-mon@nodeq&lt;br /&gt;
Precisamos checar se o serviço subiu com o comando: '''systemctl status ceph-mon@nodeq'''&lt;br /&gt;
&lt;br /&gt;
Se aparecer algo assim então parabéns, até aqui foi tudo OK:&lt;br /&gt;
[[Arquivo:Nodeq ceph.png|nenhum|miniaturadaimagem|806x806px]]Volte no Proxmox PVE01 e altere o '''/etc/pve/ceph.conf''' modificando para:&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
E adicionando no final do arquivo:&lt;br /&gt;
 [mon.nodeq]&lt;br /&gt;
         public_addr = 192.168.2.3&lt;br /&gt;
Agora ativamos, ainda no '''Proxmox PVE01''', o '''msgr2''':&lt;br /&gt;
 # ceph mon enable-msgr2&lt;br /&gt;
No Debian reinicie o serviço:&lt;br /&gt;
 # systemctl restart ceph-mon@nodeq&lt;br /&gt;
No '''Proxmox''' em '''CEPH''' verá um novo Monitor adicionado:&lt;br /&gt;
[[Arquivo:Mon ceph.png|nenhum|miniaturadaimagem|598x598px]]&lt;br /&gt;
&lt;br /&gt;
== Adicionando o OSD no Debian ==&lt;br /&gt;
Agora vamos aos procedimentos para usarmos aquele SSD como OSD no CEPH. Vamos supor que o '''SSD livre''' seja o '''/dev/sdb''':&lt;br /&gt;
 # apt install gdisk util-linux&lt;br /&gt;
 &lt;br /&gt;
 # wipefs -a /dev/sdb&lt;br /&gt;
 # sgdisk --zap-all /dev/sdb&lt;br /&gt;
&lt;br /&gt;
Feito isso só precisamos criar o volume CEPH com o comando:&lt;br /&gt;
 # ceph-volume lvm create --data /dev/sdb&lt;br /&gt;
Se tudo foi bem, nesse momento verá o '''OSD''' no seu '''Cluster Proxmox''':&lt;br /&gt;
[[Arquivo:Osd img.png|nenhum|miniaturadaimagem|1234x1234px]]&lt;br /&gt;
Olhando a saúde do nosso Cluster veremos:&lt;br /&gt;
[[Arquivo:Resultado ceph.png|nenhum|miniaturadaimagem|1235x1235px]]&lt;br /&gt;
&lt;br /&gt;
== Conclusão ==&lt;br /&gt;
Aqui vemos em funcionamento um '''Cluster Proxmox + HA''' com 2 nós apenas e uma máquina Debian servindo como apoio no funcionamento e segurança do Cluster.&lt;br /&gt;
&lt;br /&gt;
Gostou do artigo? Compartilhe!&lt;br /&gt;
&lt;br /&gt;
Autor: [[Sobre mim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Artigos Técnicos]]&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Monmap.png&amp;diff=4086</id>
		<title>Arquivo:Monmap.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Monmap.png&amp;diff=4086"/>
		<updated>2026-04-25T15:58:47Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Monmap&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Qdevice.png&amp;diff=4085</id>
		<title>Arquivo:Qdevice.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Qdevice.png&amp;diff=4085"/>
		<updated>2026-04-25T15:55:09Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;qdevice&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4084</id>
		<title>Debian Cluster CEPH</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4084"/>
		<updated>2026-04-25T15:54:03Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introdução ==&lt;br /&gt;
Este artigo tem como foco explicar como adicionar um Debian GNU/Linux em um Proxmox Cluster + HA com 2 nodes. Como muitos sabem, um '''Cluster''' deve ser composto de no '''mínimo 3 nodes''' para que possa dar segurança, existir '''quorum''' e quando usamos '''CEPH''' também precisamos de pelo menos 3 nodes com '''OSDs''' para termos uma estabilidade e segurança no sistema. O problema é quando se quer fazer  isso com apenas 2 servidores Proxmox. Comprar um terceiro servidor às vezes ainda não está nos planos mas você tem uma máquina parada, onde você pode adicionar 2 SSDs e com 4G de ram você pode adicionar ela no '''Cluster''' para servir de quorum e de disco '''CEPH'''.  Dessa maneira você consegue com 2 servidores '''Proxmox''' e uma máquina que chamei de '''Quorum Device''', colocar em produção um Cluster com HA funcional.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
O diagrama abaixo será o ambiente de exemplo mas não falaremos de como construir um Cluster + HA com Proxmox. Nesse caso você precisará ter os 2 servidores já instalados e configurados em '''Cluster''' com '''CEPH'''. Aqui vamos apenas mostrar como adicionar um Debian GNU/Linux nesse Cluster e no CEPH.&lt;br /&gt;
[[Arquivo:Diagrama ceph.png|nenhum|miniaturadaimagem|483x483px]]&lt;br /&gt;
&lt;br /&gt;
== Pré-requisitos ==&lt;br /&gt;
&lt;br /&gt;
* Debian GNU/Linux 13 (Trixie).&lt;br /&gt;
* Uma máquina com 4G ou 8G de ram.&lt;br /&gt;
* 1 SSD para instalar o sistema.&lt;br /&gt;
* 1 SSD para servir de '''OSD''' no '''CEPH'''.&lt;br /&gt;
*3 interfaces de rede. Uma para o acesso, outra para o '''Cluster''' e outra para o '''CEPH'''. &lt;br /&gt;
&lt;br /&gt;
== Configurando o Qdevice no Debian ==&lt;br /&gt;
Uma vez instalado o Debian, precisamos configurar as 3 interfaces para a comunicação com seu Cluster Proxmox. Por exemplo:&lt;br /&gt;
&lt;br /&gt;
* ens18 - IP 10.254.254.27/24 GW 10.254.254.1 (essa seria a interface com acesso à Internet para instalar os programas).&lt;br /&gt;
* ens19 - IP 192.168.1.3/24 (interface que deve se comunicar com a rede do Cluster, com os IPs dos nodes 192.168.1.1 e 192.168.1.2.&lt;br /&gt;
* ens20 - IP 192.168.2.3/24 (interface que se comunica com a rede CEPH, com os IPs 192.168.2.1 e 192.168.2.2.&lt;br /&gt;
&lt;br /&gt;
Precisamos configurar o serviço SSHD para permitir conexão com root, pois o Proxmox vai precisar acessar o Debian. Para isso altere o arquivo '''/etc/ssh/sshd_config''' o parâmetro abaixo:&lt;br /&gt;
 PermitRootLogin yes&lt;br /&gt;
Reinicie o serviço:&lt;br /&gt;
 # systemctl restart sshd&lt;br /&gt;
No Debian vamos instalar o pacote '''corosync-qnetd''':&lt;br /&gt;
 # apt install corosync-qnetd&lt;br /&gt;
Nos dois servidores Proxmox, no nosso exemplo PVE01 e PVE02 instalaremos o pacote '''corosync-qdevice''':&lt;br /&gt;
 # apt install corosync-qdevice&lt;br /&gt;
Agora vá para o shell do seu '''Proxmox principal''', no meu caso o '''PVE01''' e adicione o Debian ao Cluster com o seguinte comando: &lt;br /&gt;
 # pvecm qdevice setup 192.168.1.3&lt;br /&gt;
Com o comando '''pvecm status''' podemos ver como está o quorum e se tudo ocorreu bem, verá que agora temos 3 votos no lugar de 2 e um '''Qdevice''' no membership:&lt;br /&gt;
[[Arquivo:Qdevice.png|nenhum|miniaturadaimagem|748x748px]]&lt;br /&gt;
Agora em se tratando de Cluster, você tem o mínimo de votantes para o bom funcionamento e usando uma máquina simples com Debian.&lt;br /&gt;
&lt;br /&gt;
== Adicionando um CEPH monitor e OSD ==&lt;br /&gt;
Agora precisamos tornar nosso '''CEPH''' saudável também e para isso vamos instalar os pacotes do CEPH do Proxmox no Debian. O CEPH precisa ser da mesma versão usada no Cluster Proxmox. Para os meus testes utilizei um '''Cluster Proxmox 9''' no '''PVE01''' e '''PVE02''' que utiliza o '''CEPH Squid 19.2'''. Então vamos adicionar o repositório:&lt;br /&gt;
 # echo &amp;quot;deb &amp;lt;nowiki&amp;gt;http://download.proxmox.com/debian/ceph-squid&amp;lt;/nowiki&amp;gt; trixie no-subscription&amp;quot; &amp;gt; /etc/apt/sources.list.d/ceph.list&lt;br /&gt;
 # wget &amp;lt;nowiki&amp;gt;https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg&amp;lt;/nowiki&amp;gt; -O /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg&lt;br /&gt;
Instalando os pacotes do CEPH:&lt;br /&gt;
 # apt update&lt;br /&gt;
 # apt install ceph ceph-common&lt;br /&gt;
Antes de prosseguir adicione no '''/etc/hosts''' do Debian:&lt;br /&gt;
 192.168.2.1 node1&lt;br /&gt;
 192.168.2.2 node2&lt;br /&gt;
 192.168.2.3 nodeq&lt;br /&gt;
Estou chamando nosso '''Quorum Device''' com o hostname '''nodeq'''.&lt;br /&gt;
&lt;br /&gt;
Agora precisaremos executar algumas tarefas no nosso '''PVE01''':&lt;br /&gt;
 # ceph mon getmap -o /tmp/monmap&lt;br /&gt;
 &lt;br /&gt;
 # monmaptool \&lt;br /&gt;
   --add nodeq 192.168.2.3:6789 \&lt;br /&gt;
   /tmp/monmap&lt;br /&gt;
Vamos checar se adicionamos o '''nodeq''' ao '''monmap''' com o comando: '''monmaptool --print /tmp/monmap'''&lt;br /&gt;
[[Arquivo:Monmap.png|nenhum|miniaturadaimagem|677x677px]]&lt;br /&gt;
Vamos gerar o '''keyring''' para usarmos no Debian:&lt;br /&gt;
 # ceph auth get mon. -o /tmp/ceph.mon.keyring&lt;br /&gt;
Agora precisamos copiar todos os arquivos necessários do '''PVE01''' para o nosso Debian:&lt;br /&gt;
 # scp /tmp/monmap root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /tmp/ceph.mon.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/ceph.conf root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/priv/ceph.client.admin.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 &lt;br /&gt;
 # scp /var/lib/ceph/bootstrap-osd/ceph.keyring \&lt;br /&gt;
 root@192.168.2.3:/var/lib/ceph/bootstrap-osd/&lt;br /&gt;
'''Atenção''' '''agora''' pois vamos no nosso Debian alterar o arquivo '''/etc/ceph/ceph.conf'''. Primeiro modifique  o parâmetro abaixo para incluir o IP '''192.168.2.3''':&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
Modifique os dois parâmetros abaixo e deixe eles iguais a estes:&amp;lt;pre&amp;gt;&lt;br /&gt;
[client]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&lt;br /&gt;
[client.crash]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&amp;lt;/pre&amp;gt;Adicione no final deste mesmo arquivo a configuração abaixo:&amp;lt;pre&amp;gt;&lt;br /&gt;
[mon.nodeq]&lt;br /&gt;
	public_addr = 192.168.2.3&lt;br /&gt;
&amp;lt;/pre&amp;gt;Ainda no '''Debian''' execute os comandos abaixo para prepararmos o ambiente pro '''CEPH''':&lt;br /&gt;
 # mkdir -p /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown ceph:ceph /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chmod 750 /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
Vamos criar o monitor:&lt;br /&gt;
 # ceph-mon --mkfs \&lt;br /&gt;
 -i nodeq \&lt;br /&gt;
 --monmap /etc/ceph/monmap \&lt;br /&gt;
 --keyring /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 &lt;br /&gt;
 # chown -R ceph: /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown -R ceph: /etc/ceph/&lt;br /&gt;
 # chmod 640 /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 # chmod 640 /etc/ceph/monmap&lt;br /&gt;
Este é o momento crucial para que tenhamos mais um monitor no nosso CEPH do Proxmox:&lt;br /&gt;
 # systemctl enable ceph-mon@nodeq&lt;br /&gt;
 # systemctl start ceph-mon@nodeq&lt;br /&gt;
Precisamos checar se o serviço subiu com o comando: '''systemctl status ceph-mon@nodeq'''&lt;br /&gt;
&lt;br /&gt;
Se aparecer algo assim então parabéns, até aqui foi tudo OK:&lt;br /&gt;
[[Arquivo:Nodeq ceph.png|nenhum|miniaturadaimagem|806x806px]]Volte no Proxmox PVE01 e altere o '''/etc/pve/ceph.conf''' modificando para:&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
E adicionando no final do arquivo:&lt;br /&gt;
 [mon.nodeq]&lt;br /&gt;
         public_addr = 192.168.2.3&lt;br /&gt;
Agora ativamos, ainda no '''Proxmox PVE01''', o '''msgr2''':&lt;br /&gt;
 # ceph mon enable-msgr2&lt;br /&gt;
No Debian reinicie o serviço:&lt;br /&gt;
 # systemctl restart ceph-mon@nodeq&lt;br /&gt;
No '''Proxmox''' em '''CEPH''' verá um novo Monitor adicionado:&lt;br /&gt;
[[Arquivo:Mon ceph.png|nenhum|miniaturadaimagem|598x598px]]&lt;br /&gt;
&lt;br /&gt;
== Adicionando o OSD no Debian ==&lt;br /&gt;
Agora vamos aos procedimentos para usarmos aquele SSD como OSD no CEPH. Vamos supor que o '''SSD livre''' seja o '''/dev/sdb''':&lt;br /&gt;
 # apt install gdisk util-linux&lt;br /&gt;
 &lt;br /&gt;
 # wipefs -a /dev/sdb&lt;br /&gt;
 # sgdisk --zap-all /dev/sdb&lt;br /&gt;
&lt;br /&gt;
Feito isso só precisamos criar o volume CEPH com o comando:&lt;br /&gt;
 # ceph-volume lvm create --data /dev/sdb&lt;br /&gt;
Se tudo foi bem, nesse momento verá o '''OSD''' no seu '''Cluster Proxmox''':&lt;br /&gt;
[[Arquivo:Osd img.png|nenhum|miniaturadaimagem|1234x1234px]]&lt;br /&gt;
Olhando a saúde do nosso Cluster veremos:&lt;br /&gt;
[[Arquivo:Resultado ceph.png|nenhum|miniaturadaimagem|1235x1235px]]&lt;br /&gt;
&lt;br /&gt;
== Conclusão ==&lt;br /&gt;
Aqui vemos em funcionamento um '''Cluster Proxmox + HA''' com 2 nós apenas e uma máquina Debian servindo como apoio no funcionamento e segurança do Cluster.&lt;br /&gt;
&lt;br /&gt;
Gostou do artigo? Compartilhe!&lt;br /&gt;
&lt;br /&gt;
Autor: [[Sobre mim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Artigos Técnicos]]&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4083</id>
		<title>Debian Cluster CEPH</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4083"/>
		<updated>2026-04-25T15:50:31Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introdução ==&lt;br /&gt;
Este artigo tem como foco explicar como adicionar um Debian GNU/Linux em um Proxmox Cluster + HA com 2 nodes. Como muitos sabem, um '''Cluster''' deve ser composto de no '''mínimo 3 nodes''' para que possa dar segurança, existir '''quorum''' e quando usamos '''CEPH''' também precisamos de pelo menos 3 nodes com '''OSDs''' para termos uma estabilidade e segurança no sistema. O problema é quando se quer fazer  isso com apenas 2 servidores Proxmox. Comprar um terceiro servidor às vezes ainda não está nos planos mas você tem uma máquina parada, onde você pode adicionar 2 SSDs e com 4G de ram você pode adicionar ela no '''Cluster''' para servir de quorum e de disco '''CEPH'''.  Dessa maneira você consegue com 2 servidores '''Proxmox''' e uma máquina que chamei de '''Quorum Device''', colocar em produção um Cluster com HA funcional.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
O diagrama abaixo será o ambiente de exemplo mas não falaremos de como construir um Cluster + HA com Proxmox. Nesse caso você precisará ter os 2 servidores já instalados e configurados em '''Cluster''' com '''CEPH'''. Aqui vamos apenas mostrar como adicionar um Debian GNU/Linux nesse Cluster e no CEPH.&lt;br /&gt;
[[Arquivo:Diagrama cluster ceph.png|nenhum|alt=|commoldura|[[Arquivo:Diagrama ceph.png|nenhum|alt=|commoldura]]]]&lt;br /&gt;
&lt;br /&gt;
== Pré-requisitos ==&lt;br /&gt;
&lt;br /&gt;
* Debian GNU/Linux 13 (Trixie).&lt;br /&gt;
* Uma máquina com 4G ou 8G de ram.&lt;br /&gt;
* 1 SSD para instalar o sistema.&lt;br /&gt;
* 1 SSD para servir de '''OSD''' no '''CEPH'''.&lt;br /&gt;
*3 interfaces de rede. Uma para o acesso, outra para o '''Cluster''' e outra para o '''CEPH'''. &lt;br /&gt;
&lt;br /&gt;
== Configurando o Qdevice no Debian ==&lt;br /&gt;
Uma vez instalado o Debian, precisamos configurar as 3 interfaces para a comunicação com seu Cluster Proxmox. Por exemplo:&lt;br /&gt;
&lt;br /&gt;
* ens18 - IP 10.254.254.27/24 GW 10.254.254.1 (essa seria a interface com acesso à Internet para instalar os programas).&lt;br /&gt;
* ens19 - IP 192.168.1.3/24 (interface que deve se comunicar com a rede do Cluster, com os IPs dos nodes 192.168.1.1 e 192.168.1.2.&lt;br /&gt;
* ens20 - IP 192.168.2.3/24 (interface que se comunica com a rede CEPH, com os IPs 192.168.2.1 e 192.168.2.2.&lt;br /&gt;
&lt;br /&gt;
Precisamos configurar o serviço SSHD para permitir conexão com root, pois o Proxmox vai precisar acessar o Debian. Para isso altere o arquivo '''/etc/ssh/sshd_config''' o parâmetro abaixo:&lt;br /&gt;
 PermitRootLogin yes&lt;br /&gt;
Reinicie o serviço:&lt;br /&gt;
 # systemctl restart sshd&lt;br /&gt;
No Debian vamos instalar o pacote '''corosync-qnetd''':&lt;br /&gt;
 # apt install corosync-qnetd&lt;br /&gt;
Nos dois servidores Proxmox, no nosso exemplo PVE01 e PVE02 instalaremos o pacote '''corosync-qdevice''':&lt;br /&gt;
 # apt install corosync-qdevice&lt;br /&gt;
Agora vá para o shell do seu '''Proxmox principal''', no meu caso o '''PVE01''' e adicione o Debian ao Cluster com o seguinte comando: &lt;br /&gt;
 # pvecm qdevice setup 192.168.1.3&lt;br /&gt;
Com o comando '''pvecm status''' podemos ver como está o quorum e se tudo ocorreu bem, verá que agora temos 3 votos no lugar de 2 e um '''Qdevice''' no membership:&lt;br /&gt;
[[Arquivo:Qdevice.png|nenhum|miniaturadaimagem|748x748px]]&lt;br /&gt;
Agora em se tratando de Cluster, você tem o mínimo de votantes para o bom funcionamento e usando uma máquina simples com Debian.&lt;br /&gt;
&lt;br /&gt;
== Adicionando um CEPH monitor e OSD ==&lt;br /&gt;
Agora precisamos tornar nosso '''CEPH''' saudável também e para isso vamos instalar os pacotes do CEPH do Proxmox no Debian. O CEPH precisa ser da mesma versão usada no Cluster Proxmox. Para os meus testes utilizei um '''Cluster Proxmox 9''' no '''PVE01''' e '''PVE02''' que utiliza o '''CEPH Squid 19.2'''. Então vamos adicionar o repositório:&lt;br /&gt;
 # echo &amp;quot;deb &amp;lt;nowiki&amp;gt;http://download.proxmox.com/debian/ceph-squid&amp;lt;/nowiki&amp;gt; trixie no-subscription&amp;quot; &amp;gt; /etc/apt/sources.list.d/ceph.list&lt;br /&gt;
 # wget &amp;lt;nowiki&amp;gt;https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg&amp;lt;/nowiki&amp;gt; -O /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg&lt;br /&gt;
Instalando os pacotes do CEPH:&lt;br /&gt;
 # apt update&lt;br /&gt;
 # apt install ceph ceph-common&lt;br /&gt;
Antes de prosseguir adicione no '''/etc/hosts''' do Debian:&lt;br /&gt;
 192.168.2.1 node1&lt;br /&gt;
 192.168.2.2 node2&lt;br /&gt;
 192.168.2.3 nodeq&lt;br /&gt;
Estou chamando nosso '''Quorum Device''' com o hostname '''nodeq'''.&lt;br /&gt;
&lt;br /&gt;
Agora precisaremos executar algumas tarefas no nosso '''PVE01''':&lt;br /&gt;
 # ceph mon getmap -o /tmp/monmap&lt;br /&gt;
 &lt;br /&gt;
 # monmaptool \&lt;br /&gt;
   --add nodeq 192.168.2.3:6789 \&lt;br /&gt;
   /tmp/monmap&lt;br /&gt;
Vamos checar se adicionamos o '''nodeq''' ao '''monmap''' com o comando: '''monmaptool --print /tmp/monmap'''&lt;br /&gt;
[[Arquivo:Monmap.png|nenhum|miniaturadaimagem|677x677px]]&lt;br /&gt;
Vamos gerar o '''keyring''' para usarmos no Debian:&lt;br /&gt;
 # ceph auth get mon. -o /tmp/ceph.mon.keyring&lt;br /&gt;
Agora precisamos copiar todos os arquivos necessários do '''PVE01''' para o nosso Debian:&lt;br /&gt;
 # scp /tmp/monmap root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /tmp/ceph.mon.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/ceph.conf root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/priv/ceph.client.admin.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 &lt;br /&gt;
 # scp /var/lib/ceph/bootstrap-osd/ceph.keyring \&lt;br /&gt;
 root@192.168.2.3:/var/lib/ceph/bootstrap-osd/&lt;br /&gt;
'''Atenção''' '''agora''' pois vamos no nosso Debian alterar o arquivo '''/etc/ceph/ceph.conf'''. Primeiro modifique  o parâmetro abaixo para incluir o IP '''192.168.2.3''':&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
Modifique os dois parâmetros abaixo e deixe eles iguais a estes:&amp;lt;pre&amp;gt;&lt;br /&gt;
[client]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&lt;br /&gt;
[client.crash]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&amp;lt;/pre&amp;gt;Adicione no final deste mesmo arquivo a configuração abaixo:&amp;lt;pre&amp;gt;&lt;br /&gt;
[mon.nodeq]&lt;br /&gt;
	public_addr = 192.168.2.3&lt;br /&gt;
&amp;lt;/pre&amp;gt;Ainda no '''Debian''' execute os comandos abaixo para prepararmos o ambiente pro '''CEPH''':&lt;br /&gt;
 # mkdir -p /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown ceph:ceph /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chmod 750 /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
Vamos criar o monitor:&lt;br /&gt;
 # ceph-mon --mkfs \&lt;br /&gt;
 -i nodeq \&lt;br /&gt;
 --monmap /etc/ceph/monmap \&lt;br /&gt;
 --keyring /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 &lt;br /&gt;
 # chown -R ceph: /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown -R ceph: /etc/ceph/&lt;br /&gt;
 # chmod 640 /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 # chmod 640 /etc/ceph/monmap&lt;br /&gt;
Este é o momento crucial para que tenhamos mais um monitor no nosso CEPH do Proxmox:&lt;br /&gt;
 # systemctl enable ceph-mon@nodeq&lt;br /&gt;
 # systemctl start ceph-mon@nodeq&lt;br /&gt;
Precisamos checar se o serviço subiu com o comando: '''systemctl status ceph-mon@nodeq'''&lt;br /&gt;
&lt;br /&gt;
Se aparecer algo assim então parabéns, até aqui foi tudo OK:&lt;br /&gt;
[[Arquivo:Nodeq ceph.png|nenhum|miniaturadaimagem|806x806px]]Volte no Proxmox PVE01 e altere o '''/etc/pve/ceph.conf''' modificando para:&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
E adicionando no final do arquivo:&lt;br /&gt;
 [mon.nodeq]&lt;br /&gt;
         public_addr = 192.168.2.3&lt;br /&gt;
Agora ativamos, ainda no '''Proxmox PVE01''', o '''msgr2''':&lt;br /&gt;
 # ceph mon enable-msgr2&lt;br /&gt;
No Debian reinicie o serviço:&lt;br /&gt;
 # systemctl restart ceph-mon@nodeq&lt;br /&gt;
No '''Proxmox''' em '''CEPH''' verá um novo Monitor adicionado:&lt;br /&gt;
[[Arquivo:Mon ceph.png|nenhum|miniaturadaimagem|598x598px]]&lt;br /&gt;
&lt;br /&gt;
== Adicionando o OSD no Debian ==&lt;br /&gt;
Agora vamos aos procedimentos para usarmos aquele SSD como OSD no CEPH. Vamos supor que o '''SSD livre''' seja o '''/dev/sdb''':&lt;br /&gt;
 # apt install gdisk util-linux&lt;br /&gt;
 &lt;br /&gt;
 # wipefs -a /dev/sdb&lt;br /&gt;
 # sgdisk --zap-all /dev/sdb&lt;br /&gt;
&lt;br /&gt;
Feito isso só precisamos criar o volume CEPH com o comando:&lt;br /&gt;
 # ceph-volume lvm create --data /dev/sdb&lt;br /&gt;
Se tudo foi bem, nesse momento verá o '''OSD''' no seu '''Cluster Proxmox''':&lt;br /&gt;
[[Arquivo:Osd img.png|nenhum|miniaturadaimagem|1234x1234px]]&lt;br /&gt;
Olhando a saúde do nosso Cluster veremos:&lt;br /&gt;
[[Arquivo:Resultado ceph.png|nenhum|miniaturadaimagem|1235x1235px]]&lt;br /&gt;
&lt;br /&gt;
== Conclusão ==&lt;br /&gt;
Aqui vemos em funcionamento um '''Cluster Proxmox + HA''' com 2 nós apenas e uma máquina Debian servindo como apoio no funcionamento e segurança do Cluster.&lt;br /&gt;
&lt;br /&gt;
Gostou do artigo? Compartilhe!&lt;br /&gt;
&lt;br /&gt;
Autor: [[Sobre mim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Artigos Técnicos]]&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4082</id>
		<title>Debian Cluster CEPH</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4082"/>
		<updated>2026-04-25T15:49:41Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introdução ==&lt;br /&gt;
Este artigo tem como foco explicar como adicionar um Debian GNU/Linux em um Proxmox Cluster + HA com 2 nodes. Como muitos sabem, um '''Cluster''' deve ser composto de no '''mínimo 3 nodes''' para que possa dar segurança, existir '''quorum''' e quando usamos '''CEPH''' também precisamos de pelo menos 3 nodes com '''OSDs''' para termos uma estabilidade e segurança no sistema. O problema é quando se quer fazer  isso com apenas 2 servidores Proxmox. Comprar um terceiro servidor às vezes ainda não está nos planos mas você tem uma máquina parada, onde você pode adicionar 2 SSDs e com 4G de ram você pode adicionar ela no '''Cluster''' para servir de quorum e de disco '''CEPH'''.  Dessa maneira você consegue com 2 servidores '''Proxmox''' e uma máquina que chamei de '''Quorum Device''', colocar em produção um Cluster com HA funcional.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
O diagrama abaixo será o ambiente de exemplo mas não falaremos de como construir um Cluster + HA com Proxmox. Nesse caso você precisará ter os 2 servidores já instalados e configurados em '''Cluster''' com '''CEPH'''. Aqui vamos apenas mostrar como adicionar um Debian GNU/Linux nesse Cluster e no CEPH.&lt;br /&gt;
[[Arquivo:Diagrama cluster ceph.png|nenhum|alt=|commoldura|[[Arquivo:Diagrama ceph.png|nenhum|miniaturadaimagem|500x500px]]]]&lt;br /&gt;
&lt;br /&gt;
== Pré-requisitos ==&lt;br /&gt;
&lt;br /&gt;
* Debian GNU/Linux 13 (Trixie).&lt;br /&gt;
* Uma máquina com 4G ou 8G de ram.&lt;br /&gt;
* 1 SSD para instalar o sistema.&lt;br /&gt;
* 1 SSD para servir de '''OSD''' no '''CEPH'''.&lt;br /&gt;
*3 interfaces de rede. Uma para o acesso, outra para o '''Cluster''' e outra para o '''CEPH'''. &lt;br /&gt;
&lt;br /&gt;
== Configurando o Qdevice no Debian ==&lt;br /&gt;
Uma vez instalado o Debian, precisamos configurar as 3 interfaces para a comunicação com seu Cluster Proxmox. Por exemplo:&lt;br /&gt;
&lt;br /&gt;
* ens18 - IP 10.254.254.27/24 GW 10.254.254.1 (essa seria a interface com acesso à Internet para instalar os programas).&lt;br /&gt;
* ens19 - IP 192.168.1.3/24 (interface que deve se comunicar com a rede do Cluster, com os IPs dos nodes 192.168.1.1 e 192.168.1.2.&lt;br /&gt;
* ens20 - IP 192.168.2.3/24 (interface que se comunica com a rede CEPH, com os IPs 192.168.2.1 e 192.168.2.2.&lt;br /&gt;
&lt;br /&gt;
Precisamos configurar o serviço SSHD para permitir conexão com root, pois o Proxmox vai precisar acessar o Debian. Para isso altere o arquivo '''/etc/ssh/sshd_config''' o parâmetro abaixo:&lt;br /&gt;
 PermitRootLogin yes&lt;br /&gt;
Reinicie o serviço:&lt;br /&gt;
 # systemctl restart sshd&lt;br /&gt;
No Debian vamos instalar o pacote '''corosync-qnetd''':&lt;br /&gt;
 # apt install corosync-qnetd&lt;br /&gt;
Nos dois servidores Proxmox, no nosso exemplo PVE01 e PVE02 instalaremos o pacote '''corosync-qdevice''':&lt;br /&gt;
 # apt install corosync-qdevice&lt;br /&gt;
Agora vá para o shell do seu '''Proxmox principal''', no meu caso o '''PVE01''' e adicione o Debian ao Cluster com o seguinte comando: &lt;br /&gt;
 # pvecm qdevice setup 192.168.1.3&lt;br /&gt;
Com o comando '''pvecm status''' podemos ver como está o quorum e se tudo ocorreu bem, verá que agora temos 3 votos no lugar de 2 e um '''Qdevice''' no membership:&lt;br /&gt;
[[Arquivo:Qdevice.png|nenhum|miniaturadaimagem|748x748px]]&lt;br /&gt;
Agora em se tratando de Cluster, você tem o mínimo de votantes para o bom funcionamento e usando uma máquina simples com Debian.&lt;br /&gt;
&lt;br /&gt;
== Adicionando um CEPH monitor e OSD ==&lt;br /&gt;
Agora precisamos tornar nosso '''CEPH''' saudável também e para isso vamos instalar os pacotes do CEPH do Proxmox no Debian. O CEPH precisa ser da mesma versão usada no Cluster Proxmox. Para os meus testes utilizei um '''Cluster Proxmox 9''' no '''PVE01''' e '''PVE02''' que utiliza o '''CEPH Squid 19.2'''. Então vamos adicionar o repositório:&lt;br /&gt;
 # echo &amp;quot;deb &amp;lt;nowiki&amp;gt;http://download.proxmox.com/debian/ceph-squid&amp;lt;/nowiki&amp;gt; trixie no-subscription&amp;quot; &amp;gt; /etc/apt/sources.list.d/ceph.list&lt;br /&gt;
 # wget &amp;lt;nowiki&amp;gt;https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg&amp;lt;/nowiki&amp;gt; -O /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg&lt;br /&gt;
Instalando os pacotes do CEPH:&lt;br /&gt;
 # apt update&lt;br /&gt;
 # apt install ceph ceph-common&lt;br /&gt;
Antes de prosseguir adicione no '''/etc/hosts''' do Debian:&lt;br /&gt;
 192.168.2.1 node1&lt;br /&gt;
 192.168.2.2 node2&lt;br /&gt;
 192.168.2.3 nodeq&lt;br /&gt;
Estou chamando nosso '''Quorum Device''' com o hostname '''nodeq'''.&lt;br /&gt;
&lt;br /&gt;
Agora precisaremos executar algumas tarefas no nosso '''PVE01''':&lt;br /&gt;
 # ceph mon getmap -o /tmp/monmap&lt;br /&gt;
 &lt;br /&gt;
 # monmaptool \&lt;br /&gt;
   --add nodeq 192.168.2.3:6789 \&lt;br /&gt;
   /tmp/monmap&lt;br /&gt;
Vamos checar se adicionamos o '''nodeq''' ao '''monmap''' com o comando: '''monmaptool --print /tmp/monmap'''&lt;br /&gt;
[[Arquivo:Monmap.png|nenhum|miniaturadaimagem|677x677px]]&lt;br /&gt;
Vamos gerar o '''keyring''' para usarmos no Debian:&lt;br /&gt;
 # ceph auth get mon. -o /tmp/ceph.mon.keyring&lt;br /&gt;
Agora precisamos copiar todos os arquivos necessários do '''PVE01''' para o nosso Debian:&lt;br /&gt;
 # scp /tmp/monmap root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /tmp/ceph.mon.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/ceph.conf root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/priv/ceph.client.admin.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 &lt;br /&gt;
 # scp /var/lib/ceph/bootstrap-osd/ceph.keyring \&lt;br /&gt;
 root@192.168.2.3:/var/lib/ceph/bootstrap-osd/&lt;br /&gt;
'''Atenção''' '''agora''' pois vamos no nosso Debian alterar o arquivo '''/etc/ceph/ceph.conf'''. Primeiro modifique  o parâmetro abaixo para incluir o IP '''192.168.2.3''':&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
Modifique os dois parâmetros abaixo e deixe eles iguais a estes:&amp;lt;pre&amp;gt;&lt;br /&gt;
[client]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&lt;br /&gt;
[client.crash]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&amp;lt;/pre&amp;gt;Adicione no final deste mesmo arquivo a configuração abaixo:&amp;lt;pre&amp;gt;&lt;br /&gt;
[mon.nodeq]&lt;br /&gt;
	public_addr = 192.168.2.3&lt;br /&gt;
&amp;lt;/pre&amp;gt;Ainda no '''Debian''' execute os comandos abaixo para prepararmos o ambiente pro '''CEPH''':&lt;br /&gt;
 # mkdir -p /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown ceph:ceph /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chmod 750 /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
Vamos criar o monitor:&lt;br /&gt;
 # ceph-mon --mkfs \&lt;br /&gt;
 -i nodeq \&lt;br /&gt;
 --monmap /etc/ceph/monmap \&lt;br /&gt;
 --keyring /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 &lt;br /&gt;
 # chown -R ceph: /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown -R ceph: /etc/ceph/&lt;br /&gt;
 # chmod 640 /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 # chmod 640 /etc/ceph/monmap&lt;br /&gt;
Este é o momento crucial para que tenhamos mais um monitor no nosso CEPH do Proxmox:&lt;br /&gt;
 # systemctl enable ceph-mon@nodeq&lt;br /&gt;
 # systemctl start ceph-mon@nodeq&lt;br /&gt;
Precisamos checar se o serviço subiu com o comando: '''systemctl status ceph-mon@nodeq'''&lt;br /&gt;
&lt;br /&gt;
Se aparecer algo assim então parabéns, até aqui foi tudo OK:&lt;br /&gt;
[[Arquivo:Nodeq ceph.png|nenhum|miniaturadaimagem|806x806px]]Volte no Proxmox PVE01 e altere o '''/etc/pve/ceph.conf''' modificando para:&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
E adicionando no final do arquivo:&lt;br /&gt;
 [mon.nodeq]&lt;br /&gt;
         public_addr = 192.168.2.3&lt;br /&gt;
Agora ativamos, ainda no '''Proxmox PVE01''', o '''msgr2''':&lt;br /&gt;
 # ceph mon enable-msgr2&lt;br /&gt;
No Debian reinicie o serviço:&lt;br /&gt;
 # systemctl restart ceph-mon@nodeq&lt;br /&gt;
No '''Proxmox''' em '''CEPH''' verá um novo Monitor adicionado:&lt;br /&gt;
[[Arquivo:Mon ceph.png|nenhum|miniaturadaimagem|598x598px]]&lt;br /&gt;
&lt;br /&gt;
== Adicionando o OSD no Debian ==&lt;br /&gt;
Agora vamos aos procedimentos para usarmos aquele SSD como OSD no CEPH. Vamos supor que o '''SSD livre''' seja o '''/dev/sdb''':&lt;br /&gt;
 # apt install gdisk util-linux&lt;br /&gt;
 &lt;br /&gt;
 # wipefs -a /dev/sdb&lt;br /&gt;
 # sgdisk --zap-all /dev/sdb&lt;br /&gt;
&lt;br /&gt;
Feito isso só precisamos criar o volume CEPH com o comando:&lt;br /&gt;
 # ceph-volume lvm create --data /dev/sdb&lt;br /&gt;
Se tudo foi bem, nesse momento verá o '''OSD''' no seu '''Cluster Proxmox''':&lt;br /&gt;
[[Arquivo:Osd img.png|nenhum|miniaturadaimagem|1234x1234px]]&lt;br /&gt;
Olhando a saúde do nosso Cluster veremos:&lt;br /&gt;
[[Arquivo:Resultado ceph.png|nenhum|miniaturadaimagem|1235x1235px]]&lt;br /&gt;
&lt;br /&gt;
== Conclusão ==&lt;br /&gt;
Aqui vemos em funcionamento um '''Cluster Proxmox + HA''' com 2 nós apenas e uma máquina Debian servindo como apoio no funcionamento e segurança do Cluster.&lt;br /&gt;
&lt;br /&gt;
Gostou do artigo? Compartilhe!&lt;br /&gt;
&lt;br /&gt;
Autor: [[Sobre mim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Artigos Técnicos]]&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4081</id>
		<title>Debian Cluster CEPH</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4081"/>
		<updated>2026-04-25T15:49:17Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introdução ==&lt;br /&gt;
Este artigo tem como foco explicar como adicionar um Debian GNU/Linux em um Proxmox Cluster + HA com 2 nodes. Como muitos sabem, um '''Cluster''' deve ser composto de no '''mínimo 3 nodes''' para que possa dar segurança, existir '''quorum''' e quando usamos '''CEPH''' também precisamos de pelo menos 3 nodes com '''OSDs''' para termos uma estabilidade e segurança no sistema. O problema é quando se quer fazer  isso com apenas 2 servidores Proxmox. Comprar um terceiro servidor às vezes ainda não está nos planos mas você tem uma máquina parada, onde você pode adicionar 2 SSDs e com 4G de ram você pode adicionar ela no '''Cluster''' para servir de quorum e de disco '''CEPH'''.  Dessa maneira você consegue com 2 servidores '''Proxmox''' e uma máquina que chamei de '''Quorum Device''', colocar em produção um Cluster com HA funcional.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
O diagrama abaixo será o ambiente de exemplo mas não falaremos de como construir um Cluster + HA com Proxmox. Nesse caso você precisará ter os 2 servidores já instalados e configurados em '''Cluster''' com '''CEPH'''. Aqui vamos apenas mostrar como adicionar um Debian GNU/Linux nesse Cluster e no CEPH.&lt;br /&gt;
[[Arquivo:Diagrama cluster ceph.png|nenhum|alt=|commoldura|[[Arquivo:Diagrama ceph.png|nenhum|miniaturadaimagem]]]]&lt;br /&gt;
&lt;br /&gt;
== Pré-requisitos ==&lt;br /&gt;
&lt;br /&gt;
* Debian GNU/Linux 13 (Trixie).&lt;br /&gt;
* Uma máquina com 4G ou 8G de ram.&lt;br /&gt;
* 1 SSD para instalar o sistema.&lt;br /&gt;
* 1 SSD para servir de '''OSD''' no '''CEPH'''.&lt;br /&gt;
*3 interfaces de rede. Uma para o acesso, outra para o '''Cluster''' e outra para o '''CEPH'''. &lt;br /&gt;
&lt;br /&gt;
== Configurando o Qdevice no Debian ==&lt;br /&gt;
Uma vez instalado o Debian, precisamos configurar as 3 interfaces para a comunicação com seu Cluster Proxmox. Por exemplo:&lt;br /&gt;
&lt;br /&gt;
* ens18 - IP 10.254.254.27/24 GW 10.254.254.1 (essa seria a interface com acesso à Internet para instalar os programas).&lt;br /&gt;
* ens19 - IP 192.168.1.3/24 (interface que deve se comunicar com a rede do Cluster, com os IPs dos nodes 192.168.1.1 e 192.168.1.2.&lt;br /&gt;
* ens20 - IP 192.168.2.3/24 (interface que se comunica com a rede CEPH, com os IPs 192.168.2.1 e 192.168.2.2.&lt;br /&gt;
&lt;br /&gt;
Precisamos configurar o serviço SSHD para permitir conexão com root, pois o Proxmox vai precisar acessar o Debian. Para isso altere o arquivo '''/etc/ssh/sshd_config''' o parâmetro abaixo:&lt;br /&gt;
 PermitRootLogin yes&lt;br /&gt;
Reinicie o serviço:&lt;br /&gt;
 # systemctl restart sshd&lt;br /&gt;
No Debian vamos instalar o pacote '''corosync-qnetd''':&lt;br /&gt;
 # apt install corosync-qnetd&lt;br /&gt;
Nos dois servidores Proxmox, no nosso exemplo PVE01 e PVE02 instalaremos o pacote '''corosync-qdevice''':&lt;br /&gt;
 # apt install corosync-qdevice&lt;br /&gt;
Agora vá para o shell do seu '''Proxmox principal''', no meu caso o '''PVE01''' e adicione o Debian ao Cluster com o seguinte comando: &lt;br /&gt;
 # pvecm qdevice setup 192.168.1.3&lt;br /&gt;
Com o comando '''pvecm status''' podemos ver como está o quorum e se tudo ocorreu bem, verá que agora temos 3 votos no lugar de 2 e um '''Qdevice''' no membership:&lt;br /&gt;
[[Arquivo:Qdevice.png|nenhum|miniaturadaimagem|748x748px]]&lt;br /&gt;
Agora em se tratando de Cluster, você tem o mínimo de votantes para o bom funcionamento e usando uma máquina simples com Debian.&lt;br /&gt;
&lt;br /&gt;
== Adicionando um CEPH monitor e OSD ==&lt;br /&gt;
Agora precisamos tornar nosso '''CEPH''' saudável também e para isso vamos instalar os pacotes do CEPH do Proxmox no Debian. O CEPH precisa ser da mesma versão usada no Cluster Proxmox. Para os meus testes utilizei um '''Cluster Proxmox 9''' no '''PVE01''' e '''PVE02''' que utiliza o '''CEPH Squid 19.2'''. Então vamos adicionar o repositório:&lt;br /&gt;
 # echo &amp;quot;deb &amp;lt;nowiki&amp;gt;http://download.proxmox.com/debian/ceph-squid&amp;lt;/nowiki&amp;gt; trixie no-subscription&amp;quot; &amp;gt; /etc/apt/sources.list.d/ceph.list&lt;br /&gt;
 # wget &amp;lt;nowiki&amp;gt;https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg&amp;lt;/nowiki&amp;gt; -O /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg&lt;br /&gt;
Instalando os pacotes do CEPH:&lt;br /&gt;
 # apt update&lt;br /&gt;
 # apt install ceph ceph-common&lt;br /&gt;
Antes de prosseguir adicione no '''/etc/hosts''' do Debian:&lt;br /&gt;
 192.168.2.1 node1&lt;br /&gt;
 192.168.2.2 node2&lt;br /&gt;
 192.168.2.3 nodeq&lt;br /&gt;
Estou chamando nosso '''Quorum Device''' com o hostname '''nodeq'''.&lt;br /&gt;
&lt;br /&gt;
Agora precisaremos executar algumas tarefas no nosso '''PVE01''':&lt;br /&gt;
 # ceph mon getmap -o /tmp/monmap&lt;br /&gt;
 &lt;br /&gt;
 # monmaptool \&lt;br /&gt;
   --add nodeq 192.168.2.3:6789 \&lt;br /&gt;
   /tmp/monmap&lt;br /&gt;
Vamos checar se adicionamos o '''nodeq''' ao '''monmap''' com o comando: '''monmaptool --print /tmp/monmap'''&lt;br /&gt;
[[Arquivo:Monmap.png|nenhum|miniaturadaimagem|677x677px]]&lt;br /&gt;
Vamos gerar o '''keyring''' para usarmos no Debian:&lt;br /&gt;
 # ceph auth get mon. -o /tmp/ceph.mon.keyring&lt;br /&gt;
Agora precisamos copiar todos os arquivos necessários do '''PVE01''' para o nosso Debian:&lt;br /&gt;
 # scp /tmp/monmap root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /tmp/ceph.mon.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/ceph.conf root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/priv/ceph.client.admin.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 &lt;br /&gt;
 # scp /var/lib/ceph/bootstrap-osd/ceph.keyring \&lt;br /&gt;
 root@192.168.2.3:/var/lib/ceph/bootstrap-osd/&lt;br /&gt;
'''Atenção''' '''agora''' pois vamos no nosso Debian alterar o arquivo '''/etc/ceph/ceph.conf'''. Primeiro modifique  o parâmetro abaixo para incluir o IP '''192.168.2.3''':&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
Modifique os dois parâmetros abaixo e deixe eles iguais a estes:&amp;lt;pre&amp;gt;&lt;br /&gt;
[client]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&lt;br /&gt;
[client.crash]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&amp;lt;/pre&amp;gt;Adicione no final deste mesmo arquivo a configuração abaixo:&amp;lt;pre&amp;gt;&lt;br /&gt;
[mon.nodeq]&lt;br /&gt;
	public_addr = 192.168.2.3&lt;br /&gt;
&amp;lt;/pre&amp;gt;Ainda no '''Debian''' execute os comandos abaixo para prepararmos o ambiente pro '''CEPH''':&lt;br /&gt;
 # mkdir -p /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown ceph:ceph /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chmod 750 /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
Vamos criar o monitor:&lt;br /&gt;
 # ceph-mon --mkfs \&lt;br /&gt;
 -i nodeq \&lt;br /&gt;
 --monmap /etc/ceph/monmap \&lt;br /&gt;
 --keyring /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 &lt;br /&gt;
 # chown -R ceph: /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown -R ceph: /etc/ceph/&lt;br /&gt;
 # chmod 640 /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 # chmod 640 /etc/ceph/monmap&lt;br /&gt;
Este é o momento crucial para que tenhamos mais um monitor no nosso CEPH do Proxmox:&lt;br /&gt;
 # systemctl enable ceph-mon@nodeq&lt;br /&gt;
 # systemctl start ceph-mon@nodeq&lt;br /&gt;
Precisamos checar se o serviço subiu com o comando: '''systemctl status ceph-mon@nodeq'''&lt;br /&gt;
&lt;br /&gt;
Se aparecer algo assim então parabéns, até aqui foi tudo OK:&lt;br /&gt;
[[Arquivo:Nodeq ceph.png|nenhum|miniaturadaimagem|806x806px]]Volte no Proxmox PVE01 e altere o '''/etc/pve/ceph.conf''' modificando para:&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
E adicionando no final do arquivo:&lt;br /&gt;
 [mon.nodeq]&lt;br /&gt;
         public_addr = 192.168.2.3&lt;br /&gt;
Agora ativamos, ainda no '''Proxmox PVE01''', o '''msgr2''':&lt;br /&gt;
 # ceph mon enable-msgr2&lt;br /&gt;
No Debian reinicie o serviço:&lt;br /&gt;
 # systemctl restart ceph-mon@nodeq&lt;br /&gt;
No '''Proxmox''' em '''CEPH''' verá um novo Monitor adicionado:&lt;br /&gt;
[[Arquivo:Mon ceph.png|nenhum|miniaturadaimagem|598x598px]]&lt;br /&gt;
&lt;br /&gt;
== Adicionando o OSD no Debian ==&lt;br /&gt;
Agora vamos aos procedimentos para usarmos aquele SSD como OSD no CEPH. Vamos supor que o '''SSD livre''' seja o '''/dev/sdb''':&lt;br /&gt;
 # apt install gdisk util-linux&lt;br /&gt;
 &lt;br /&gt;
 # wipefs -a /dev/sdb&lt;br /&gt;
 # sgdisk --zap-all /dev/sdb&lt;br /&gt;
&lt;br /&gt;
Feito isso só precisamos criar o volume CEPH com o comando:&lt;br /&gt;
 # ceph-volume lvm create --data /dev/sdb&lt;br /&gt;
Se tudo foi bem, nesse momento verá o '''OSD''' no seu '''Cluster Proxmox''':&lt;br /&gt;
[[Arquivo:Osd img.png|nenhum|miniaturadaimagem|1234x1234px]]&lt;br /&gt;
Olhando a saúde do nosso Cluster veremos:&lt;br /&gt;
[[Arquivo:Resultado ceph.png|nenhum|miniaturadaimagem|1235x1235px]]&lt;br /&gt;
&lt;br /&gt;
== Conclusão ==&lt;br /&gt;
Aqui vemos em funcionamento um '''Cluster Proxmox + HA''' com 2 nós apenas e uma máquina Debian servindo como apoio no funcionamento e segurança do Cluster.&lt;br /&gt;
&lt;br /&gt;
Gostou do artigo? Compartilhe!&lt;br /&gt;
&lt;br /&gt;
Autor: [[Sobre mim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Artigos Técnicos]]&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Diagrama_ceph.png&amp;diff=4080</id>
		<title>Arquivo:Diagrama ceph.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Diagrama_ceph.png&amp;diff=4080"/>
		<updated>2026-04-25T15:48:24Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;diagrama_ceph&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4079</id>
		<title>Debian Cluster CEPH</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Debian_Cluster_CEPH&amp;diff=4079"/>
		<updated>2026-04-25T15:47:19Z</updated>

		<summary type="html">&lt;p&gt;Gondim: Criou página com '== Introdução == Este artigo tem como foco explicar como adicionar um Debian GNU/Linux em um Proxmox Cluster + HA com 2 nodes. Como muitos sabem, um '''Cluster''' deve ser c...'&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introdução ==&lt;br /&gt;
Este artigo tem como foco explicar como adicionar um Debian GNU/Linux em um Proxmox Cluster + HA com 2 nodes. Como muitos sabem, um '''Cluster''' deve ser composto de no '''mínimo 3 nodes''' para que possa dar segurança, existir '''quorum''' e quando usamos '''CEPH''' também precisamos de pelo menos 3 nodes com '''OSDs''' para termos uma estabilidade e segurança no sistema. O problema é quando se quer fazer  isso com apenas 2 servidores Proxmox. Comprar um terceiro servidor às vezes ainda não está nos planos mas você tem uma máquina parada, onde você pode adicionar 2 SSDs e com 4G de ram você pode adicionar ela no '''Cluster''' para servir de quorum e de disco '''CEPH'''.  Dessa maneira você consegue com 2 servidores '''Proxmox''' e uma máquina que chamei de '''Quorum Device''', colocar em produção um Cluster com HA funcional.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
O diagrama abaixo será o ambiente de exemplo mas não falaremos de como construir um Cluster + HA com Proxmox. Nesse caso você precisará ter os 2 servidores já instalados e configurados em '''Cluster''' com '''CEPH'''. Aqui vamos apenas mostrar como adicionar um Debian GNU/Linux nesse Cluster e no CEPH.&lt;br /&gt;
[[Arquivo:Diagrama cluster ceph.png|nenhum|miniaturadaimagem|522x522px]]&lt;br /&gt;
&lt;br /&gt;
== Pré-requisitos ==&lt;br /&gt;
&lt;br /&gt;
* Debian GNU/Linux 13 (Trixie).&lt;br /&gt;
* Uma máquina com 4G ou 8G de ram.&lt;br /&gt;
* 1 SSD para instalar o sistema.&lt;br /&gt;
* 1 SSD para servir de '''OSD''' no '''CEPH'''.&lt;br /&gt;
*3 interfaces de rede. Uma para o acesso, outra para o '''Cluster''' e outra para o '''CEPH'''. &lt;br /&gt;
&lt;br /&gt;
== Configurando o Qdevice no Debian ==&lt;br /&gt;
Uma vez instalado o Debian, precisamos configurar as 3 interfaces para a comunicação com seu Cluster Proxmox. Por exemplo:&lt;br /&gt;
&lt;br /&gt;
* ens18 - IP 10.254.254.27/24 GW 10.254.254.1 (essa seria a interface com acesso à Internet para instalar os programas).&lt;br /&gt;
* ens19 - IP 192.168.1.3/24 (interface que deve se comunicar com a rede do Cluster, com os IPs dos nodes 192.168.1.1 e 192.168.1.2.&lt;br /&gt;
* ens20 - IP 192.168.2.3/24 (interface que se comunica com a rede CEPH, com os IPs 192.168.2.1 e 192.168.2.2.&lt;br /&gt;
&lt;br /&gt;
Precisamos configurar o serviço SSHD para permitir conexão com root, pois o Proxmox vai precisar acessar o Debian. Para isso altere o arquivo '''/etc/ssh/sshd_config''' o parâmetro abaixo:&lt;br /&gt;
 PermitRootLogin yes&lt;br /&gt;
Reinicie o serviço:&lt;br /&gt;
 # systemctl restart sshd&lt;br /&gt;
No Debian vamos instalar o pacote '''corosync-qnetd''':&lt;br /&gt;
 # apt install corosync-qnetd&lt;br /&gt;
Nos dois servidores Proxmox, no nosso exemplo PVE01 e PVE02 instalaremos o pacote '''corosync-qdevice''':&lt;br /&gt;
 # apt install corosync-qdevice&lt;br /&gt;
Agora vá para o shell do seu '''Proxmox principal''', no meu caso o '''PVE01''' e adicione o Debian ao Cluster com o seguinte comando: &lt;br /&gt;
 # pvecm qdevice setup 192.168.1.3&lt;br /&gt;
Com o comando '''pvecm status''' podemos ver como está o quorum e se tudo ocorreu bem, verá que agora temos 3 votos no lugar de 2 e um '''Qdevice''' no membership:&lt;br /&gt;
[[Arquivo:Qdevice.png|nenhum|miniaturadaimagem|748x748px]]&lt;br /&gt;
Agora em se tratando de Cluster, você tem o mínimo de votantes para o bom funcionamento e usando uma máquina simples com Debian.&lt;br /&gt;
&lt;br /&gt;
== Adicionando um CEPH monitor e OSD ==&lt;br /&gt;
Agora precisamos tornar nosso '''CEPH''' saudável também e para isso vamos instalar os pacotes do CEPH do Proxmox no Debian. O CEPH precisa ser da mesma versão usada no Cluster Proxmox. Para os meus testes utilizei um '''Cluster Proxmox 9''' no '''PVE01''' e '''PVE02''' que utiliza o '''CEPH Squid 19.2'''. Então vamos adicionar o repositório:&lt;br /&gt;
 # echo &amp;quot;deb &amp;lt;nowiki&amp;gt;http://download.proxmox.com/debian/ceph-squid&amp;lt;/nowiki&amp;gt; trixie no-subscription&amp;quot; &amp;gt; /etc/apt/sources.list.d/ceph.list&lt;br /&gt;
 # wget &amp;lt;nowiki&amp;gt;https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg&amp;lt;/nowiki&amp;gt; -O /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg&lt;br /&gt;
Instalando os pacotes do CEPH:&lt;br /&gt;
 # apt update&lt;br /&gt;
 # apt install ceph ceph-common&lt;br /&gt;
Antes de prosseguir adicione no '''/etc/hosts''' do Debian:&lt;br /&gt;
 192.168.2.1 node1&lt;br /&gt;
 192.168.2.2 node2&lt;br /&gt;
 192.168.2.3 nodeq&lt;br /&gt;
Estou chamando nosso '''Quorum Device''' com o hostname '''nodeq'''.&lt;br /&gt;
&lt;br /&gt;
Agora precisaremos executar algumas tarefas no nosso '''PVE01''':&lt;br /&gt;
 # ceph mon getmap -o /tmp/monmap&lt;br /&gt;
 &lt;br /&gt;
 # monmaptool \&lt;br /&gt;
   --add nodeq 192.168.2.3:6789 \&lt;br /&gt;
   /tmp/monmap&lt;br /&gt;
Vamos checar se adicionamos o '''nodeq''' ao '''monmap''' com o comando: '''monmaptool --print /tmp/monmap'''&lt;br /&gt;
[[Arquivo:Monmap.png|nenhum|miniaturadaimagem|677x677px]]&lt;br /&gt;
Vamos gerar o '''keyring''' para usarmos no Debian:&lt;br /&gt;
 # ceph auth get mon. -o /tmp/ceph.mon.keyring&lt;br /&gt;
Agora precisamos copiar todos os arquivos necessários do '''PVE01''' para o nosso Debian:&lt;br /&gt;
 # scp /tmp/monmap root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /tmp/ceph.mon.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/ceph.conf root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 # scp /etc/pve/priv/ceph.client.admin.keyring root@192.168.2.3:/etc/ceph/&lt;br /&gt;
 &lt;br /&gt;
 # scp /var/lib/ceph/bootstrap-osd/ceph.keyring \&lt;br /&gt;
 root@192.168.2.3:/var/lib/ceph/bootstrap-osd/&lt;br /&gt;
'''Atenção''' '''agora''' pois vamos no nosso Debian alterar o arquivo '''/etc/ceph/ceph.conf'''. Primeiro modifique  o parâmetro abaixo para incluir o IP '''192.168.2.3''':&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
Modifique os dois parâmetros abaixo e deixe eles iguais a estes:&amp;lt;pre&amp;gt;&lt;br /&gt;
[client]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&lt;br /&gt;
[client.crash]&lt;br /&gt;
	keyring = /etc/ceph/$cluster.$name.keyring&lt;br /&gt;
&amp;lt;/pre&amp;gt;Adicione no final deste mesmo arquivo a configuração abaixo:&amp;lt;pre&amp;gt;&lt;br /&gt;
[mon.nodeq]&lt;br /&gt;
	public_addr = 192.168.2.3&lt;br /&gt;
&amp;lt;/pre&amp;gt;Ainda no '''Debian''' execute os comandos abaixo para prepararmos o ambiente pro '''CEPH''':&lt;br /&gt;
 # mkdir -p /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown ceph:ceph /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chmod 750 /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
Vamos criar o monitor:&lt;br /&gt;
 # ceph-mon --mkfs \&lt;br /&gt;
 -i nodeq \&lt;br /&gt;
 --monmap /etc/ceph/monmap \&lt;br /&gt;
 --keyring /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 &lt;br /&gt;
 # chown -R ceph: /var/lib/ceph/mon/ceph-nodeq&lt;br /&gt;
 # chown -R ceph: /etc/ceph/&lt;br /&gt;
 # chmod 640 /etc/ceph/ceph.mon.keyring&lt;br /&gt;
 # chmod 640 /etc/ceph/monmap&lt;br /&gt;
Este é o momento crucial para que tenhamos mais um monitor no nosso CEPH do Proxmox:&lt;br /&gt;
 # systemctl enable ceph-mon@nodeq&lt;br /&gt;
 # systemctl start ceph-mon@nodeq&lt;br /&gt;
Precisamos checar se o serviço subiu com o comando: '''systemctl status ceph-mon@nodeq'''&lt;br /&gt;
&lt;br /&gt;
Se aparecer algo assim então parabéns, até aqui foi tudo OK:&lt;br /&gt;
[[Arquivo:Nodeq ceph.png|nenhum|miniaturadaimagem|806x806px]]Volte no Proxmox PVE01 e altere o '''/etc/pve/ceph.conf''' modificando para:&lt;br /&gt;
 mon_host = 192.168.2.1 192.168.2.2 192.168.2.3&lt;br /&gt;
E adicionando no final do arquivo:&lt;br /&gt;
 [mon.nodeq]&lt;br /&gt;
         public_addr = 192.168.2.3&lt;br /&gt;
Agora ativamos, ainda no '''Proxmox PVE01''', o '''msgr2''':&lt;br /&gt;
 # ceph mon enable-msgr2&lt;br /&gt;
No Debian reinicie o serviço:&lt;br /&gt;
 # systemctl restart ceph-mon@nodeq&lt;br /&gt;
No '''Proxmox''' em '''CEPH''' verá um novo Monitor adicionado:&lt;br /&gt;
[[Arquivo:Mon ceph.png|nenhum|miniaturadaimagem|598x598px]]&lt;br /&gt;
&lt;br /&gt;
== Adicionando o OSD no Debian ==&lt;br /&gt;
Agora vamos aos procedimentos para usarmos aquele SSD como OSD no CEPH. Vamos supor que o '''SSD livre''' seja o '''/dev/sdb''':&lt;br /&gt;
 # apt install gdisk util-linux&lt;br /&gt;
 &lt;br /&gt;
 # wipefs -a /dev/sdb&lt;br /&gt;
 # sgdisk --zap-all /dev/sdb&lt;br /&gt;
&lt;br /&gt;
Feito isso só precisamos criar o volume CEPH com o comando:&lt;br /&gt;
 # ceph-volume lvm create --data /dev/sdb&lt;br /&gt;
Se tudo foi bem, nesse momento verá o '''OSD''' no seu '''Cluster Proxmox''':&lt;br /&gt;
[[Arquivo:Osd img.png|nenhum|miniaturadaimagem|1234x1234px]]&lt;br /&gt;
Olhando a saúde do nosso Cluster veremos:&lt;br /&gt;
[[Arquivo:Resultado ceph.png|nenhum|miniaturadaimagem|1235x1235px]]&lt;br /&gt;
&lt;br /&gt;
== Conclusão ==&lt;br /&gt;
Aqui vemos em funcionamento um '''Cluster Proxmox + HA''' com 2 nós apenas e uma máquina Debian servindo como apoio no funcionamento e segurança do Cluster.&lt;br /&gt;
&lt;br /&gt;
Gostou do artigo? Compartilhe!&lt;br /&gt;
&lt;br /&gt;
Autor: [[Sobre mim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Artigos Técnicos]]&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4070</id>
		<title>Usuário:Gondim</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4070"/>
		<updated>2026-04-01T20:15:39Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Marcelo Gondim da Cunha'''&lt;br /&gt;
[[Arquivo:Gondim paisagem.jpg|esquerda|commoldura]]&lt;br /&gt;
&lt;br /&gt;
'''Contribuições e trabalhos:'''&lt;br /&gt;
&lt;br /&gt;
* Administração de Sistemas Unix-Like desde 1996.&lt;br /&gt;
* Consultor na Conectiva S/A - Unidade Rio em 2000.&lt;br /&gt;
** Autor do projeto TuxFrw - https://github.com/gondimcodes/tuxfrw e https://github.com/gondimcodes/tuxfrw-nft&lt;br /&gt;
* Administração de sistemas BSD pela FreeBSD Brasil em 2010.&lt;br /&gt;
* Direção do AS53135 - Nettel Telecomunicações entre 2003 e 2021 atingindo a marca de 41.000 assinantes. Gerando qualidade na entrega de serviços e implantando boas práticas como: &lt;br /&gt;
&lt;br /&gt;
a) IPv6.&lt;br /&gt;
&lt;br /&gt;
b) MANRS.&lt;br /&gt;
&lt;br /&gt;
c) RPKI.&lt;br /&gt;
&lt;br /&gt;
d) CPEs com firmware baseada na BCOP &amp;lt;nowiki&amp;gt;https://www.m3aawg.org/sites/default/files/lac-bcop-1-m3aawg-v1-portuguese-final.pdf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** SOC Specialist na Brasil TecPar (AS262907) de 2022 a 2025. Um milhão de clientes. Responsável pelas estratégias de mitigação anti-DDoS atendendo as Operações de RJ, SP, RS, SC, MT e MS.&lt;br /&gt;
'''Palestras ministradas:'''&lt;br /&gt;
&lt;br /&gt;
* Semana da Informática UERJ 2002 - TuxFrw.&lt;br /&gt;
* CONISLI 2003 - TuxFrw.&lt;br /&gt;
* CONISLI 2004 - Fazendo compras com Gentoo Linux - Palestra sobre a distribuição Linux e suas ferramentas fantásticas.&lt;br /&gt;
* CONISLI 2004 - OpenVPN - Palestra sobre como criar VPNs seguras com OpenVPN e diferenças entre ele e o IPSec.&lt;br /&gt;
* CONISLI 2005 - SPoP (Security Point of Presence) com OpenVPN - Como utilizar túneis encriptados do OpenVPN para acessar a Internet de forma segura, onde quer que esteja.&lt;br /&gt;
* SECOMP 2005 UNIFEI - TuxFrw.&lt;br /&gt;
&lt;br /&gt;
* Debconf19 2019 - [https://debconf19.debconf.org/talks/4-debian-na-vida-de-uma-operadora-de-telecom/ Debian na vida de uma operadora de Telecom], [https://www.youtube.com/watch?v=vQSTslUZy8k&amp;amp;list=PLYUtdmpYPTTJDtwgD8AtxzFJ9t_URhFMK&amp;amp;index=35 vídeo] e [https://salsa.debian.org/debconf-team/public/share/debconf19/raw/master/slides/4-debian-na-vida-de-uma-operadora-de-telecom.pdf?inline=false pdf].&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=5uOFtkplDts FiqueEmCasaUseDebian - CGNAT com NFTables] e [https://www.youtube.com/watch?v=Wz2IAg6MMlU SysAdmin apps].&lt;br /&gt;
&lt;br /&gt;
'''Artigos desenvolvidos para a comunidade do Brasil Peering Fórum:'''&lt;br /&gt;
&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_na_pratica CGNAT na pratica].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Acesso_via_IPv6_Link-Local Acesso via IPv6 Link-Local].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/MANRS MANRS].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_Bulk_Port_Allocation_com_DPDK CGNAT Bulk Port Allocation com DPDK].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Servidor_de_Logs Servidor de Logs].&lt;br /&gt;
* [[DNS Recursivo Anycast Hyperlocal|DNS Anycast com Hyperlocal]].&lt;br /&gt;
* [[Recomendações sobre Mitigação DDoS]]&lt;br /&gt;
* [[Portas de Amplificação DDoS e Botnets]]&lt;br /&gt;
* [[Static Loop - um erro que pode matar seu ISP/ITP]]&lt;br /&gt;
* [[Identificando e neutralizando uma Botnet]]&lt;br /&gt;
&lt;br /&gt;
'''Tutorial:'''&lt;br /&gt;
&lt;br /&gt;
* [https://bit.ly/2saumHK Segurança de roteamento: MANRS (Mutually Agreed Norms for Routing Security) - Tutoriais NIC.br em 09/12/2019].&lt;br /&gt;
&lt;br /&gt;
'''[https://www.manrs.org/about/advisory-group/members/ MANRS Advisory Group Member (2020-2021)]'''.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=oahQkGx8urY '''Live sobre MANRS com Leonardo Furtado'''].&lt;br /&gt;
&lt;br /&gt;
Criação da Wiki ISPUP! em 24/12/2022.&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 6 do NIC.br 28/04/2023''' - &amp;quot;'''CONCEITOS E IMPLEMENTAÇÃO DE CGNAT'''&amp;quot;. Material [https://semanacap.bcp.nic.br/6-online/ aqui] e vídeo aula [https://www.youtube.com/watch?v=1q7J3NkQVSc aqui].&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 10 do NIC.br 01/07/2025''' - &amp;quot;'''Teste para padrões técnicos modernos de Internet e segurança: IPv6, DNSSEC, TLS, HTTPS e HSTS'''&amp;quot;'''.''' Material [https://semanacap.bcp.nic.br/semana-de-capacitacao-online-edicao-10-2025/ aqui] e vídeo aula [https://www.youtube.com/watch?v=55RBnGQhi2o aqui].&lt;br /&gt;
&lt;br /&gt;
'''IX Fórum Regional Sudeste (Rio de Janeiro) 24/10/2025''' com a palestra &amp;quot;'''Segurança com o pé direito'''&amp;quot; pode ser baixada [https://regional.forum.ix.br/files/apresentacao/arquivo/2307/gondim.pdf aqui].&lt;br /&gt;
&lt;br /&gt;
'''Fórum BCOP-ICANN Edição Especial DNS''' com o painel &amp;quot;'''DNS em Ação: Como os provedores estão implantando as Boas Práticas&amp;quot;''' com '''apresentação''' [https://forumbcop.nic.br/files/apresentacao/arquivo/2428/DNS_KINDNS_Reduzido.pdf aqui] e vídeo [https://www.youtube.com/live/GnYK9UOLXr4?t=10257s aqui].&lt;br /&gt;
&lt;br /&gt;
'''Fórum BCOP Fortaleza''' com a palestra: &amp;quot;'''Recomendações de segurança para provedores&amp;quot;''' com apresentação [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2487/Marcelo_Gondim_Recomendacoes_seguranca_provedores.pdf aqui] e vídeo [https://youtu.be/Qjgb7P3cG8k?t=9237 aqui]'''.''' Os arquivos anexos de configuração: [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2489/Marcelo_Gondim_filtros_edge_huawei.pdf filtros_edge_huawei], [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2490/spoofer.pdf spoofer] e [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2491/filtros_bng_huawei.pdf filtros_bng_huawei].  &lt;br /&gt;
&lt;br /&gt;
'''Moeda recebida pelo NIC.br por contribuir com conhecimento palestrando na Semana de Infraestrutura da Internet no Brasil em 2025:'''&lt;br /&gt;
[[Arquivo:Moeda1.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
'''Moeda comemorativa de 5 anos recebida pelo NIC.br em 2025 por contribuir com conhecimento para a Semana de Capacitação e Camada 8:'''&lt;br /&gt;
[[Arquivo:Moeda2.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
'''Moeda IX Fórum Fortaleza 2026:'''&lt;br /&gt;
[[Arquivo:Frum-bcop-fortaleza-2026 55178462504 o.jpg|esquerda|miniaturadaimagem]]&lt;br /&gt;
[[Arquivo:Frum-bcop-fortaleza-2026 55178206816 o.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
'''Webinar:'''&lt;br /&gt;
&lt;br /&gt;
Proteção e Mitigação de ataques DDoS em 10/09/2024 às 20:00 UTC -3. Site da chamada [https://gdg.community.dev/events/details/google-gdg-sinop-presents-webinar-ao-vivo-protecao-e-mitigacao-de-ataques-ddos/ aqui] e o vídeo da live no Youtube [https://www.youtube.com/live/7VIaoDQaLQE aqui].&lt;br /&gt;
&lt;br /&gt;
'''Podcast:'''&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/live/x4fxtma4eyQ Segurança de Rede e Infraestrutura para 2025: Preparando os ISPs para o futuro!]&lt;br /&gt;
&lt;br /&gt;
'''Contatos:'''&lt;br /&gt;
&lt;br /&gt;
Telegram: '''@Marcelo_Gondim'''&lt;br /&gt;
&lt;br /&gt;
WhatsApp: +55 (22) 99743-9060&lt;br /&gt;
&lt;br /&gt;
E-mail: '''gondim at ispup.com.br'''&lt;br /&gt;
&lt;br /&gt;
Linkedin: https://www.linkedin.com/in/marcelo-gondim-sysadmin/&lt;br /&gt;
&lt;br /&gt;
Meu Github: https://github.com/gondimcodes&lt;br /&gt;
&lt;br /&gt;
== Mini-CV ==&lt;br /&gt;
'''Marcelo Gondim''' começou sua carreira como desenvolvedor de software em COBOL e Clipper entre 1992 e 1995. Em 1996 foi responsável por desenvolver um sistema concorrente com o RENPAC da Embratel para acesso ao SISCOMEX e implantou a Internet para fins comerciais na empresa DATABRAS. Trabalhou como consultor e instrutor de GNU/Linux na Conectiva S/A em 2000. Em 2003 se tornou consultor de diversos Provedores de Internet na Região dos Lagos - RJ e onde acabou se tornando CTO da Nettel Telecomunicações (AS53135) com 42.000 assinantes. Implantou IPv6 iniciando em 2013 e se tornou participante do MANRS com diversas contribuições com artigos e palestras. Trabalhou como Especialista em Redes e SOC (Security Operations Center) na Brasil TecPar AS262907 entre 2022 e 2025, onde implementou boas práticas, tratamentos de incidentes relacionados ao ASN, desenvolveu as estratégias de Mitigação DDoS e uma Rede de DNS Recursivo Anycast espalhada pelo RS, RJ, SP, SC MT e MS, também certificada KINDNS. Fundador da empresa ISPFocus especializada em Tecnologia da Informação e boas práticas para ISPs.&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4069</id>
		<title>Usuário:Gondim</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4069"/>
		<updated>2026-04-01T20:13:33Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Marcelo Gondim da Cunha'''&lt;br /&gt;
[[Arquivo:Gondim paisagem.jpg|esquerda|commoldura]]&lt;br /&gt;
&lt;br /&gt;
'''Contribuições e trabalhos:'''&lt;br /&gt;
&lt;br /&gt;
* Administração de Sistemas Unix-Like desde 1996.&lt;br /&gt;
* Consultor na Conectiva S/A - Unidade Rio em 2000.&lt;br /&gt;
** Autor do projeto TuxFrw - https://github.com/gondimcodes/tuxfrw e https://github.com/gondimcodes/tuxfrw-nft&lt;br /&gt;
* Administração de sistemas BSD pela FreeBSD Brasil em 2010.&lt;br /&gt;
* Direção do AS53135 - Nettel Telecomunicações entre 2003 e 2021 atingindo a marca de 41.000 assinantes. Gerando qualidade na entrega de serviços e implantando boas práticas como: &lt;br /&gt;
&lt;br /&gt;
a) IPv6.&lt;br /&gt;
&lt;br /&gt;
b) MANRS.&lt;br /&gt;
&lt;br /&gt;
c) RPKI.&lt;br /&gt;
&lt;br /&gt;
d) CPEs com firmware baseada na BCOP &amp;lt;nowiki&amp;gt;https://www.m3aawg.org/sites/default/files/lac-bcop-1-m3aawg-v1-portuguese-final.pdf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** SOC Specialist na Brasil TecPar (AS262907) de 2022 a 2025. Um milhão de clientes. Responsável pelas estratégias de mitigação anti-DDoS atendendo as Operações de RJ, SP, RS, SC, MT e MS.&lt;br /&gt;
'''Palestras ministradas:'''&lt;br /&gt;
&lt;br /&gt;
* Semana da Informática UERJ 2002 - TuxFrw.&lt;br /&gt;
* CONISLI 2003 - TuxFrw.&lt;br /&gt;
* CONISLI 2004 - Fazendo compras com Gentoo Linux - Palestra sobre a distribuição Linux e suas ferramentas fantásticas.&lt;br /&gt;
* CONISLI 2004 - OpenVPN - Palestra sobre como criar VPNs seguras com OpenVPN e diferenças entre ele e o IPSec.&lt;br /&gt;
* CONISLI 2005 - SPoP (Security Point of Presence) com OpenVPN - Como utilizar túneis encriptados do OpenVPN para acessar a Internet de forma segura, onde quer que esteja.&lt;br /&gt;
* SECOMP 2005 UNIFEI - TuxFrw.&lt;br /&gt;
&lt;br /&gt;
* Debconf19 2019 - [https://debconf19.debconf.org/talks/4-debian-na-vida-de-uma-operadora-de-telecom/ Debian na vida de uma operadora de Telecom], [https://www.youtube.com/watch?v=vQSTslUZy8k&amp;amp;list=PLYUtdmpYPTTJDtwgD8AtxzFJ9t_URhFMK&amp;amp;index=35 vídeo] e [https://salsa.debian.org/debconf-team/public/share/debconf19/raw/master/slides/4-debian-na-vida-de-uma-operadora-de-telecom.pdf?inline=false pdf].&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=5uOFtkplDts FiqueEmCasaUseDebian - CGNAT com NFTables] e [https://www.youtube.com/watch?v=Wz2IAg6MMlU SysAdmin apps].&lt;br /&gt;
&lt;br /&gt;
'''Artigos desenvolvidos para a comunidade do Brasil Peering Fórum:'''&lt;br /&gt;
&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_na_pratica CGNAT na pratica].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Acesso_via_IPv6_Link-Local Acesso via IPv6 Link-Local].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/MANRS MANRS].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_Bulk_Port_Allocation_com_DPDK CGNAT Bulk Port Allocation com DPDK].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Servidor_de_Logs Servidor de Logs].&lt;br /&gt;
* [[DNS Recursivo Anycast Hyperlocal|DNS Anycast com Hyperlocal]].&lt;br /&gt;
* [[Recomendações sobre Mitigação DDoS]]&lt;br /&gt;
* [[Portas de Amplificação DDoS e Botnets]]&lt;br /&gt;
* [[Static Loop - um erro que pode matar seu ISP/ITP]]&lt;br /&gt;
* [[Identificando e neutralizando uma Botnet]]&lt;br /&gt;
&lt;br /&gt;
'''Tutorial:'''&lt;br /&gt;
&lt;br /&gt;
* [https://bit.ly/2saumHK Segurança de roteamento: MANRS (Mutually Agreed Norms for Routing Security) - Tutoriais NIC.br em 09/12/2019].&lt;br /&gt;
&lt;br /&gt;
'''[https://www.manrs.org/about/advisory-group/members/ MANRS Advisory Group Member (2020-2021)]'''.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=oahQkGx8urY '''Live sobre MANRS com Leonardo Furtado'''].&lt;br /&gt;
&lt;br /&gt;
Criação da Wiki ISPUP! em 24/12/2022.&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 6 do NIC.br 28/04/2023''' - &amp;quot;'''CONCEITOS E IMPLEMENTAÇÃO DE CGNAT'''&amp;quot;. Material [https://semanacap.bcp.nic.br/6-online/ aqui] e vídeo aula [https://www.youtube.com/watch?v=1q7J3NkQVSc aqui].&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 10 do NIC.br 01/07/2025''' - &amp;quot;'''Teste para padrões técnicos modernos de Internet e segurança: IPv6, DNSSEC, TLS, HTTPS e HSTS'''&amp;quot;'''.''' Material [https://semanacap.bcp.nic.br/semana-de-capacitacao-online-edicao-10-2025/ aqui] e vídeo aula [https://www.youtube.com/watch?v=55RBnGQhi2o aqui].&lt;br /&gt;
&lt;br /&gt;
'''IX Fórum Regional Sudeste (Rio de Janeiro) 24/10/2025''' com a palestra &amp;quot;'''Segurança com o pé direito'''&amp;quot; pode ser baixada [https://regional.forum.ix.br/files/apresentacao/arquivo/2307/gondim.pdf aqui].&lt;br /&gt;
&lt;br /&gt;
'''Fórum BCOP-ICANN Edição Especial DNS''' com o painel &amp;quot;'''DNS em Ação: Como os provedores estão implantando as Boas Práticas&amp;quot;''' com '''apresentação''' [https://forumbcop.nic.br/files/apresentacao/arquivo/2428/DNS_KINDNS_Reduzido.pdf aqui] e vídeo [https://www.youtube.com/live/GnYK9UOLXr4?t=10257s aqui].&lt;br /&gt;
&lt;br /&gt;
'''Fórum BCOP Fortaleza''' com a palestra: &amp;quot;'''Recomendações de segurança para provedores&amp;quot;''' com apresentação [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2487/Marcelo_Gondim_Recomendacoes_seguranca_provedores.pdf aqui] e vídeo [https://youtu.be/Qjgb7P3cG8k?t=9237 aqui]'''.''' Os arquivos anexos de configuração: [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2489/Marcelo_Gondim_filtros_edge_huawei.pdf filtros_edge_huawei], [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2490/spoofer.pdf spoofer] e [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2491/filtros_bng_huawei.pdf filtros_bng_huawei].  &lt;br /&gt;
&lt;br /&gt;
'''Moeda recebida pelo NIC.br por contribuir com conhecimento palestrando na Semana de Infraestrutura da Internet no Brasil em 2025:'''&lt;br /&gt;
[[Arquivo:Moeda1.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
'''Moeda comemorativa de 5 anos recebida pelo NIC.br em 2025 por contribuir com conhecimento para a Semana de Capacitação e Camada 8:'''&lt;br /&gt;
[[Arquivo:Moeda2.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
'''Moeda IX Fórum Fortaleza 2026:'''&lt;br /&gt;
[[Arquivo:Frum-bcop-fortaleza-2026 55178462504 o.jpg|esquerda|miniaturadaimagem]]&lt;br /&gt;
[[Arquivo:Frum-bcop-fortaleza-2026 55178206816 o.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
&lt;br /&gt;
'''Webinar:'''&lt;br /&gt;
&lt;br /&gt;
Proteção e Mitigação de ataques DDoS em 10/09/2024 às 20:00 UTC -3. Site da chamada [https://gdg.community.dev/events/details/google-gdg-sinop-presents-webinar-ao-vivo-protecao-e-mitigacao-de-ataques-ddos/ aqui] e o vídeo da live no Youtube [https://www.youtube.com/live/7VIaoDQaLQE aqui].&lt;br /&gt;
&lt;br /&gt;
'''Podcast:'''&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/live/x4fxtma4eyQ Segurança de Rede e Infraestrutura para 2025: Preparando os ISPs para o futuro!]&lt;br /&gt;
&lt;br /&gt;
'''Contatos:'''&lt;br /&gt;
&lt;br /&gt;
Telegram: '''@Marcelo_Gondim'''&lt;br /&gt;
&lt;br /&gt;
WhatsApp: +55 (22) 99743-9060&lt;br /&gt;
&lt;br /&gt;
E-mail: '''gondim at ispup.com.br'''&lt;br /&gt;
&lt;br /&gt;
Linkedin: https://www.linkedin.com/in/marcelo-gondim-sysadmin/&lt;br /&gt;
&lt;br /&gt;
Meu Github: https://github.com/gondimcodes&lt;br /&gt;
&lt;br /&gt;
== Mini-CV ==&lt;br /&gt;
'''Marcelo Gondim''' começou sua carreira como desenvolvedor de software em COBOL e Clipper entre 1992 e 1995. Em 1996 foi responsável por desenvolver um sistema concorrente com o RENPAC da Embratel para acesso ao SISCOMEX e implantou a Internet para fins comerciais na empresa DATABRAS. Trabalhou como consultor e instrutor de GNU/Linux na Conectiva S/A em 2000. Em 2003 se tornou consultor de diversos Provedores de Internet na Região dos Lagos - RJ e onde acabou se tornando CTO da Nettel Telecomunicações (AS53135) com 42.000 assinantes. Implantou IPv6 iniciando em 2013 e se tornou participante do MANRS com diversas contribuições com artigos e palestras. Trabalhou como Especialista em Redes e SOC (Security Operations Center) na Brasil TecPar AS262907 entre 2022 e 2025, onde implementou boas práticas, tratamentos de incidentes relacionados ao ASN, desenvolveu as estratégias de Mitigação DDoS e uma Rede de DNS Recursivo Anycast espalhada pelo RS, RJ, SP, SC MT e MS, também certificada KINDNS. Fundador da empresa ISPFocus especializada em Tecnologia da Informação e boas práticas para ISPs.&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4068</id>
		<title>Usuário:Gondim</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4068"/>
		<updated>2026-04-01T20:13:19Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Marcelo Gondim da Cunha'''&lt;br /&gt;
[[Arquivo:Gondim paisagem.jpg|esquerda|commoldura]]&lt;br /&gt;
&lt;br /&gt;
'''Contribuições e trabalhos:'''&lt;br /&gt;
&lt;br /&gt;
* Administração de Sistemas Unix-Like desde 1996.&lt;br /&gt;
* Consultor na Conectiva S/A - Unidade Rio em 2000.&lt;br /&gt;
** Autor do projeto TuxFrw - https://github.com/gondimcodes/tuxfrw e https://github.com/gondimcodes/tuxfrw-nft&lt;br /&gt;
* Administração de sistemas BSD pela FreeBSD Brasil em 2010.&lt;br /&gt;
* Direção do AS53135 - Nettel Telecomunicações entre 2003 e 2021 atingindo a marca de 41.000 assinantes. Gerando qualidade na entrega de serviços e implantando boas práticas como: &lt;br /&gt;
&lt;br /&gt;
a) IPv6.&lt;br /&gt;
&lt;br /&gt;
b) MANRS.&lt;br /&gt;
&lt;br /&gt;
c) RPKI.&lt;br /&gt;
&lt;br /&gt;
d) CPEs com firmware baseada na BCOP &amp;lt;nowiki&amp;gt;https://www.m3aawg.org/sites/default/files/lac-bcop-1-m3aawg-v1-portuguese-final.pdf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** SOC Specialist na Brasil TecPar (AS262907) de 2022 a 2025. Um milhão de clientes. Responsável pelas estratégias de mitigação anti-DDoS atendendo as Operações de RJ, SP, RS, SC, MT e MS.&lt;br /&gt;
'''Palestras ministradas:'''&lt;br /&gt;
&lt;br /&gt;
* Semana da Informática UERJ 2002 - TuxFrw.&lt;br /&gt;
* CONISLI 2003 - TuxFrw.&lt;br /&gt;
* CONISLI 2004 - Fazendo compras com Gentoo Linux - Palestra sobre a distribuição Linux e suas ferramentas fantásticas.&lt;br /&gt;
* CONISLI 2004 - OpenVPN - Palestra sobre como criar VPNs seguras com OpenVPN e diferenças entre ele e o IPSec.&lt;br /&gt;
* CONISLI 2005 - SPoP (Security Point of Presence) com OpenVPN - Como utilizar túneis encriptados do OpenVPN para acessar a Internet de forma segura, onde quer que esteja.&lt;br /&gt;
* SECOMP 2005 UNIFEI - TuxFrw.&lt;br /&gt;
&lt;br /&gt;
* Debconf19 2019 - [https://debconf19.debconf.org/talks/4-debian-na-vida-de-uma-operadora-de-telecom/ Debian na vida de uma operadora de Telecom], [https://www.youtube.com/watch?v=vQSTslUZy8k&amp;amp;list=PLYUtdmpYPTTJDtwgD8AtxzFJ9t_URhFMK&amp;amp;index=35 vídeo] e [https://salsa.debian.org/debconf-team/public/share/debconf19/raw/master/slides/4-debian-na-vida-de-uma-operadora-de-telecom.pdf?inline=false pdf].&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=5uOFtkplDts FiqueEmCasaUseDebian - CGNAT com NFTables] e [https://www.youtube.com/watch?v=Wz2IAg6MMlU SysAdmin apps].&lt;br /&gt;
&lt;br /&gt;
'''Artigos desenvolvidos para a comunidade do Brasil Peering Fórum:'''&lt;br /&gt;
&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_na_pratica CGNAT na pratica].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Acesso_via_IPv6_Link-Local Acesso via IPv6 Link-Local].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/MANRS MANRS].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_Bulk_Port_Allocation_com_DPDK CGNAT Bulk Port Allocation com DPDK].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Servidor_de_Logs Servidor de Logs].&lt;br /&gt;
* [[DNS Recursivo Anycast Hyperlocal|DNS Anycast com Hyperlocal]].&lt;br /&gt;
* [[Recomendações sobre Mitigação DDoS]]&lt;br /&gt;
* [[Portas de Amplificação DDoS e Botnets]]&lt;br /&gt;
* [[Static Loop - um erro que pode matar seu ISP/ITP]]&lt;br /&gt;
* [[Identificando e neutralizando uma Botnet]]&lt;br /&gt;
&lt;br /&gt;
'''Tutorial:'''&lt;br /&gt;
&lt;br /&gt;
* [https://bit.ly/2saumHK Segurança de roteamento: MANRS (Mutually Agreed Norms for Routing Security) - Tutoriais NIC.br em 09/12/2019].&lt;br /&gt;
&lt;br /&gt;
'''[https://www.manrs.org/about/advisory-group/members/ MANRS Advisory Group Member (2020-2021)]'''.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=oahQkGx8urY '''Live sobre MANRS com Leonardo Furtado'''].&lt;br /&gt;
&lt;br /&gt;
Criação da Wiki ISPUP! em 24/12/2022.&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 6 do NIC.br 28/04/2023''' - &amp;quot;'''CONCEITOS E IMPLEMENTAÇÃO DE CGNAT'''&amp;quot;. Material [https://semanacap.bcp.nic.br/6-online/ aqui] e vídeo aula [https://www.youtube.com/watch?v=1q7J3NkQVSc aqui].&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 10 do NIC.br 01/07/2025''' - &amp;quot;'''Teste para padrões técnicos modernos de Internet e segurança: IPv6, DNSSEC, TLS, HTTPS e HSTS'''&amp;quot;'''.''' Material [https://semanacap.bcp.nic.br/semana-de-capacitacao-online-edicao-10-2025/ aqui] e vídeo aula [https://www.youtube.com/watch?v=55RBnGQhi2o aqui].&lt;br /&gt;
&lt;br /&gt;
'''IX Fórum Regional Sudeste (Rio de Janeiro) 24/10/2025''' com a palestra &amp;quot;'''Segurança com o pé direito'''&amp;quot; pode ser baixada [https://regional.forum.ix.br/files/apresentacao/arquivo/2307/gondim.pdf aqui].&lt;br /&gt;
&lt;br /&gt;
'''Fórum BCOP-ICANN Edição Especial DNS''' com o painel &amp;quot;'''DNS em Ação: Como os provedores estão implantando as Boas Práticas&amp;quot;''' com '''apresentação''' [https://forumbcop.nic.br/files/apresentacao/arquivo/2428/DNS_KINDNS_Reduzido.pdf aqui] e vídeo [https://www.youtube.com/live/GnYK9UOLXr4?t=10257s aqui].&lt;br /&gt;
&lt;br /&gt;
'''Fórum BCOP Fortaleza''' com a palestra: &amp;quot;'''Recomendações de segurança para provedores&amp;quot;''' com apresentação [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2487/Marcelo_Gondim_Recomendacoes_seguranca_provedores.pdf aqui] e vídeo [https://youtu.be/Qjgb7P3cG8k?t=9237 aqui]'''.''' Os arquivos anexos de configuração: [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2489/Marcelo_Gondim_filtros_edge_huawei.pdf filtros_edge_huawei], [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2490/spoofer.pdf spoofer] e [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2491/filtros_bng_huawei.pdf filtros_bng_huawei].  &lt;br /&gt;
&lt;br /&gt;
'''Moeda recebida pelo NIC.br por contribuir com conhecimento palestrando na Semana de Infraestrutura da Internet no Brasil em 2025:'''&lt;br /&gt;
[[Arquivo:Moeda1.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
'''Moeda comemorativa de 5 anos recebida pelo NIC.br em 2025 por contribuir com conhecimento para a Semana de Capacitação e Camada 8:'''&lt;br /&gt;
[[Arquivo:Moeda2.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
'''Moeda IX Fórum Fortaleza 2026:'''&lt;br /&gt;
[[Arquivo:Frum-bcop-fortaleza-2026 55178462504 o.jpg|esquerda|miniaturadaimagem]]&lt;br /&gt;
[[Arquivo:Frum-bcop-fortaleza-2026 55178206816 o.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
'''Webinar:'''&lt;br /&gt;
&lt;br /&gt;
Proteção e Mitigação de ataques DDoS em 10/09/2024 às 20:00 UTC -3. Site da chamada [https://gdg.community.dev/events/details/google-gdg-sinop-presents-webinar-ao-vivo-protecao-e-mitigacao-de-ataques-ddos/ aqui] e o vídeo da live no Youtube [https://www.youtube.com/live/7VIaoDQaLQE aqui].&lt;br /&gt;
&lt;br /&gt;
'''Podcast:'''&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/live/x4fxtma4eyQ Segurança de Rede e Infraestrutura para 2025: Preparando os ISPs para o futuro!]&lt;br /&gt;
&lt;br /&gt;
'''Contatos:'''&lt;br /&gt;
&lt;br /&gt;
Telegram: '''@Marcelo_Gondim'''&lt;br /&gt;
&lt;br /&gt;
WhatsApp: +55 (22) 99743-9060&lt;br /&gt;
&lt;br /&gt;
E-mail: '''gondim at ispup.com.br'''&lt;br /&gt;
&lt;br /&gt;
Linkedin: https://www.linkedin.com/in/marcelo-gondim-sysadmin/&lt;br /&gt;
&lt;br /&gt;
Meu Github: https://github.com/gondimcodes&lt;br /&gt;
&lt;br /&gt;
== Mini-CV ==&lt;br /&gt;
'''Marcelo Gondim''' começou sua carreira como desenvolvedor de software em COBOL e Clipper entre 1992 e 1995. Em 1996 foi responsável por desenvolver um sistema concorrente com o RENPAC da Embratel para acesso ao SISCOMEX e implantou a Internet para fins comerciais na empresa DATABRAS. Trabalhou como consultor e instrutor de GNU/Linux na Conectiva S/A em 2000. Em 2003 se tornou consultor de diversos Provedores de Internet na Região dos Lagos - RJ e onde acabou se tornando CTO da Nettel Telecomunicações (AS53135) com 42.000 assinantes. Implantou IPv6 iniciando em 2013 e se tornou participante do MANRS com diversas contribuições com artigos e palestras. Trabalhou como Especialista em Redes e SOC (Security Operations Center) na Brasil TecPar AS262907 entre 2022 e 2025, onde implementou boas práticas, tratamentos de incidentes relacionados ao ASN, desenvolveu as estratégias de Mitigação DDoS e uma Rede de DNS Recursivo Anycast espalhada pelo RS, RJ, SP, SC MT e MS, também certificada KINDNS. Fundador da empresa ISPFocus especializada em Tecnologia da Informação e boas práticas para ISPs.&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Frum-bcop-fortaleza-2026_55178206816_o.jpg&amp;diff=4067</id>
		<title>Arquivo:Frum-bcop-fortaleza-2026 55178206816 o.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Frum-bcop-fortaleza-2026_55178206816_o.jpg&amp;diff=4067"/>
		<updated>2026-04-01T20:12:59Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Frum-bcop-fortaleza-2026 55178206816 o&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Frum-bcop-fortaleza-2026_55178462504_o.jpg&amp;diff=4066</id>
		<title>Arquivo:Frum-bcop-fortaleza-2026 55178462504 o.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Frum-bcop-fortaleza-2026_55178462504_o.jpg&amp;diff=4066"/>
		<updated>2026-04-01T20:12:11Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Frum-bcop-fortaleza-2026 55178462504 o&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4065</id>
		<title>Usuário:Gondim</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4065"/>
		<updated>2026-04-01T20:11:12Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Marcelo Gondim da Cunha'''&lt;br /&gt;
[[Arquivo:Gondim paisagem.jpg|esquerda|commoldura]]&lt;br /&gt;
&lt;br /&gt;
'''Contribuições e trabalhos:'''&lt;br /&gt;
&lt;br /&gt;
* Administração de Sistemas Unix-Like desde 1996.&lt;br /&gt;
* Consultor na Conectiva S/A - Unidade Rio em 2000.&lt;br /&gt;
** Autor do projeto TuxFrw - https://github.com/gondimcodes/tuxfrw e https://github.com/gondimcodes/tuxfrw-nft&lt;br /&gt;
* Administração de sistemas BSD pela FreeBSD Brasil em 2010.&lt;br /&gt;
* Direção do AS53135 - Nettel Telecomunicações entre 2003 e 2021 atingindo a marca de 41.000 assinantes. Gerando qualidade na entrega de serviços e implantando boas práticas como: &lt;br /&gt;
&lt;br /&gt;
a) IPv6.&lt;br /&gt;
&lt;br /&gt;
b) MANRS.&lt;br /&gt;
&lt;br /&gt;
c) RPKI.&lt;br /&gt;
&lt;br /&gt;
d) CPEs com firmware baseada na BCOP &amp;lt;nowiki&amp;gt;https://www.m3aawg.org/sites/default/files/lac-bcop-1-m3aawg-v1-portuguese-final.pdf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** SOC Specialist na Brasil TecPar (AS262907) de 2022 a 2025. Um milhão de clientes. Responsável pelas estratégias de mitigação anti-DDoS atendendo as Operações de RJ, SP, RS, SC, MT e MS.&lt;br /&gt;
'''Palestras ministradas:'''&lt;br /&gt;
&lt;br /&gt;
* Semana da Informática UERJ 2002 - TuxFrw.&lt;br /&gt;
* CONISLI 2003 - TuxFrw.&lt;br /&gt;
* CONISLI 2004 - Fazendo compras com Gentoo Linux - Palestra sobre a distribuição Linux e suas ferramentas fantásticas.&lt;br /&gt;
* CONISLI 2004 - OpenVPN - Palestra sobre como criar VPNs seguras com OpenVPN e diferenças entre ele e o IPSec.&lt;br /&gt;
* CONISLI 2005 - SPoP (Security Point of Presence) com OpenVPN - Como utilizar túneis encriptados do OpenVPN para acessar a Internet de forma segura, onde quer que esteja.&lt;br /&gt;
* SECOMP 2005 UNIFEI - TuxFrw.&lt;br /&gt;
&lt;br /&gt;
* Debconf19 2019 - [https://debconf19.debconf.org/talks/4-debian-na-vida-de-uma-operadora-de-telecom/ Debian na vida de uma operadora de Telecom], [https://www.youtube.com/watch?v=vQSTslUZy8k&amp;amp;list=PLYUtdmpYPTTJDtwgD8AtxzFJ9t_URhFMK&amp;amp;index=35 vídeo] e [https://salsa.debian.org/debconf-team/public/share/debconf19/raw/master/slides/4-debian-na-vida-de-uma-operadora-de-telecom.pdf?inline=false pdf].&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=5uOFtkplDts FiqueEmCasaUseDebian - CGNAT com NFTables] e [https://www.youtube.com/watch?v=Wz2IAg6MMlU SysAdmin apps].&lt;br /&gt;
&lt;br /&gt;
'''Artigos desenvolvidos para a comunidade do Brasil Peering Fórum:'''&lt;br /&gt;
&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_na_pratica CGNAT na pratica].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Acesso_via_IPv6_Link-Local Acesso via IPv6 Link-Local].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/MANRS MANRS].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_Bulk_Port_Allocation_com_DPDK CGNAT Bulk Port Allocation com DPDK].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Servidor_de_Logs Servidor de Logs].&lt;br /&gt;
* [[DNS Recursivo Anycast Hyperlocal|DNS Anycast com Hyperlocal]].&lt;br /&gt;
* [[Recomendações sobre Mitigação DDoS]]&lt;br /&gt;
* [[Portas de Amplificação DDoS e Botnets]]&lt;br /&gt;
* [[Static Loop - um erro que pode matar seu ISP/ITP]]&lt;br /&gt;
* [[Identificando e neutralizando uma Botnet]]&lt;br /&gt;
&lt;br /&gt;
'''Tutorial:'''&lt;br /&gt;
&lt;br /&gt;
* [https://bit.ly/2saumHK Segurança de roteamento: MANRS (Mutually Agreed Norms for Routing Security) - Tutoriais NIC.br em 09/12/2019].&lt;br /&gt;
&lt;br /&gt;
'''[https://www.manrs.org/about/advisory-group/members/ MANRS Advisory Group Member (2020-2021)]'''.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=oahQkGx8urY '''Live sobre MANRS com Leonardo Furtado'''].&lt;br /&gt;
&lt;br /&gt;
Criação da Wiki ISPUP! em 24/12/2022.&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 6 do NIC.br 28/04/2023''' - &amp;quot;'''CONCEITOS E IMPLEMENTAÇÃO DE CGNAT'''&amp;quot;. Material [https://semanacap.bcp.nic.br/6-online/ aqui] e vídeo aula [https://www.youtube.com/watch?v=1q7J3NkQVSc aqui].&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 10 do NIC.br 01/07/2025''' - &amp;quot;'''Teste para padrões técnicos modernos de Internet e segurança: IPv6, DNSSEC, TLS, HTTPS e HSTS'''&amp;quot;'''.''' Material [https://semanacap.bcp.nic.br/semana-de-capacitacao-online-edicao-10-2025/ aqui] e vídeo aula [https://www.youtube.com/watch?v=55RBnGQhi2o aqui].&lt;br /&gt;
&lt;br /&gt;
'''IX Fórum Regional Sudeste (Rio de Janeiro) 24/10/2025''' com a palestra &amp;quot;'''Segurança com o pé direito'''&amp;quot; pode ser baixada [https://regional.forum.ix.br/files/apresentacao/arquivo/2307/gondim.pdf aqui].&lt;br /&gt;
&lt;br /&gt;
'''Fórum BCOP-ICANN Edição Especial DNS''' com o painel &amp;quot;'''DNS em Ação: Como os provedores estão implantando as Boas Práticas&amp;quot;''' com '''apresentação''' [https://forumbcop.nic.br/files/apresentacao/arquivo/2428/DNS_KINDNS_Reduzido.pdf aqui] e vídeo [https://www.youtube.com/live/GnYK9UOLXr4?t=10257s aqui].&lt;br /&gt;
&lt;br /&gt;
'''Fórum BCOP Fortaleza''' com a palestra: &amp;quot;'''Recomendações de segurança para provedores&amp;quot;''' com apresentação [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2487/Marcelo_Gondim_Recomendacoes_seguranca_provedores.pdf aqui] e vídeo [https://youtu.be/Qjgb7P3cG8k?t=9237 aqui]'''.''' Os arquivos anexos de configuração: [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2489/Marcelo_Gondim_filtros_edge_huawei.pdf filtros_edge_huawei], [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2490/spoofer.pdf spoofer] e [https://fortaleza.forumbcop.nic.br/files/apresentacao/arquivo/2491/filtros_bng_huawei.pdf filtros_bng_huawei].  &lt;br /&gt;
&lt;br /&gt;
'''Moeda recebida pelo NIC.br por contribuir com conhecimento palestrando na Semana de Infraestrutura da Internet no Brasil em 2025:'''&lt;br /&gt;
[[Arquivo:Moeda1.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
'''Moeda comemorativa de 5 anos recebida pelo NIC.br em 2025 por contribuir com conhecimento para a Semana de Capacitação e Camada 8:'''&lt;br /&gt;
[[Arquivo:Moeda2.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
'''Webinar:'''&lt;br /&gt;
&lt;br /&gt;
Proteção e Mitigação de ataques DDoS em 10/09/2024 às 20:00 UTC -3. Site da chamada [https://gdg.community.dev/events/details/google-gdg-sinop-presents-webinar-ao-vivo-protecao-e-mitigacao-de-ataques-ddos/ aqui] e o vídeo da live no Youtube [https://www.youtube.com/live/7VIaoDQaLQE aqui].&lt;br /&gt;
&lt;br /&gt;
'''Podcast:'''&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/live/x4fxtma4eyQ Segurança de Rede e Infraestrutura para 2025: Preparando os ISPs para o futuro!]&lt;br /&gt;
&lt;br /&gt;
'''Contatos:'''&lt;br /&gt;
&lt;br /&gt;
Telegram: '''@Marcelo_Gondim'''&lt;br /&gt;
&lt;br /&gt;
WhatsApp: +55 (22) 99743-9060&lt;br /&gt;
&lt;br /&gt;
E-mail: '''gondim at ispup.com.br'''&lt;br /&gt;
&lt;br /&gt;
Linkedin: https://www.linkedin.com/in/marcelo-gondim-sysadmin/&lt;br /&gt;
&lt;br /&gt;
Meu Github: https://github.com/gondimcodes&lt;br /&gt;
&lt;br /&gt;
== Mini-CV ==&lt;br /&gt;
'''Marcelo Gondim''' começou sua carreira como desenvolvedor de software em COBOL e Clipper entre 1992 e 1995. Em 1996 foi responsável por desenvolver um sistema concorrente com o RENPAC da Embratel para acesso ao SISCOMEX e implantou a Internet para fins comerciais na empresa DATABRAS. Trabalhou como consultor e instrutor de GNU/Linux na Conectiva S/A em 2000. Em 2003 se tornou consultor de diversos Provedores de Internet na Região dos Lagos - RJ e onde acabou se tornando CTO da Nettel Telecomunicações (AS53135) com 42.000 assinantes. Implantou IPv6 iniciando em 2013 e se tornou participante do MANRS com diversas contribuições com artigos e palestras. Trabalhou como Especialista em Redes e SOC (Security Operations Center) na Brasil TecPar AS262907 entre 2022 e 2025, onde implementou boas práticas, tratamentos de incidentes relacionados ao ASN, desenvolveu as estratégias de Mitigação DDoS e uma Rede de DNS Recursivo Anycast espalhada pelo RS, RJ, SP, SC MT e MS, também certificada KINDNS. Fundador da empresa ISPFocus especializada em Tecnologia da Informação e boas práticas para ISPs.&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4028</id>
		<title>Usuário:Gondim</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4028"/>
		<updated>2026-01-20T16:25:08Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Marcelo Gondim da Cunha'''&lt;br /&gt;
[[Arquivo:Gondim paisagem.jpg|esquerda|commoldura]]&lt;br /&gt;
&lt;br /&gt;
'''Contribuições e trabalhos:'''&lt;br /&gt;
&lt;br /&gt;
* Administração de Sistemas Unix-Like desde 1996.&lt;br /&gt;
* Consultor na Conectiva S/A - Unidade Rio em 2000.&lt;br /&gt;
** Autor do projeto TuxFrw - https://github.com/gondimcodes/tuxfrw e https://github.com/gondimcodes/tuxfrw-nft&lt;br /&gt;
* Administração de sistemas BSD pela FreeBSD Brasil em 2010.&lt;br /&gt;
* Direção do AS53135 - Nettel Telecomunicações entre 2003 e 2021 atingindo a marca de 41.000 assinantes. Gerando qualidade na entrega de serviços e implantando boas práticas como: &lt;br /&gt;
&lt;br /&gt;
a) IPv6.&lt;br /&gt;
&lt;br /&gt;
b) MANRS.&lt;br /&gt;
&lt;br /&gt;
c) RPKI.&lt;br /&gt;
&lt;br /&gt;
d) CPEs com firmware baseada na BCOP &amp;lt;nowiki&amp;gt;https://www.m3aawg.org/sites/default/files/lac-bcop-1-m3aawg-v1-portuguese-final.pdf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** SOC Specialist na Brasil TecPar (AS262907) de 2022 a 2025. Um milhão de clientes. Responsável pelas estratégias de mitigação anti-DDoS atendendo as Operações de RJ, SP, RS, SC, MT e MS.&lt;br /&gt;
'''Palestras ministradas:'''&lt;br /&gt;
&lt;br /&gt;
* Semana da Informática UERJ 2002 - TuxFrw.&lt;br /&gt;
* CONISLI 2003 - TuxFrw.&lt;br /&gt;
* CONISLI 2004 - Fazendo compras com Gentoo Linux - Palestra sobre a distribuição Linux e suas ferramentas fantásticas.&lt;br /&gt;
* CONISLI 2004 - OpenVPN - Palestra sobre como criar VPNs seguras com OpenVPN e diferenças entre ele e o IPSec.&lt;br /&gt;
* CONISLI 2005 - SPoP (Security Point of Presence) com OpenVPN - Como utilizar túneis encriptados do OpenVPN para acessar a Internet de forma segura, onde quer que esteja.&lt;br /&gt;
* SECOMP 2005 UNIFEI - TuxFrw.&lt;br /&gt;
&lt;br /&gt;
* Debconf19 2019 - [https://debconf19.debconf.org/talks/4-debian-na-vida-de-uma-operadora-de-telecom/ Debian na vida de uma operadora de Telecom], [https://www.youtube.com/watch?v=vQSTslUZy8k&amp;amp;list=PLYUtdmpYPTTJDtwgD8AtxzFJ9t_URhFMK&amp;amp;index=35 vídeo] e [https://salsa.debian.org/debconf-team/public/share/debconf19/raw/master/slides/4-debian-na-vida-de-uma-operadora-de-telecom.pdf?inline=false pdf].&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=5uOFtkplDts FiqueEmCasaUseDebian - CGNAT com NFTables] e [https://www.youtube.com/watch?v=Wz2IAg6MMlU SysAdmin apps].&lt;br /&gt;
&lt;br /&gt;
'''Artigos desenvolvidos para a comunidade do Brasil Peering Fórum:'''&lt;br /&gt;
&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_na_pratica CGNAT na pratica].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Acesso_via_IPv6_Link-Local Acesso via IPv6 Link-Local].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/MANRS MANRS].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_Bulk_Port_Allocation_com_DPDK CGNAT Bulk Port Allocation com DPDK].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Servidor_de_Logs Servidor de Logs].&lt;br /&gt;
* [[DNS Recursivo Anycast Hyperlocal|DNS Anycast com Hyperlocal]].&lt;br /&gt;
* [[Recomendações sobre Mitigação DDoS]]&lt;br /&gt;
* [[Portas de Amplificação DDoS e Botnets]]&lt;br /&gt;
* [[Static Loop - um erro que pode matar seu ISP/ITP]]&lt;br /&gt;
* [[Identificando e neutralizando uma Botnet]]&lt;br /&gt;
&lt;br /&gt;
'''Tutorial:'''&lt;br /&gt;
&lt;br /&gt;
* [https://bit.ly/2saumHK Segurança de roteamento: MANRS (Mutually Agreed Norms for Routing Security) - Tutoriais NIC.br em 09/12/2019].&lt;br /&gt;
&lt;br /&gt;
'''[https://www.manrs.org/about/advisory-group/members/ MANRS Advisory Group Member (2020-2021)]'''.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=oahQkGx8urY '''Live sobre MANRS com Leonardo Furtado'''].&lt;br /&gt;
&lt;br /&gt;
Criação da Wiki ISPUP! em 24/12/2022.&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 6 do NIC.br 28/04/2023''' - &amp;quot;'''CONCEITOS E IMPLEMENTAÇÃO DE CGNAT'''&amp;quot;. Material [https://semanacap.bcp.nic.br/6-online/ aqui] e vídeo aula [https://www.youtube.com/watch?v=1q7J3NkQVSc aqui].&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 10 do NIC.br 01/07/2025''' - &amp;quot;'''Teste para padrões técnicos modernos de Internet e segurança: IPv6, DNSSEC, TLS, HTTPS e HSTS'''&amp;quot;'''.''' Material [https://semanacap.bcp.nic.br/semana-de-capacitacao-online-edicao-10-2025/ aqui] e vídeo aula [https://www.youtube.com/watch?v=55RBnGQhi2o aqui].&lt;br /&gt;
&lt;br /&gt;
'''IX Fórum Regional Sudeste (Rio de Janeiro) 24/10/2025''' com a palestra &amp;quot;'''Segurança com o pé direito'''&amp;quot; pode ser baixada [https://regional.forum.ix.br/files/apresentacao/arquivo/2307/gondim.pdf aqui].&lt;br /&gt;
&lt;br /&gt;
'''Fórum BCOP-ICANN Edição Especial DNS''' com o painel &amp;quot;'''DNS em Ação: Como os provedores estão implantando as Boas Práticas&amp;quot;''' com '''apresentação''' [https://forumbcop.nic.br/files/apresentacao/arquivo/2428/DNS_KINDNS_Reduzido.pdf aqui] e vídeo [https://www.youtube.com/live/GnYK9UOLXr4?t=10257s aqui].&lt;br /&gt;
&lt;br /&gt;
'''Moeda recebida pelo NIC.br por contribuir com conhecimento palestrando na Semana de Infraestrutura da Internet no Brasil em 2025:'''&lt;br /&gt;
[[Arquivo:Moeda1.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
'''Moeda comemorativa de 5 anos recebida pelo NIC.br em 2025 por contribuir com conhecimento para a Semana de Capacitação e Camada 8:'''&lt;br /&gt;
[[Arquivo:Moeda2.jpg|nenhum|miniaturadaimagem]]&lt;br /&gt;
'''Webinar:'''&lt;br /&gt;
&lt;br /&gt;
Proteção e Mitigação de ataques DDoS em 10/09/2024 às 20:00 UTC -3. Site da chamada [https://gdg.community.dev/events/details/google-gdg-sinop-presents-webinar-ao-vivo-protecao-e-mitigacao-de-ataques-ddos/ aqui] e o vídeo da live no Youtube [https://www.youtube.com/live/7VIaoDQaLQE aqui].&lt;br /&gt;
&lt;br /&gt;
'''Podcast:'''&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/live/x4fxtma4eyQ Segurança de Rede e Infraestrutura para 2025: Preparando os ISPs para o futuro!]&lt;br /&gt;
&lt;br /&gt;
'''Contatos:'''&lt;br /&gt;
&lt;br /&gt;
Telegram: '''@Marcelo_Gondim'''&lt;br /&gt;
&lt;br /&gt;
WhatsApp: +55 (22) 99743-9060&lt;br /&gt;
&lt;br /&gt;
E-mail: '''gondim at ispup.com.br'''&lt;br /&gt;
&lt;br /&gt;
Linkedin: https://www.linkedin.com/in/marcelo-gondim-sysadmin/&lt;br /&gt;
&lt;br /&gt;
Meu Github: https://github.com/gondimcodes&lt;br /&gt;
&lt;br /&gt;
== Mini-CV ==&lt;br /&gt;
'''Marcelo Gondim''' começou sua carreira como desenvolvedor de software em COBOL e Clipper entre 1992 e 1995. Em 1996 foi responsável por desenvolver um sistema concorrente com o RENPAC da Embratel para acesso ao SISCOMEX e implantou a Internet para fins comerciais na empresa DATABRAS. Trabalhou como consultor e instrutor de GNU/Linux na Conectiva S/A em 2000. Em 2003 se tornou consultor de diversos Provedores de Internet na Região dos Lagos - RJ e onde acabou se tornando CTO da Nettel Telecomunicações (AS53135) com 42.000 assinantes. Implantou IPv6 iniciando em 2013 e se tornou participante do MANRS com diversas contribuições com artigos e palestras. Trabalhou como Especialista em Redes e SOC (Security Operations Center) na Brasil TecPar AS262907 entre 2022 e 2025, onde implementou boas práticas, tratamentos de incidentes relacionados ao ASN, desenvolveu as estratégias de Mitigação DDoS e uma Rede de DNS Recursivo Anycast espalhada pelo RS, RJ, SP, SC MT e MS, também certificada KINDNS. Fundador da empresa ISPFocus especializada em Tecnologia da Informação e boas práticas para ISPs.&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Moeda2.jpg&amp;diff=4027</id>
		<title>Arquivo:Moeda2.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Moeda2.jpg&amp;diff=4027"/>
		<updated>2026-01-20T16:24:42Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Moeda2&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Moeda1.jpg&amp;diff=4026</id>
		<title>Arquivo:Moeda1.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Moeda1.jpg&amp;diff=4026"/>
		<updated>2026-01-20T16:23:43Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Moeda1&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=4006</id>
		<title>DNS Recursivo Anycast Hyperlocal</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=4006"/>
		<updated>2026-01-15T02:19:57Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
==Introdução==&lt;br /&gt;
Você sabe como funciona a Internet? Essa é uma pergunta que meu amigo '''Thiago Ayub''' sempre faz aos seus candidatos à vagas de emprego e não importa o quanto tenham de experiência em '''Engenharia de Redes''', todos sempre travam nesse momento. Todos estão sempre prontos e preparados para resolver os problemas mais cabeludos em '''BGP''', '''OSPF''', '''MPLS''', etc mas travam com essa simples pergunta. Para contextualizar e visualizarmos melhor vamos nos atentar à imagem abaixo e uma explicação simplificada de como funciona:&lt;br /&gt;
[[Arquivo:Dns hierarquia.png|esquerda|commoldura]]&lt;br /&gt;
Tudo começa com um usuário sentado confortavelmente e querendo acessar um conteúdo disponível na Internet. Ele digita em seu navegador preferido a URL: '''&amp;lt;nowiki&amp;gt;https://wiki.brasilpeeringforum.org&amp;lt;/nowiki&amp;gt;''',&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;1)&amp;lt;/big&amp;gt;''' &amp;lt;big&amp;gt;O&amp;lt;/big&amp;gt; &amp;lt;big&amp;gt;navegador irá requisitar do '''DNS Recursivo''' utilizado pelo usuário, o '''endereço IP''' que responde pelo nome '''wiki.'''&amp;lt;/big&amp;gt;'''brasilpeeringforum.org'''&amp;lt;big&amp;gt;. Isso porque todos os acessos se dão na Internet através do '''endereço''' '''IP''' e não através do '''nome'''. Imaginem se tivéssemos que decorar os endereços IPs de todos os sites e serviços que quiséssemos acessar na Internet?&amp;lt;/big&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;big&amp;gt;'''2)''' Nosso DNS Recursivo checa se a informação consta em seu cache.&amp;lt;/big&amp;gt; Se a informação existir ela é devolvida ao navegador do usuário e aí este consegue acessar o site.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Do contrário o DNS Recursivo pergunta ao '''Root Server''' quem é o '''TLD (Top Level Domain)''' responsável para atender a requisição. &lt;br /&gt;
&lt;br /&gt;
'''4)''' O '''Root Server''' informa ao DNS Recursivo o endereço do '''TLD responsável'''. No Brasil o '''TLD''' responsável pelo '''.br''' seria o '''Registro.br'''.&lt;br /&gt;
&lt;br /&gt;
'''5)''' O DNS Recursivo pergunta ao '''TLD''' sobre '''wiki.brasilpeeringforum.org''' e este responde com os endereços IP dos '''DNS Autoritativos''' responsáveis pelo domínio '''brasilpeeringforum.org.'''&lt;br /&gt;
&lt;br /&gt;
'''6)''' O DNS Recursivo pergunta aos '''DNS Autoritativos''' pelo '''wiki.brasilpeeringforum.org''' e este responde com o '''endereço IP'''.&lt;br /&gt;
&lt;br /&gt;
'''7)''' Por último o DNS Recursivo devolve a informação para o navegador do usuário.&lt;br /&gt;
&lt;br /&gt;
Como que se dá a comunicação entre os '''DNS(s) Recursivos, Root Servers, TLDs''' e '''Autoritativos'''? Como que o navegador do usuário, após receber o IP do site, consegue chegar no servidor que tem o conteúdo? Isso só é possível devido ao protocolo chamado '''BGP (Border Gateway Protocol)''', todos os caminhos que conhecemos como rotas de destino, são anunciadas por milhares de participantes na '''Internet''' conhecidos como '''AS (Autonomous System)''', esses participantes se interligam para disponibilizar conteúdos e acessos pelo mundo aos milhares de usuários. É uma imensa rede colaborativa formada por Empresas, Universidades, Governos e todos que queiram se interconectar. Percebam que sem o '''BGP''', que serve de caminho para chegarmos nos conteúdos e sem o '''DNS (Domain Name System)''' para traduzir o nome para o endereço IP, a '''Internet''' não funcionaria e por isso precisamos cuidar muito bem desses dois serviços.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Mas não acaba por aí. O '''DNS Recursivo''' tem um papel muito importante para o Provedor de Internet e que envolve segurança, qualidade de acesso à Internet e a disponibilidade do serviço entregue ao cliente. Quando bem configurado acelera as consultas dos acessos graças ao seu cache interno, mas para que isso seja percebido pelo assinante, é necessário que esteja o mais próximo possível do seu cliente.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Um erro que destrói a qualidade do nosso serviço ==&lt;br /&gt;
Um erro muito comum que muitas operadoras cometem é utilizar DNS Recursivo externo, como o '''8.8.8.8''', '''1.1.1.1''' e outros, para seus clientes. Quanto mais próximo dos seus clientes, mais qualidade de serviço estará entregando a eles. Conteúdos serão entregues mais rapidamente pois serão resolvidos e armazenados em caches locais e não consultados remotamente na Internet. Para falar mais sobre isso, te convido leitor desse documento, que assista essa palestra do '''Thiago Ayub''' no '''GTER 51/GTS 37''' (2022) '''8.888 MOTIVOS PARA NÃO USAR DNS RECURSIVO EXTERNO EM SEU AS''': https://www.youtube.com/watch?v=Rsvpu5uF2Io&lt;br /&gt;
&lt;br /&gt;
== Objetivo ==&lt;br /&gt;
O objetivo desta documentação não é te ensinar tudo sobre '''DNS''', '''BGP''', '''OSPF''' e nem tão pouco sobre GNU/Linux e sim te mostrar um exemplo de servidor DNS Recursivo implementado pensando em segurança, qualidade e resiliência. Usaremos em todas as nossas documentações o [https://www.debian.org/ Debian GNU/Linux], por ser uma distribuição que considero uma obra de arte criada por uma enorme comunidade séria, com vasta experiência de anos, qualidade no empacotamento dos programas, estável e com uma equipe de segurança excelente e ativa. Caso você leitor, utilize alguma outra distribuição GNU/Linux, todo conteúdo apresentado aqui pode ser aplicado em outras distros, desde que respeitando as particularidades de cada uma.&lt;br /&gt;
&lt;br /&gt;
Aqui construiremos um sistema do tipo '''Anycast''', ou seja, terás o serviço rodando em diversas localidades da sua Rede utilizando o mesmo endereçamento IP e que atenderá seu cliente mais próximo. Em caso de falhas, seus clientes automaticamente e de forma transparente continuarão consultando o DNS mais próximo deles. Para que ele funcione dessa forma você precisará ter uma '''Rede OSPF''' implementada no seu Provedor Internet ou algum outro protocolo como por exemplo o '''ISIS,''' mas esse documento não irá abordar o '''ISIS'''. Também utilizaremos o '''Hyperlocal''' como recurso adicional para gerar algumas proteções de segurança e velocidade na resposta relacionada aos servidores de DNS Raiz da Internet.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
Para exemplificar nosso servidor de DNS Recursivo, usaremos como base das explicações um diagrama demonstrando o uso do DNS Recursivo em uma Rede fictícia. Adotaremos IPs privados e reservados para demonstrar todo o ambiente do Provedor de Internet.&lt;br /&gt;
[[Arquivo:Recursivo99.png|esquerda|miniaturadaimagem|695x695px]]&lt;br /&gt;
Nesse diagrama podemos observar alguns detalhes técnicos como por exemplo: existem '''3 servidores de DNS Recursivo''' posicionados em locais diferentes, que poderiam estar em bairros diferentes e até em cidades diferentes. Em cada servidor teremos '''2 loopbacks''' com os IPs:&lt;br /&gt;
&lt;br /&gt;
'''10.10.10.10/32 - fd00::10:10:10:10/128'''&lt;br /&gt;
&lt;br /&gt;
'''10.10.9.9/32 - fd00::10:10:9:9/128'''&lt;br /&gt;
&lt;br /&gt;
Esses IPs serão entregues pelos concentradores '''PPPoE''' ou '''IPoE''' ('''BNG''') para seus clientes como '''DNS primário''' e '''secundário'''. Podemos usar IPs privados como DNS primário e secundário em um ambiente real? Sim podemos, desde que não sejam IPs que possam ter problemas com as redes privadas dos clientes. Ex.: rede do cliente usando '''192.168.0.0/24'''. Se entregarmos o DNS sendo '''192.168.0.10''' e '''192.168.0.20''' teremos problemas e o cliente ficará sem Internet, porque '''192.168.0.10''' e '''192.168.0.20''' fazem parte da rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
Agora entregando '''10.10.10.10,''' '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9''' não teríamos problemas com a rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
'''Motivos para usarmos IPs privados:'''&lt;br /&gt;
* O principal motivo está relacionado com a segurança, uma vez que sendo um IP privado, não pode sofrer ataques DDoS direcionados diretamente para ele, vindos da Internet.&lt;br /&gt;
* Nem mesmo o cliente da sua rede conhece os '''IPs públicos''' utilizados para recursividade na Internet.&lt;br /&gt;
* Memorizar os IPs '''10.10.10.10''' e '''10.10.9.9''' é tão fácil quanto memorizar o '''8.8.8.8''' e o '''1.1.1.1'''. Mais fácil para o seu técnico guardar essa informação e utilizar onde for necessário.&lt;br /&gt;
Cada servidor DNS Recursivo possui um '''IPv4 público''', aqui representado por '''198.18.x.x/27''' e um '''IPv6 global''' representado por um IP dentro do prefixo '''2001:db8::/32'''. Cada servidor precisa ter os seus próprios IPs e são através destes IPs que as consultas de DNS serão realizadas na Internet.&lt;br /&gt;
&lt;br /&gt;
Nessa topologia usando '''Anycast''', o cliente será sempre atendido pelo '''DNS Recursivo''' mais próximo, desde que os pesos no '''OSPF''' estejam ajustados corretamente.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
== Dados do servidor ==&lt;br /&gt;
Podemos utilizar um sistema virtualizado ou não. Sistemas virtualizados são bem vindos pois são mais simples quando precisamos fazer backups, levantar outros sistemas sem complicações e se precisarmos restaurar rapidamente algum sistema que ficou indisponível por algum motivo. A configuração abaixo tem capacidade para atender algo em torno a '''50.000 assinantes ou mais'''. O DNS Recursivo é um serviço que pode ser utilizado até mesmo em um '''Raspberry Pi''' e atender operações pequenas, nesse caso com o intuito de economizar energia e espaço. Nosso foco aqui é montar uma rede de '''DNS Recursivo Anycast com HyperLocal'''. Como comentei acima o servidor deve ficar o mais próximo dos clientes para termos a '''menor latência possível''' e '''sempre menor que 5ms''' entre o cliente e o servidor.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!CPU&lt;br /&gt;
!Memória&lt;br /&gt;
!Disco&lt;br /&gt;
!Sistema&lt;br /&gt;
|-&lt;br /&gt;
|2.4Ghz 8 cores&lt;br /&gt;
|16G DDR4&lt;br /&gt;
|30G&lt;br /&gt;
|Debian 13 amd64 (Trixie)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Softwares utilizados ==&lt;br /&gt;
* Debian 13 amd64 (Trixie) instalação mínima.&lt;br /&gt;
&lt;br /&gt;
* [https://frrouting.org/ FRRouting].&lt;br /&gt;
* Unbound.&lt;br /&gt;
* Chrony (NTP/NTS).&lt;br /&gt;
* Shell script em bash.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades que teremos ==&lt;br /&gt;
* Sistema em Anycast.&lt;br /&gt;
* Hyperlocal.&lt;br /&gt;
* Controle de acesso por &amp;lt;abbr&amp;gt;ACL&amp;lt;/abbr&amp;gt;.&lt;br /&gt;
* RPZ (Response Policy Zone).&lt;br /&gt;
* Bloqueio de consultas do tipo ANY.&lt;br /&gt;
* QNAME minimization habilitado. (habilitado por default no Unbound)&lt;br /&gt;
* Recursividade em IPv4 e IPv6.&lt;br /&gt;
* DNSSEC habilitado.&lt;br /&gt;
* &amp;lt;abbr&amp;gt;DoH (DNS&amp;lt;/abbr&amp;gt; over HTTPS) habilitado.&lt;br /&gt;
&lt;br /&gt;
== Monitoramento ==&lt;br /&gt;
O monitoramento é algo bem específico e não é o foco deste documento mas é extremamente importante que você monitore seus servidores de DNS por alguma ferramenta como o Zabbix. Aqui mostrarei apenas como enviar as informações para o Zabbix. Algumas coisas que você deveria monitorar nos servidores de DNS Recursivo:&lt;br /&gt;
* Serviço do unbound parou.&lt;br /&gt;
* Perda de pacotes.&lt;br /&gt;
* Latência alta de pacotes.&lt;br /&gt;
* Lentidão na resolução de queries.&lt;br /&gt;
* CPU alta.&lt;br /&gt;
* Load alto.&lt;br /&gt;
* Memória com uso alto.&lt;br /&gt;
* Disco com pouco espaço.&lt;br /&gt;
* Queda brusca nas queries.&lt;br /&gt;
* A recursividade parou de funcionar.&lt;br /&gt;
* A recursividade voltou a funcionar.&lt;br /&gt;
Este abaixo é um exemplo de monitoramento de um sistema de DNS Recursivo que atende 50.000 assinantes:&lt;br /&gt;
[[Arquivo:Grafana dns.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Configurando a Rede ==&lt;br /&gt;
Nossa documentação será baseada no diagrama apresentado acima e por isso configuraremos apenas um dos três servidores, porque os outros serão configurados da mesma forma, só que com dados diferentes. Para tanto assumirei que já temos um sistema Debian instalado com o mínimo de pacotes e somente com sshd, para que possamos acessar remotamente mais tarde. '''Não instale um ambiente gráfico no servidor''', você não deve querer fazer isso por diversos motivos e os principais: primeiro porque não é um Desktop e segundo porque o ambiente gráfico devoraria toda a memória com recursos que não seriam úteis aqui.&lt;br /&gt;
&lt;br /&gt;
Em '''/etc/network/interfaces''' deixaremos assim:&lt;br /&gt;
 # This file describes the network interfaces available on your system&lt;br /&gt;
 # and how to activate them. For more information, see interfaces(5).&lt;br /&gt;
  &lt;br /&gt;
 source /etc/network/interfaces.d/*&lt;br /&gt;
  &lt;br /&gt;
 # The loopback network interface&lt;br /&gt;
 auto lo&lt;br /&gt;
 iface lo inet loopback&lt;br /&gt;
  &lt;br /&gt;
 auto lo:0&lt;br /&gt;
 iface lo:0 inet static&lt;br /&gt;
       address 10.10.10.10/32&lt;br /&gt;
  &lt;br /&gt;
 auto lo:1&lt;br /&gt;
 iface lo:1 inet static&lt;br /&gt;
       address 10.10.9.9/32&lt;br /&gt;
 &lt;br /&gt;
 auto lo:2&lt;br /&gt;
 iface lo:2 inet6 static&lt;br /&gt;
       address fd00::10:10:10:10/128&lt;br /&gt;
 &lt;br /&gt;
 auto lo:3&lt;br /&gt;
 iface lo:3 inet6 static&lt;br /&gt;
       address fd00::10:10:9:9/128&lt;br /&gt;
  &lt;br /&gt;
 # The primary network interface&lt;br /&gt;
 auto ens18&lt;br /&gt;
 iface ens18 inet static&lt;br /&gt;
         address 198.18.1.10/27&lt;br /&gt;
         gateway 198.18.1.1&lt;br /&gt;
  &lt;br /&gt;
 iface ens18 inet6 static&lt;br /&gt;
         address 2001:db8::faca:198:18:1:10/64&lt;br /&gt;
         gateway 2001:db8::faca:198:18:1:1&lt;br /&gt;
  &lt;br /&gt;
 # The secondary network interface&lt;br /&gt;
 auto ens18:0&lt;br /&gt;
 iface ens18:0 inet static&lt;br /&gt;
         address 172.16.0.6/30&lt;br /&gt;
Nesse cenário temos as duas '''loopbacks''' com os IPs '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10''' e '''fd00::10:10:9:9''' que serão anunciados via OSPF para a rede e serem entregues aos clientes via BNG. Os IPs '''198.18.1.10''' e '''2001:db8::faca:198:18:1:10''' serão usados para fazerem a recursividade na Internet tanto em IPv4 quanto em IPv6. Esses IPs não devem ser divulgados para clientes; os IPs públicos são dedicados apenas para essa finalidade.&lt;br /&gt;
&lt;br /&gt;
== Configuração dos repositórios Debian ==&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://security.debian.org/debian-security/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-security&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-updates&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian-backports.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-backports&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
&lt;br /&gt;
 # rm /etc/apt/sources.list&lt;br /&gt;
Após a configuração vamos instalar alguns pacotes necessários e outros úteis:&lt;br /&gt;
 # apt update &amp;amp;&amp;amp; apt full-upgrade&lt;br /&gt;
 # apt install net-tools nftables htop iotop sipcalc tcpdump curl gnupg rsync wget host dnsutils mtr-tiny bmon sudo tmux whois ethtool dnstop irqbalance&lt;br /&gt;
&lt;br /&gt;
== Fazendo algum tuning no sistema ==&lt;br /&gt;
Em '''/etc/sysctl.d/100-tuning.conf''' adicionamos essas instruções:&lt;br /&gt;
 net.core.rmem_max = 2147483647&lt;br /&gt;
 net.core.wmem_max = 2147483647&lt;br /&gt;
 net.ipv4.tcp_rmem = 4096 87380 2147483647&lt;br /&gt;
 net.ipv4.tcp_wmem = 4096 65536 2147483647&lt;br /&gt;
 net.netfilter.nf_conntrack_buckets = 512000&lt;br /&gt;
 net.netfilter.nf_conntrack_max = 4096000&lt;br /&gt;
 vm.swappiness=10&lt;br /&gt;
Estamos fazendo algumas melhorias de memória, algumas relacionadas a '''conntrack''' porque se for usar um filtro de pacotes stateful, como o '''Netfilter/IPTables''' ou '''Netfilter/NFTables''', o valor default da tabela é pequeno e dependendo da situação, se estourar essa tabela, as consultas de DNS terão problemas também. O DNS Recursivo não deve ficar aberto para qualquer um na Internet, ele deve ser liberado apenas para seus clientes. Podemos fazer através das ACLs do Unbound e pelo filtro de pacotes. O último parâmetro diz respeito ao uso de swap, por padrão o Debian permite o uso de swap após 40% do uso da memória, nesse caso estamos dizendo para o sistema usar o swap com 90% de uso da memória.&lt;br /&gt;
&lt;br /&gt;
Precisamos adicionar o módulo '''nf_conntrack''' em '''/etc/modules''' para que seja carregado em tempo de boot, senão os parâmetros de '''conntrack''' que colocamos em '''/etc/sysctl.conf''' não serão carregados.&lt;br /&gt;
 # echo nf_conntrack &amp;gt;&amp;gt; /etc/modules&lt;br /&gt;
 # modprobe nf_conntrack&lt;br /&gt;
 # sysctl -p&lt;br /&gt;
&lt;br /&gt;
== Instalando o FRRouting ==&lt;br /&gt;
O FRRouting é o programa que usaremos para fazer os anúncios das nossas loopbacks via OSPF. Nesse documento usaremos a versão 10.x:&lt;br /&gt;
 # apt install frr frr-doc frr-pythontools&lt;br /&gt;
Aconselho depois de instalar os pacotes, marcá-los para não atualizar juntamente com os demais pacotes, isso é para evitar de ocorrer alguma atualização no FRRouting, que torne o serviço instável por algum motivo. Não que isso vá ocorrer, mas é melhor fazer essa atualização quando realmente for necessário.&lt;br /&gt;
 # apt-mark hold frr frr-doc frr-pythontools&lt;br /&gt;
Após esse comando acima, o sistema manterá a instalação original do pacote intacta. Para desbloquear basta executar o comando abaixo:&lt;br /&gt;
 # apt-mark unhold frr frr-doc frr-pythontools&lt;br /&gt;
&lt;br /&gt;
== Removendo o APPARMOR ==&lt;br /&gt;
O '''APPARMOR''' às vezes causa mais problemas que solução e se não for fazer uma completa configuração nele, é melhor desabilitá-lo. Para fazer isso efetivamente, o procedimento é esse abaixo:&lt;br /&gt;
 # mkdir -p /etc/default/grub.d&lt;br /&gt;
 # echo 'GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;$GRUB_CMDLINE_LINUX_DEFAULT apparmor=0&amp;quot;' | tee /etc/default/grub.d/apparmor.cfg&lt;br /&gt;
 # update-grub&lt;br /&gt;
 # reboot&lt;br /&gt;
&lt;br /&gt;
== Instalando o Unbound ==&lt;br /&gt;
Nesse momento ainda não iremos configurar o Unbound, apenas instalar o pacote e acertar o ambiente. Vamos instalar o unbound do backports porque este já possui suporte ao DoH que veremos mais à frente.&lt;br /&gt;
 # apt install unbound dns-root-data&lt;br /&gt;
 # mkdir -p /var/log/unbound&lt;br /&gt;
 # touch /var/log/unbound/unbound.log&lt;br /&gt;
 # chown -R unbound:unbound /var/log/unbound/&lt;br /&gt;
 # systemctl restart unbound&lt;br /&gt;
Configurando o logrotate:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/logrotate.d/unbound&lt;br /&gt;
 /var/log/unbound/unbound.log {&lt;br /&gt;
     rotate 5&lt;br /&gt;
     weekly&lt;br /&gt;
     postrotate&lt;br /&gt;
         unbound-control log_reopen&lt;br /&gt;
     endscript&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
Reiniciando o serviço:&lt;br /&gt;
 # systemctl restart logrotate.service&lt;br /&gt;
&lt;br /&gt;
== Desabilitando THP (Transparente Huge Pages) em arquitetura AMD64 ==&lt;br /&gt;
No Debian o '''THP''' vem habilitado como '''always''' e o '''unbound''' por trabalhar bastante com alterações do cache em memória, isso pode acabar causando um consumo crescente de uso de RAM sem necessidade. É uma boa prática desabilitá-lo com os passos abaixo:&lt;br /&gt;
&lt;br /&gt;
https://github.com/NLnetLabs/unbound/issues/724&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/systemd/system/disable-thp.service&lt;br /&gt;
 [Unit]&lt;br /&gt;
 Description=Desabilita Transparent Huge Pages (THP)&lt;br /&gt;
 After=network.target&lt;br /&gt;
 &lt;br /&gt;
 [Service]&lt;br /&gt;
 Type=oneshot&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled&amp;quot;&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/defrag&amp;quot;&lt;br /&gt;
 RemainAfterExit=yes&lt;br /&gt;
 &lt;br /&gt;
 [Install]&lt;br /&gt;
 WantedBy=multi-user.target&lt;br /&gt;
 EOF&lt;br /&gt;
Acima configuramos o serviço '''disable-thp.service''' para desabilitar o '''THP''' e abaixo habilitamos no '''systemd''' e iniciamos:&lt;br /&gt;
 # systemctl daemon-reload&lt;br /&gt;
 # systemctl enable --now disable-thp&lt;br /&gt;
&lt;br /&gt;
== Preparando o monitoramento do seu DNS Recursivo ==&lt;br /&gt;
O monitoramento do seu DNS Recursivo é muito importante e para isso vamos usar um '''template para Zabbix''', que modifiquei juntamente com o seu shell script e que enviará os dados para o seu Zabbix server via '''zabbix-sender'''. O projeto original está aqui '''https://github.com/jeftedelima/Unbound-DNS&amp;lt;nowiki/&amp;gt;.''' O xml alterado está aqui '''https://github.com/gondimcodes/template_zabbix_dns_unbound'''. Embora seja antigo é perfeitamente importável no Zabbix 6.0, por exemplo.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;nowiki/&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Teremos um shell script que você precisará colocar no seu '''/etc/crontab'''. No exemplo abaixo assumi que o shell script está em '''/root/scripts'''. De 5 em 5 minutos os dados serão enviados para o seu Zabbix server.&lt;br /&gt;
 */5 * * * *     root    /root/scripts/unboundSend.sh '''IP_zabbix_server''' '''nome_do_host''' 1&amp;gt; /dev/null&lt;br /&gt;
Na linha acima, troque o '''IP_zabbix_server''' pelo '''IP do seu servidor Zabbix''' e o '''nome_do_host''' pelo '''hostname''' '''do seu DNS Recursivo'''. Você precisará instalar o pacote '''zabbix-sender''' no seu DNS Recursivo pois ele será usado para enviar os dados para o Zabbix server.&lt;br /&gt;
&lt;br /&gt;
Abaixo o '''unboundSend.sh''' também alterado com inclusão de mais dados:&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 #       @Jefte de Lima Ferreira&lt;br /&gt;
 #       jeftedelima at gmail dot com&lt;br /&gt;
 #       CRON Example&lt;br /&gt;
 #       Contributor: Marcelo Gondim - gondim at gmail dot com&lt;br /&gt;
 #       */5   **** root sh /home/dir/unboundSend.sh 192.168.10.1 Unbound 1&amp;gt; /dev/null&lt;br /&gt;
  &lt;br /&gt;
 if [ -z ${1} ] || [ -z ${2} ] ; then&lt;br /&gt;
         echo &amp;quot;You need to specify the IP address of zabbix server and hostname of your DNS Unbound on zabbix&amp;quot;&lt;br /&gt;
         echo &amp;quot;Usage example: ./unboundSend.sh 192.168.10.1 UnboundServer&amp;quot;&lt;br /&gt;
         exit 1&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 # ZABBIX_SERVER IP&lt;br /&gt;
 IP_ZABBIX=$1&lt;br /&gt;
 # NAME Unbound on Zabbix&lt;br /&gt;
 NAME_HOST=$2&lt;br /&gt;
 DIR_TEMP=/var/tmp/&lt;br /&gt;
 FILE=&amp;quot;${DIR_TEMP}dump_unbound_control_stats.txt&amp;quot;&lt;br /&gt;
 unbound-control stats &amp;gt; ${FILE}&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_NUM_QUERIES=$(cat ${FILE} | grep -w 'total.num.queries' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEHITS=$(cat ${FILE} | grep -w 'total.num.cachehits' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEMISS=$(cat ${FILE} | grep -w 'total.num.cachemiss' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_PREFETCH=$(cat ${FILE} | grep -w 'total.num.prefetch' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_RECURSIVEREPLIES=$(cat ${FILE} | grep -w 'total.num.recursivereplies' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_REQ_MAX=$(cat ${FILE} | grep -w 'total.requestlist.max' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_AVG=$(cat ${FILE} | grep -w 'total.requestlist.avg' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_OVERWRITTEN=$(cat ${FILE} | grep -w 'total.requestlist.overwritten' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_EXCEEDED=$(cat ${FILE} | grep -w 'total.requestlist.exceeded' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_ALL=$(cat ${FILE} | grep -w 'total.requestlist.current.all' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_USER=$(cat ${FILE} | grep -w 'total.requestlist.current.user' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_TCPUSAGE=$(cat ${FILE} | grep -w 'total.tcpusage' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_QUERY_TYPE_A=$(cat ${FILE} | grep -w 'num.query.type.A' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NS=$(cat ${FILE} | grep -w 'num.query.type.NS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_MX=$(cat ${FILE} | grep -w 'num.query.type.MX' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TXT=$(cat ${FILE} | grep -w 'num.query.type.TXT' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_PTR=$(cat ${FILE} | grep -w 'num.query.type.PTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_AAAA=$(cat ${FILE} | grep -w 'num.query.type.AAAA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SRV=$(cat ${FILE} | grep -w 'num.query.type.SRV' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SOA=$(cat ${FILE} | grep -w 'num.query.type.SOA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HTTPS=$(cat ${FILE} | grep -w 'num.query.type.HTTPS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TYPE0=$(cat ${FILE} | grep -w 'num.query.type.TYPE0' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_CNAME=$(cat ${FILE} | grep -w 'num.query.type.CNAME' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_WKS=$(cat ${FILE} | grep -w 'num.query.type.WKS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HINFO=$(cat ${FILE} | grep -w 'num.query.type.HINFO' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_X25=$(cat ${FILE} | grep -w 'num.query.type.X25' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NAPTR=$(cat ${FILE} | grep -w 'num.query.type.NAPTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DS=$(cat ${FILE} | grep -w 'num.query.type.DS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DNSKEY=$(cat ${FILE} | grep -w 'num.query.type.DNSKEY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TLSA=$(cat ${FILE} | grep -w 'num.query.type.TLSA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SVCB=$(cat ${FILE} | grep -w 'num.query.type.SVCB' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SPF=$(cat ${FILE} | grep -w 'num.query.type.SPF' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_ANY=$(cat ${FILE} | grep -w 'num.query.type.ANY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_OTHER=$(cat ${FILE} | grep -w 'num.query.type.other' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_ANSWER_RCODE_NOERROR=$(cat ${FILE} | grep -w 'num.answer.rcode.NOERROR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_NXDOMAIN=$(cat ${FILE} | grep -w 'num.answer.rcode.NXDOMAIN' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_SERVFAIL=$(cat ${FILE} | grep -w 'num.answer.rcode.SERVFAIL' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_REFUSED=$(cat ${FILE} | grep -w 'num.answer.rcode.REFUSED' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_nodata=$(cat ${FILE} | grep -w 'num.answer.rcode.nodata' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_secure=$(cat ${FILE} | grep -w 'num.answer.secure' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 #       Sending info to zabbix_server.&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.queries -o $(( ${TOTAL_NUM_QUERIES:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachehits -o $(( ${TOTAL_NUM_CACHEHITS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachemiss -o $(( ${TOTAL_NUM_CACHEMISS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.prefetch -o $(( ${TOTAL_NUM_PREFETCH:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.recursivereplies -o $(( ${TOTAL_NUM_RECURSIVEREPLIES:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.max -o $(( ${TOTAL_REQ_MAX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.avg -o $(( ${TOTAL_REQ_AVG:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.overwritten -o $(( ${TOTAL_REQ_OVERWRITTEN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.exceeded -o $(( ${TOTAL_REQ_EXCEEDED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.all -o $(( ${TOTAL_REQ_CURRENT_ALL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.user -o $(( ${TOTAL_REQ_CURRENT_USER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.tcpusage -o $(( ${TOTAL_TCPUSAGE:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.a -o $(( ${NUM_QUERY_TYPE_A:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ns -o $(( ${NUM_QUERY_TYPE_NS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.mx -o $(( ${NUM_QUERY_TYPE_MX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.txt -o $(( ${NUM_QUERY_TYPE_TXT:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ptr -o $(( ${NUM_QUERY_TYPE_PTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.aaaa -o $(( ${NUM_QUERY_TYPE_AAAA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.srv -o $(( ${NUM_QUERY_TYPE_SRV:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.soa -o $(( ${NUM_QUERY_TYPE_SOA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.https -o $(( ${NUM_QUERY_TYPE_HTTPS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.type0 -o $(( ${NUM_QUERY_TYPE_TYPE0:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.cname -o $(( ${NUM_QUERY_TYPE_CNAME:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.wks -o $(( ${NUM_QUERY_TYPE_WKS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.hinfo -o $(( ${NUM_QUERY_TYPE_HINFO:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.X25 -o $(( ${NUM_QUERY_TYPE_X25:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.naptr -o $(( ${NUM_QUERY_TYPE_NAPTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ds -o $(( ${NUM_QUERY_TYPE_DS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.dnskey -o $(( ${NUM_QUERY_TYPE_DNSKEY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.tlsa -o $(( ${NUM_QUERY_TYPE_TLSA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.svcb -o $(( ${NUM_QUERY_TYPE_SVCB:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.spf -o $(( ${NUM_QUERY_TYPE_SPF:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.any -o $(( ${NUM_QUERY_TYPE_ANY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.other -o $(( ${NUM_QUERY_TYPE_OTHER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NOERROR -o $(( ${NUM_ANSWER_RCODE_NOERROR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NXDOMAIN -o $(( ${NUM_ANSWER_RCODE_NXDOMAIN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.SERVFAIL -o $(( ${NUM_ANSWER_RCODE_SERVFAIL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.REFUSED -o $(( ${NUM_ANSWER_RCODE_REFUSED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.nodata -o $(( ${NUM_ANSWER_RCODE_nodata:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.secure -o $(( ${NUM_ANSWER_secure:-0} / 300 ))&lt;br /&gt;
No Zabbix será registrado dados como esses abaixo e posteriormente pode ser montado um Grafana com eles:&lt;br /&gt;
[[Arquivo:Zabbix dns01.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns02.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns03.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns04.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Mantendo a hora certa ==&lt;br /&gt;
Vamos instalar agora o Chrony para manter a data e hora certas no sistema:&lt;br /&gt;
 # apt install chrony&lt;br /&gt;
Após a instalação do Chrony edite o arquivo /etc/chrony/chrony.conf, comente e a linha abaixo e adicione seus servidores NTP. Caso não tenha servidores NTP, estou colocando os do NIC.br aqui.&lt;br /&gt;
 #pool 2.debian.pool.ntp.org iburst&lt;br /&gt;
 server a.st1.ntp.br iburst nts&lt;br /&gt;
 server b.st1.ntp.br iburst nts&lt;br /&gt;
 server c.st1.ntp.br iburst nts&lt;br /&gt;
 server d.st1.ntp.br iburst nts&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart chronyd.service&lt;br /&gt;
Cheque com o '''chronyc''' se os servidores estão OK:&lt;br /&gt;
 # chronyc sourcestats&lt;br /&gt;
 Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev&lt;br /&gt;
 ==============================================================================&lt;br /&gt;
 a.st1.ntp.br               10   5  155m     -0.027      0.030    -71us    51us&lt;br /&gt;
 b.st1.ntp.br               11   7  344m     +0.068      0.079    +23ms   382us&lt;br /&gt;
 c.st1.ntp.br                6   3  344m     +0.026      0.037   -124us    92us&lt;br /&gt;
 200.20.186.76               9   3  138m     -0.022      0.031   +172us    42us&lt;br /&gt;
&lt;br /&gt;
 # chronyc sources&lt;br /&gt;
 MS Name/IP address         Stratum Poll Reach LastRx Last sample&lt;br /&gt;
 ===============================================================================&lt;br /&gt;
 ^* a.st1.ntp.br                  1  10   377   588   +487us[ +397us] +/-   12ms&lt;br /&gt;
 ^- b.st1.ntp.br                  2  10   377   830    +23ms[  +23ms] +/-   49ms&lt;br /&gt;
 ^+ c.st1.ntp.br                  2  10    21  1038   -147us[ -242us] +/-   17ms&lt;br /&gt;
 ^+ 200.20.186.76                 1  10   377  1032   +381us[ +285us] +/-   15ms&lt;br /&gt;
&lt;br /&gt;
== Configurando o FRRouting ==&lt;br /&gt;
Nesse ponto iremos configurar o '''FRRouting''' para enviar os IPs das '''loopbacks''' e o '''/30''' para o nosso PE do diagrama. Em '''/etc/frr/daemons''' habilite o parâmetro conforme abaixo:&lt;br /&gt;
 ospfd=yes&lt;br /&gt;
 ospf6d=yes&lt;br /&gt;
Edite o arquivo '''/etc/frr/frr.conf''' e deixe com o conteúdo abaixo, para ficar conforme nosso diagrama do projeto. Apenas troque '''&amp;lt;SENHA&amp;gt;''' por uma senha para fechar o OSPF com mais segurança. Essa senha deve ser usada dos dois lados.&lt;br /&gt;
 frr version 10.3&lt;br /&gt;
 frr defaults traditional&lt;br /&gt;
 hostname dns-recursivo-01&lt;br /&gt;
 log syslog informational&lt;br /&gt;
 no ip forwarding&lt;br /&gt;
 no ipv6 forwarding&lt;br /&gt;
 service integrated-vtysh-config&lt;br /&gt;
 !&lt;br /&gt;
 interface ens18&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf message-digest-key 5 md5 &amp;lt;SENHA&amp;gt;&lt;br /&gt;
  ip ospf network point-to-point&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 network point-to-point&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 interface lo&lt;br /&gt;
  description LOOPBACKS&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf passive&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 passive&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf&lt;br /&gt;
  ospf router-id 172.16.0.6&lt;br /&gt;
  area 0.0.0.0 authentication message-digest&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf6&lt;br /&gt;
  ospf6 router-id 172.16.0.6&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart frr.service&lt;br /&gt;
Cheque se está tudo OK com o OSPF e verifique no PE se está recebendo os prefixos anunciados.&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL&lt;br /&gt;
 172.16.0.5     1 Full/-          10m49s            35.310s 172.16.0.5   ens18:172.16.0.6                  0     0     0&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri    DeadTime    State/IfState         Duration I/F[State]&lt;br /&gt;
 172.16.0.5       1    00:00:30     Full/PointToPoint 25d22:53:47 ens18[PointToPoint]&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor detail'&lt;br /&gt;
 &lt;br /&gt;
  Neighbor 172.16.0.5, interface address 172.16.0.5&lt;br /&gt;
     In the area 0.0.0.0 via interface ens18&lt;br /&gt;
     Neighbor priority is 1, State is Full/-, 5 state changes&lt;br /&gt;
     Most recent state change statistics:&lt;br /&gt;
       Progressive change 21w3d15h ago&lt;br /&gt;
     DR is 0.0.0.0, BDR is 0.0.0.0&lt;br /&gt;
     Options 18 *|-|-|EA|-|-|E|-&lt;br /&gt;
     Dead timer due in 34.685s&lt;br /&gt;
     Database Summary List 0&lt;br /&gt;
     Link State Request List 0&lt;br /&gt;
     Link State Retransmission List 0&lt;br /&gt;
     Thread Inactivity Timer on&lt;br /&gt;
     Thread Database Description Retransmision off&lt;br /&gt;
     Thread Link State Request Retransmission on&lt;br /&gt;
     Thread Link State Update Retransmission on&lt;br /&gt;
 &lt;br /&gt;
     Graceful restart Helper info:&lt;br /&gt;
       Graceful Restart HELPER Status : None&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor detail'&lt;br /&gt;
  Neighbor 172.16.0.5%ens18&lt;br /&gt;
     Area 0.0.0.0 via interface ens18 (ifindex 4)&lt;br /&gt;
     His IfIndex: 60 Link-local address: fe80::469b:c1ff:fed6:43ee&lt;br /&gt;
     State Full for a duration of 25d22:57:14&lt;br /&gt;
     His choice of DR/BDR 0.0.0.0/0.0.0.0, Priority 1&lt;br /&gt;
     DbDesc status: Master SeqNum: 0xb94b0000&lt;br /&gt;
     Summary-List: 0 LSAs&lt;br /&gt;
     Request-List: 0 LSAs&lt;br /&gt;
     Retrans-List: 0 LSAs&lt;br /&gt;
     0 Pending LSAs for DbDesc in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSReq in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSAck in Time 00:00:00 [thread off]&lt;br /&gt;
     Authentication header not present&lt;br /&gt;
&lt;br /&gt;
== Configurando o Unbound ==&lt;br /&gt;
Abaixo a configuração que usaremos nos servidores atentando para o detalhe do '''num-threads''', esse deve ter o valor igual ao número de CPUs do servidor.&lt;br /&gt;
&lt;br /&gt;
Também os IPs utilizados em '''outgoing-interface''' que serão diferentes em cada servidor, esses serão os IPs usados para '''recursividade'''. Consulte o manual do Unbound para obter mais informações sobre cada parâmetro listado na configuração.&lt;br /&gt;
&lt;br /&gt;
O tuning no Unbound pode ser alterado conforme abaixo:&lt;br /&gt;
 num-threads = nº CPUs&lt;br /&gt;
 so-reuseport = yes&lt;br /&gt;
 *-slabs = potência de 2 próximo ao num-threads&lt;br /&gt;
 msg-cache-size = 1g (quantidade de memória pra usar de cache)&lt;br /&gt;
 rrset-cache-size = 2 * msg-cache-size&lt;br /&gt;
 outgoing-range = 8192&lt;br /&gt;
 num-queries-per-thread = 4096&lt;br /&gt;
 so-rcvbuf e so-sndbuf = 4m ou 8m para servidores com muita requisição&lt;br /&gt;
Agora vamos criar nosso arquivo de configuração base em '''/etc/unbound/unbound.conf.d/local.conf''':&lt;br /&gt;
 server:&lt;br /&gt;
         verbosity: 1&lt;br /&gt;
         statistics-interval: 0&lt;br /&gt;
         statistics-cumulative: no&lt;br /&gt;
         extended-statistics: yes&lt;br /&gt;
         num-threads: 8&lt;br /&gt;
         serve-expired: yes&lt;br /&gt;
         interface: 127.0.0.1&lt;br /&gt;
         interface: 10.10.10.10&lt;br /&gt;
         interface: 10.10.9.9&lt;br /&gt;
         interface: 172.16.0.6&lt;br /&gt;
         interface: fd00::10:10:10:10&lt;br /&gt;
         interface: fd00::10:10:9:9&lt;br /&gt;
         interface: ::1&lt;br /&gt;
         interface-automatic: no&lt;br /&gt;
         outgoing-interface: 198.18.1.10&lt;br /&gt;
         outgoing-interface: 2001:db8::faca:198:18:1:10&lt;br /&gt;
         outgoing-range: 8192&lt;br /&gt;
         outgoing-num-tcp: 1024&lt;br /&gt;
         incoming-num-tcp: 2048&lt;br /&gt;
         so-rcvbuf: 4m&lt;br /&gt;
         so-sndbuf: 4m&lt;br /&gt;
         so-reuseport: yes&lt;br /&gt;
         edns-buffer-size: 1232&lt;br /&gt;
         msg-cache-size: 512m&lt;br /&gt;
         msg-cache-slabs: 4&lt;br /&gt;
         num-queries-per-thread: 4096&lt;br /&gt;
         rrset-cache-size: 1g&lt;br /&gt;
         rrset-cache-slabs: 4&lt;br /&gt;
         infra-cache-slabs: 4&lt;br /&gt;
         do-ip4: yes&lt;br /&gt;
         do-ip6: yes&lt;br /&gt;
         do-udp: yes&lt;br /&gt;
         do-tcp: yes&lt;br /&gt;
         chroot: &amp;quot;&amp;quot;&lt;br /&gt;
         username: &amp;quot;unbound&amp;quot;&lt;br /&gt;
         directory: &amp;quot;/etc/unbound&amp;quot;&lt;br /&gt;
         logfile: &amp;quot;/var/log/unbound/unbound.log&amp;quot;&lt;br /&gt;
         use-syslog: no&lt;br /&gt;
         log-time-ascii: yes&lt;br /&gt;
         log-queries: no&lt;br /&gt;
         pidfile: &amp;quot;/var/run/unbound.pid&amp;quot;&lt;br /&gt;
         root-hints: &amp;quot;/usr/share/dns/root.hints&amp;quot;&lt;br /&gt;
         hide-identity: yes&lt;br /&gt;
         hide-version: yes&lt;br /&gt;
         unwanted-reply-threshold: 10000000&lt;br /&gt;
         prefetch: yes&lt;br /&gt;
         prefetch-key: yes&lt;br /&gt;
         rrset-roundrobin: yes&lt;br /&gt;
         minimal-responses: yes&lt;br /&gt;
         module-config: &amp;quot;respip validator iterator&amp;quot;&lt;br /&gt;
         val-clean-additional: yes&lt;br /&gt;
         val-log-level: 1&lt;br /&gt;
         key-cache-slabs: 4&lt;br /&gt;
         deny-any: yes&lt;br /&gt;
         cache-min-ttl: 60&lt;br /&gt;
         key-cache-size: 128m&lt;br /&gt;
         neg-cache-size: 64m&lt;br /&gt;
         cache-max-ttl: 86400&lt;br /&gt;
         infra-cache-numhosts: 100000&lt;br /&gt;
         access-control: 198.18.0.0/22 allow&lt;br /&gt;
         access-control: 2001:db8::/32 allow&lt;br /&gt;
  &lt;br /&gt;
 rpz:&lt;br /&gt;
   name: rpz.block.host.local.zone&lt;br /&gt;
   zonefile: /etc/unbound/rpz.block.hosts.zone&lt;br /&gt;
   rpz-action-override: nxdomain&lt;br /&gt;
  &lt;br /&gt;
 python:&lt;br /&gt;
  &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;.&amp;quot;&lt;br /&gt;
     master: &amp;quot;b.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;c.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;d.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;f.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;g.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;k.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/root.zone&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;arpa.&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/arpa.zone&amp;quot;&lt;br /&gt;
No parâmetro '''interface''' colocamos os IPs que serão usados para consulta dos clientes como o '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9'''. Ali repare que coloquei também o IP privado '''172.16.0.6''', isso porque cada servidor terá o seu IP privado e este deve ser usado pelo seu sistema de monitoramento para checar cada servidor. No '''outgoing-interface''' teremos os IPs, tanto '''IPv4''' quanto '''IPv6''', para que seja feita a recursividade na Internet utilizando eles. Não tem '''IPv6''' ainda na sua rede? Dê uma olhada nesse artigo. Outro parâmetro importante é o '''access-control''' e é através dele que liberamos os prefixos IP para consultarem no nosso DNS Recursivo. No exemplo estou liberando todo o prefixo '''198.18.0.0/22''' e o prefixo '''2001:db8::/32'''. Além da ACL no Unbound, recomendo que crie um filtro de pacotes com iptables ou nftables protegendo seu sistema e liberando as portas '''53/UDP''', '''53/TCP,'''  '''443/TCP e 853/TCP''' apenas para seus clientes. Falarei sobre a '''443/TCP e 853/TCP''' mais para frente nessa mesma documentação.&lt;br /&gt;
&lt;br /&gt;
Agora criaremos o arquivo '''RPZ''' ('''Response Policy Zones'''). Esse arquivo contém os sites que serão bloqueados via '''&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; Recursivo'''. São aqueles sites que às vezes você recebe um Ofício da Justiça solicitando o bloqueio deles. Não entrarei no mérito da efetividade desses bloqueios, porque muitos de vocês sabem que tecnicamente, existem formas de se fazer um bypass através desses bloqueios. Contudo vamos deixar nosso ambiente preparado para esses bloqueios e por isso crie o arquivo '''/etc/unbound/rpz.block.hosts.zone''' com esse conteúdo de exemplo:&lt;br /&gt;
 $TTL 2h&lt;br /&gt;
 @ IN SOA localhost. root.localhost. (2 6h 1h 1w 2h)&lt;br /&gt;
   IN NS  localhost.&lt;br /&gt;
 ; RPZ manual block hosts&lt;br /&gt;
 *.josedascoves.com CNAME .&lt;br /&gt;
 josedascoves.com CNAME .&lt;br /&gt;
No exemplo acima estamos bloqueando qualquer consulta de DNS para '''josedascoves.com''' ou qualquer coisa '''.josedascoves.com'''.&lt;br /&gt;
&lt;br /&gt;
Para testar podemos fazer assim do próprio servidor:&lt;br /&gt;
 # host josedascoves.com ::1&lt;br /&gt;
 Using domain server:&lt;br /&gt;
 Name: ::1&lt;br /&gt;
 Address: ::1#53&lt;br /&gt;
 Aliases:&lt;br /&gt;
 &lt;br /&gt;
 Host josedascoves.com not found: 3(NXDOMAIN)&lt;br /&gt;
Se a resposta for '''NXDOMAIN''' então está funcionando o bloqueio. Para incluir novos bloqueios basta adicionar os domínios, um abaixo do outro, conforme o exemplo que coloquei no arquivo RPZ.&lt;br /&gt;
&lt;br /&gt;
== Acertando o resolv.conf ==&lt;br /&gt;
Vamos modificar nosso /etc/resolv.conf para utilizar DNS externo. Sim você deve estar se perguntando em qual situação isso seria utilizado. Primeiro entenda que o Unbound não irá utilizar o DNS externo para fazer as consultas na Internet e sim, qualquer teste que você faça do servidor precisará apontar para o Unbound usando os IPs '''127.0.0.1''' ou '''::1'''. Faremos isso pela seguinte situação: imagine que o daemon unbound morreu mas você ainda continua com conectividade na Internet. Você conseguiria acessar qualquer local na Internet através do IP mas não através do hostname porque não conseguiria resolver nomes, seu unbound estaria fora do ar. Imagine ainda que você gostaria que seu servidor te avisasse do problema via Telegram ou e-mail. Por isso estamos utilizando um DNS externo no '''/etc/resolv.conf''', apenas para essas situações. Se você não quiser utilizar desse recurso, pode usar o '''127.0.0.1''' e '''::1''' no lugar.&lt;br /&gt;
 nameserver 8.8.8.8&lt;br /&gt;
 nameserver 8.8.4.4&lt;br /&gt;
 nameserver 2001:4860:4860::8888&lt;br /&gt;
&lt;br /&gt;
== Script de teste de recursividade ==&lt;br /&gt;
Estamos montando uma '''Rede de DNS Recursivo Anycast''', então é muito importante que você monitore essa rede para saber se algum node morreu e iniciar o troubleshooting, resolver o problema e levantar o sistema novamente. Tudo isso é importante mas o cliente não deve ficar esperando até você resolver o problema, seu sistema precisa ser inteligente o suficiente para se remover da Rede quando tiver um problema e se inserir novamente, quando o problema estiver sido solucionado. Se você montar uma Rede de DNS e um dos nodes apresentar algum problema, todos os clientes atendidos por aquele node migrarão automaticamente e transparentemente para outro '''DNS Recursivo Anycast''' mais próximo. Isso se chama '''disponibilidade'''.&lt;br /&gt;
&lt;br /&gt;
O script '''/root/scripts/checa_dns.sh''' abaixo tem a função de fazer os testes de recursividade e checar se o daemon do unbound continua rodando. Se algo acontecer, ele para o anúncio do '''10.10.10.10''' e '''10.10.9.9''' e retorna eles quando tudo estiver resolvido.&lt;br /&gt;
 # mkdir /root/scripts&lt;br /&gt;
&lt;br /&gt;
 #!/usr/bin/env bash&lt;br /&gt;
 #Script para teste de DNS v2.1&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 #Informe um domínio por linha:&lt;br /&gt;
 dominios_testar=(&lt;br /&gt;
 www.google.com&lt;br /&gt;
 www.terra.com.br&lt;br /&gt;
 www.uol.com.br&lt;br /&gt;
 www.globo.com&lt;br /&gt;
 www.facebook.com&lt;br /&gt;
 www.youtube.com&lt;br /&gt;
 www.twitch.com&lt;br /&gt;
 www.discord.com&lt;br /&gt;
 www.debian.org&lt;br /&gt;
 www.redhat.com&lt;br /&gt;
 )&lt;br /&gt;
 corte_taxa_falha=100 #Porcentagem de falha para executar uma ação&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 remove_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; != &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no description' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME morreu!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 adiciona_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; == &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'description LOOPBACKS' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME retornou do inferno!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
 if [ $? -ne 0 ]; then&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME morreu DNS mas tentando levantar!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    systemctl restart unbound&lt;br /&gt;
    systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
    if [ $? -ne 0 ]; then&lt;br /&gt;
       remove_ospf&lt;br /&gt;
       exit&lt;br /&gt;
    fi&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME servico DNS voltou mas tinha morrido!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 qt_falhas=0&lt;br /&gt;
 qt_total=&amp;quot;${#dominios_testar[@]}&amp;quot;&lt;br /&gt;
 echo &amp;quot;total_dominios: $qt_total&amp;quot;&lt;br /&gt;
 for site in &amp;quot;${dominios_testar[@]}&amp;quot;&lt;br /&gt;
 do&lt;br /&gt;
   unbound-control flush $site &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   resolver=&amp;quot;127.0.0.1&amp;quot;&lt;br /&gt;
   echo -e &amp;quot; - dominio $site - $resolver - \c&amp;quot;&lt;br /&gt;
   host $site $resolver &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   if [ $? -ne 0 ]; then&lt;br /&gt;
      ((qt_falhas++))&lt;br /&gt;
      echo -e &amp;quot;[Falhou]&amp;quot;&lt;br /&gt;
   else&lt;br /&gt;
      echo -e &amp;quot;[OK]&amp;quot;&lt;br /&gt;
   fi&lt;br /&gt;
 done&lt;br /&gt;
  &lt;br /&gt;
 taxa_falha=$((qt_falhas*100/qt_total))&lt;br /&gt;
 echo &amp;quot;Falhas $qt_falhas/$qt_total ($taxa_falha%)&amp;quot;&lt;br /&gt;
  &lt;br /&gt;
 if [ &amp;quot;$taxa_falha&amp;quot; -ge &amp;quot;$corte_taxa_falha&amp;quot; ]; then&lt;br /&gt;
    remove_ospf&lt;br /&gt;
    exit&lt;br /&gt;
 fi&lt;br /&gt;
 adiciona_ospf&lt;br /&gt;
Se rodarmos o script manualmente veremos isto:&lt;br /&gt;
 # /root/scripts/checa_dns.sh&lt;br /&gt;
 total_dominios: 10&lt;br /&gt;
  - dominio www.google.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.terra.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.uol.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.globo.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.facebook.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.youtube.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.twitch.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.discord.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.debian.org - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.redhat.com - 127.0.0.1 - [OK]&lt;br /&gt;
 Falhas 0/10 (0%)&lt;br /&gt;
Se acontecer 100% de falhas o script irá remover os anúncios do OSPF. Se o daemon do unbound morrer, ele tentará reiniciá-lo. Se tudo normalizar o script irá retornar os anúncios para o OSPF. Deixei comentado no script as partes que enviariam uma notificação para o Telegram. Existem diversas documentações sobre isso na Internet, eu mesmo tenho uma. Assim que eu publicar aqui, atualizo essa documentação e sinta-se à vontade de modificar como desejar.&lt;br /&gt;
 # chmod 700 /root/scripts/checa_dns.sh&lt;br /&gt;
Adicione a linha abaixo em seu '''/etc/crontab''':&lt;br /&gt;
 */1 *   * * *   root    /root/scripts/checa_dns.sh&lt;br /&gt;
&lt;br /&gt;
== Habilitando o DoH (&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; over HTTPS) - opcional ==&lt;br /&gt;
Para habilitar o '''DoH''' no Unbound é bem simples. O recurso do '''DoH''' vem para trazer mais segurança e privacidade para o usuário. É um recurso muito pouco utilizado ainda mas que seu cliente pode vir a pedir algum dia.&lt;br /&gt;
&lt;br /&gt;
Você precisará gerar certificados SSL legítimos e para isso você poderá usar o '''Let's Encrypt''' só que de uma forma não tão convencional.&lt;br /&gt;
&lt;br /&gt;
Na sequência vamos instalar o Let's Encrypt para gerarmos nosso certificado SSL:&lt;br /&gt;
 # apt install letsencrypt&lt;br /&gt;
Escolha um '''hostname''' para ser usado no nosso '''DoH''' e aponte ele no seu DNS Autoritativo para seus IPs 10.10.10.10 e 10.10.9.9. Aqui vamos usar o seguinte como exemplo: '''doh.brasilpeeringforum.org'''. Para gerarmos nosso certificado iremos usar o tipo '''DNS-01''', ele não necessita que tenhamos um servidor web rodando no servidor e nem tão pouco levanta um serviço na porta 80 para checar o hostname. Ele utiliza o DNS como validador e vai te solicitar que crie um registro '''CNAME''' no seu '''DNS Autoritativo''' para provar que você tem o controle sobre aquele hostname. Antes disso vamos instalar um programa em Python para podermos automatizar nossa renovação de certificado no futuro. Esse programa se encontra '''[https://github.com/joohoi/acme-dns-certbot-joohoi/raw/master/acme-dns-auth.py aqui]''' mas vou deixá-lo abaixo já modificado o interpretador.&lt;br /&gt;
&lt;br /&gt;
Crie o arquivo '''/etc/letsencrypt/acme-dns-auth.py''' com o conteúdo abaixo:&lt;br /&gt;
 #!/usr/bin/env python3&lt;br /&gt;
 import json&lt;br /&gt;
 import os&lt;br /&gt;
 import requests&lt;br /&gt;
 import sys&lt;br /&gt;
 &lt;br /&gt;
 ### EDIT THESE: Configuration values ###&lt;br /&gt;
 &lt;br /&gt;
 # URL to acme-dns instance&lt;br /&gt;
 ACMEDNS_URL = &amp;quot;&amp;lt;nowiki&amp;gt;https://auth.acme-dns.io&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
 # Path for acme-dns credential storage&lt;br /&gt;
 STORAGE_PATH = &amp;quot;/etc/letsencrypt/acmedns.json&amp;quot;&lt;br /&gt;
 # Whitelist for address ranges to allow the updates from&lt;br /&gt;
 # Example: ALLOW_FROM = [&amp;quot;192.168.10.0/24&amp;quot;, &amp;quot;::1/128&amp;quot;]&lt;br /&gt;
 ALLOW_FROM = []&lt;br /&gt;
 # Force re-registration. Overwrites the already existing acme-dns accounts.&lt;br /&gt;
 FORCE_REGISTER = False&lt;br /&gt;
 &lt;br /&gt;
 ###   DO NOT EDIT BELOW THIS POINT   ###&lt;br /&gt;
 ###         HERE BE DRAGONS          ###&lt;br /&gt;
 &lt;br /&gt;
 DOMAIN = os.environ[&amp;quot;CERTBOT_DOMAIN&amp;quot;]&lt;br /&gt;
 if DOMAIN.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
     DOMAIN = DOMAIN[2:]&lt;br /&gt;
 VALIDATION_DOMAIN = &amp;quot;_acme-challenge.&amp;quot;+DOMAIN&lt;br /&gt;
 VALIDATION_TOKEN = os.environ[&amp;quot;CERTBOT_VALIDATION&amp;quot;]&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 class AcmeDnsClient(object):&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
     Handles the communication with ACME-DNS API&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
     def __init__(self, acmedns_url):&lt;br /&gt;
         self.acmedns_url = acmedns_url&lt;br /&gt;
 &lt;br /&gt;
     def register_account(self, allowfrom):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Registers a new ACME-DNS account&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
         if allowfrom:&lt;br /&gt;
             # Include whitelisted networks to the registration call&lt;br /&gt;
             reg_data = {&amp;quot;allowfrom&amp;quot;: allowfrom}&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;,&lt;br /&gt;
                                 data=json.dumps(reg_data))&lt;br /&gt;
         else:&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;)&lt;br /&gt;
         if res.status_code == 201:&lt;br /&gt;
             # The request was successful&lt;br /&gt;
             return res.json()&lt;br /&gt;
         else:&lt;br /&gt;
             # Encountered an error&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to register a new acme-dns &amp;quot;&lt;br /&gt;
                    &amp;quot;account. HTTP status {}, Response body: {}&amp;quot;)&lt;br /&gt;
             print(msg.format(res.status_code, res.text))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def update_txt_record(self, account, txt):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Updates the TXT challenge record to ACME-DNS subdomain.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         update = {&amp;quot;subdomain&amp;quot;: account['subdomain'], &amp;quot;txt&amp;quot;: txt}&lt;br /&gt;
         headers = {&amp;quot;X-Api-User&amp;quot;: account['username'],&lt;br /&gt;
                    &amp;quot;X-Api-Key&amp;quot;: account['password'],&lt;br /&gt;
                    &amp;quot;Content-Type&amp;quot;: &amp;quot;application/json&amp;quot;}&lt;br /&gt;
         res = requests.post(self.acmedns_url+&amp;quot;/update&amp;quot;,&lt;br /&gt;
                             headers=headers,&lt;br /&gt;
                             data=json.dumps(update))&lt;br /&gt;
         if res.status_code == 200:&lt;br /&gt;
             # Successful update&lt;br /&gt;
             return&lt;br /&gt;
         else:&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to update TXT record in &amp;quot;&lt;br /&gt;
                    &amp;quot;acme-dns. \n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request headers:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request body:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response HTTP status: {}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response body: {}&amp;quot;)&lt;br /&gt;
             s_headers = json.dumps(headers, indent=2, sort_keys=True)&lt;br /&gt;
             s_update = json.dumps(update, indent=2, sort_keys=True)&lt;br /&gt;
             s_body = json.dumps(res.json(), indent=2, sort_keys=True)&lt;br /&gt;
             print(msg.format(s_headers, s_update, res.status_code, s_body))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
 class Storage(object):&lt;br /&gt;
     def __init__(self, storagepath):&lt;br /&gt;
         self.storagepath = storagepath&lt;br /&gt;
         self._data = self.load()&lt;br /&gt;
 &lt;br /&gt;
     def load(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Reads the storage content from the disk to a dict structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         data = dict()&lt;br /&gt;
         filedata = &amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             with open(self.storagepath, 'r') as fh:&lt;br /&gt;
                 filedata = fh.read()&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             if os.path.isfile(self.storagepath):&lt;br /&gt;
                 # Only error out if file exists, but cannot be read&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage file exists but cannot be read&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         try:&lt;br /&gt;
             data = json.loads(filedata)&lt;br /&gt;
         except ValueError:&lt;br /&gt;
             if len(filedata) &amp;gt; 0:&lt;br /&gt;
                 # Storage file is corrupted&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage JSON is corrupted&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         return data&lt;br /&gt;
 &lt;br /&gt;
     def save(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Saves the storage content to disk&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         serialized = json.dumps(self._data)&lt;br /&gt;
         try:&lt;br /&gt;
             with os.fdopen(os.open(self.storagepath,&lt;br /&gt;
                                    os.O_WRONLY | os.O_CREAT, 0o600), 'w') as fh:&lt;br /&gt;
                 fh.truncate()&lt;br /&gt;
                 fh.write(serialized)&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             print(&amp;quot;ERROR: Could not write storage file.&amp;quot;)&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def put(self, key, value):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Puts the configuration value to storage and sanitize it&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         # If wildcard domain, remove the wildcard part as this will use the&lt;br /&gt;
         # same validation record name as the base domain&lt;br /&gt;
         if key.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
             key = key[2:]&lt;br /&gt;
         self._data[key] = value&lt;br /&gt;
 &lt;br /&gt;
     def fetch(self, key):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Gets configuration value from storage&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             return self._data[key]&lt;br /&gt;
         except KeyError:&lt;br /&gt;
             return None&lt;br /&gt;
 &lt;br /&gt;
 if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
     # Init&lt;br /&gt;
     client = AcmeDnsClient(ACMEDNS_URL)&lt;br /&gt;
     storage = Storage(STORAGE_PATH)&lt;br /&gt;
 &lt;br /&gt;
     # Check if an account already exists in storage&lt;br /&gt;
     account = storage.fetch(DOMAIN)&lt;br /&gt;
     if FORCE_REGISTER or not account:&lt;br /&gt;
         # Create and save the new account&lt;br /&gt;
         account = client.register_account(ALLOW_FROM)&lt;br /&gt;
         storage.put(DOMAIN, account)&lt;br /&gt;
         storage.save()&lt;br /&gt;
 &lt;br /&gt;
         # Display the notification for the user to update the main zone&lt;br /&gt;
         msg = &amp;quot;Please add the following CNAME record to your main DNS zone:\n{}&amp;quot;&lt;br /&gt;
         cname = &amp;quot;{} CNAME {}.&amp;quot;.format(VALIDATION_DOMAIN, account[&amp;quot;fulldomain&amp;quot;])&lt;br /&gt;
         print(msg.format(cname))&lt;br /&gt;
 &lt;br /&gt;
     # Update the TXT record in acme-dns instance&lt;br /&gt;
     client.update_txt_record(account, VALIDATION_TOKEN)&lt;br /&gt;
&lt;br /&gt;
 # chmod +x /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
Usaremos a seguinte instrução para criar nosso certificado:&lt;br /&gt;
 # certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d doh.brasilpeeringforum.org&lt;br /&gt;
 Saving debug log to /var/log/letsencrypt/letsencrypt.log&lt;br /&gt;
 Plugins selected: Authenticator manual, Installer None&lt;br /&gt;
 Cert is due for renewal, auto-renewing...&lt;br /&gt;
 Renewing an existing certificate for doh.brasilpeeringforum.org&lt;br /&gt;
 Performing the following challenges:&lt;br /&gt;
 dns-01 challenge for doh.brasilpeeringforum.org&lt;br /&gt;
 Running manual-auth-hook command: /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
 Output from manual-auth-hook command acme-dns-auth.py:&lt;br /&gt;
 Please add the following CNAME record to your main DNS zone:&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
 &lt;br /&gt;
 Waiting for verification...&lt;br /&gt;
 &lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Challenges loaded. Press continue to submit to CA. Pass &amp;quot;-v&amp;quot; for more info about&lt;br /&gt;
 challenges.&lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Press Enter to Continue&lt;br /&gt;
Nesse momento você cria o registro '''CNAME''' no seu DNS Autoritativo conforme ele solicitou: '''_acme-challenge.doh.brasilpeeringforum.org IN CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.''' e somente depois de criado e checado no DNS, você pressiona o '''Enter''' para continuar. Você pode checar dessa forma:&lt;br /&gt;
 # host -t cname _acme-challenge.doh.brasilpeeringforum.org&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org is an alias for b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
Para que nosso certificado seja automaticamente renovado colocaremos no '''/etc/crontab''' a seguinte linha abaixo:&lt;br /&gt;
 00 00   1 * *   root    /usr/bin/certbot -q renew --deploy-hook &amp;quot;/usr/sbin/unbound-control reload_keep_cache&amp;quot;&lt;br /&gt;
Acima temos a instrução para renovação automática do certificado. Repare que você vai precisar também copiar esse certificado para seus outros servidores, escolha um servidor para manter o certificado sempre atualizado e crie um script que faça a mesma cópia remotamente para os outros servidores. O '''scp''' e o '''rsync''' são seus aliados nisso.&lt;br /&gt;
&lt;br /&gt;
=== Configurando o Unbound ===&lt;br /&gt;
Em nosso '''/etc/unbound/unbound.conf.d/local.conf''', adicionaremos no bloco &amp;quot;'''server:'''&amp;quot; o seguinte:&lt;br /&gt;
 interface: 10.10.10.10@443 &lt;br /&gt;
 interface: 10.10.9.9@443&lt;br /&gt;
 interface: fd00::10:10:10:10@443&lt;br /&gt;
 interface: fd00::10:10:9:9@443&lt;br /&gt;
 tls-service-key: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/privkey.pem&amp;quot; &lt;br /&gt;
 tls-service-pem: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/fullchain.pem&amp;quot;&lt;br /&gt;
Para usar o recurso do '''DoH''' você precisará habilitar o recurso no seu navegador e informar a URL. Vou colocar o exemplo do '''Google Chrome''': Digite '''chrome://settings/security?search=dns''' no seu Chrome e ative '''Usar DNS seguro''', selecione '''Personalizado''' e adicione nossa URL:&lt;br /&gt;
[[Arquivo:Doh bpf2.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Finalizando ==&lt;br /&gt;
Aqui finalizamos nosso projeto para uma Rede de DNS(s) Recursivos Anycast com Hyperlocal. Esse projeto é escalável, seguro, resiliente e você entregará muito mais qualidade de Internet para o seu cliente. Pare de entregar o '''8.8.8.8''' para os seus clientes, você está contribuindo para uma Internet mais lenta, sem a qualidade que o seu cliente merece. Investi meu tempo, que é muito pouco, para deixar esse documento para a comunidade, para você melhorar o seu ISP, para dar um UP! nele, então vamos começar 2023 com o pé direito. O que acha?&lt;br /&gt;
&lt;br /&gt;
Como prova de conceito, uma imagem abaixo onde temos uma Rede em produção de DNS(s) Recursivos Anycast e apontando exatamente o momento em que houve alguma situação que fez com que as queries de DNS, convergissem de um node para outro, de forma transparente e automática para o cliente. Podemos notar também que ao ser resolvido o problema, o tráfego retornou para o seu node correto:&lt;br /&gt;
[[Arquivo:Convergencia.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== KINDNS (Stands for Knowledge-Sharing and Instantiating Norms for DNS and Naming Security) ==&lt;br /&gt;
Achou que havia terminado? Agora que você tem a capacidade de montar uma '''Rede de DNS Recursivo''' com todas essas features acima, com todas as ferramentas que foram comentadas, o que acha de certificar o que fez?&lt;br /&gt;
&lt;br /&gt;
Assim como o [https://www.manrs.org/ MANRS] veio para certificar nosso sistema de roteamento na Internet, agora temos o [https://kindns.org/ KINDNS] para certificar que nossos sistemas de DNS estão bem feitos e dentro dos padrões de segurança. Existem '''7 ações''' que podem ser certificadas para nossos DNS Recursivos e estão aqui em https://kindns.org/shared-private-resolvers/. Com essa nossa documentação, se bem aplicada, você pode se candidatar ao KINDNS e ter seu ASN listado aqui https://kindns.org/participants/&lt;br /&gt;
&lt;br /&gt;
Obter e manter o '''MANRS''' e '''KINDNS''' demonstra seu compromisso com as Boas Práticas, contribui para termos uma '''Internet''' mais segura e te abre portas para novos negócios que possam exigir essas conformidades.&lt;br /&gt;
&lt;br /&gt;
Autor: [[Usuário:Gondim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Infraestrutura]]&lt;br /&gt;
__FORCARTDC__&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=4005</id>
		<title>DNS Recursivo Anycast Hyperlocal</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=4005"/>
		<updated>2025-12-26T16:35:30Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
==Introdução==&lt;br /&gt;
Você sabe como funciona a Internet? Essa é uma pergunta que meu amigo '''Thiago Ayub''' sempre faz aos seus candidatos à vagas de emprego e não importa o quanto tenham de experiência em '''Engenharia de Redes''', todos sempre travam nesse momento. Todos estão sempre prontos e preparados para resolver os problemas mais cabeludos em '''BGP''', '''OSPF''', '''MPLS''', etc mas travam com essa simples pergunta. Para contextualizar e visualizarmos melhor vamos nos atentar à imagem abaixo e uma explicação simplificada de como funciona:&lt;br /&gt;
[[Arquivo:Dns hierarquia.png|esquerda|commoldura]]&lt;br /&gt;
Tudo começa com um usuário sentado confortavelmente e querendo acessar um conteúdo disponível na Internet. Ele digita em seu navegador preferido a URL: '''&amp;lt;nowiki&amp;gt;https://wiki.brasilpeeringforum.org&amp;lt;/nowiki&amp;gt;''',&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;1)&amp;lt;/big&amp;gt;''' &amp;lt;big&amp;gt;O&amp;lt;/big&amp;gt; &amp;lt;big&amp;gt;navegador irá requisitar do '''DNS Recursivo''' utilizado pelo usuário, o '''endereço IP''' que responde pelo nome '''wiki.'''&amp;lt;/big&amp;gt;'''brasilpeeringforum.org'''&amp;lt;big&amp;gt;. Isso porque todos os acessos se dão na Internet através do '''endereço''' '''IP''' e não através do '''nome'''. Imaginem se tivéssemos que decorar os endereços IPs de todos os sites e serviços que quiséssemos acessar na Internet?&amp;lt;/big&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;big&amp;gt;'''2)''' Nosso DNS Recursivo checa se a informação consta em seu cache.&amp;lt;/big&amp;gt; Se a informação existir ela é devolvida ao navegador do usuário e aí este consegue acessar o site.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Do contrário o DNS Recursivo pergunta ao '''Root Server''' quem é o '''TLD (Top Level Domain)''' responsável para atender a requisição. &lt;br /&gt;
&lt;br /&gt;
'''4)''' O '''Root Server''' informa ao DNS Recursivo o endereço do '''TLD responsável'''. No Brasil o '''TLD''' responsável pelo '''.br''' seria o '''Registro.br'''.&lt;br /&gt;
&lt;br /&gt;
'''5)''' O DNS Recursivo pergunta ao '''TLD''' sobre '''wiki.brasilpeeringforum.org''' e este responde com os endereços IP dos '''DNS Autoritativos''' responsáveis pelo domínio '''brasilpeeringforum.org.'''&lt;br /&gt;
&lt;br /&gt;
'''6)''' O DNS Recursivo pergunta aos '''DNS Autoritativos''' pelo '''wiki.brasilpeeringforum.org''' e este responde com o '''endereço IP'''.&lt;br /&gt;
&lt;br /&gt;
'''7)''' Por último o DNS Recursivo devolve a informação para o navegador do usuário.&lt;br /&gt;
&lt;br /&gt;
Como que se dá a comunicação entre os '''DNS(s) Recursivos, Root Servers, TLDs''' e '''Autoritativos'''? Como que o navegador do usuário, após receber o IP do site, consegue chegar no servidor que tem o conteúdo? Isso só é possível devido ao protocolo chamado '''BGP (Border Gateway Protocol)''', todos os caminhos que conhecemos como rotas de destino, são anunciadas por milhares de participantes na '''Internet''' conhecidos como '''AS (Autonomous System)''', esses participantes se interligam para disponibilizar conteúdos e acessos pelo mundo aos milhares de usuários. É uma imensa rede colaborativa formada por Empresas, Universidades, Governos e todos que queiram se interconectar. Percebam que sem o '''BGP''', que serve de caminho para chegarmos nos conteúdos e sem o '''DNS (Domain Name System)''' para traduzir o nome para o endereço IP, a '''Internet''' não funcionaria e por isso precisamos cuidar muito bem desses dois serviços.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Mas não acaba por aí. O '''DNS Recursivo''' tem um papel muito importante para o Provedor de Internet e que envolve segurança, qualidade de acesso à Internet e a disponibilidade do serviço entregue ao cliente. Quando bem configurado acelera as consultas dos acessos graças ao seu cache interno, mas para que isso seja percebido pelo assinante, é necessário que esteja o mais próximo possível do seu cliente.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Um erro que destrói a qualidade do nosso serviço ==&lt;br /&gt;
Um erro muito comum que muitas operadoras cometem é utilizar DNS Recursivo externo, como o '''8.8.8.8''', '''1.1.1.1''' e outros, para seus clientes. Quanto mais próximo dos seus clientes, mais qualidade de serviço estará entregando a eles. Conteúdos serão entregues mais rapidamente pois serão resolvidos e armazenados em caches locais e não consultados remotamente na Internet. Para falar mais sobre isso, te convido leitor desse documento, que assista essa palestra do '''Thiago Ayub''' no '''GTER 51/GTS 37''' (2022) '''8.888 MOTIVOS PARA NÃO USAR DNS RECURSIVO EXTERNO EM SEU AS''': https://www.youtube.com/watch?v=Rsvpu5uF2Io&lt;br /&gt;
&lt;br /&gt;
== Objetivo ==&lt;br /&gt;
O objetivo desta documentação não é te ensinar tudo sobre '''DNS''', '''BGP''', '''OSPF''' e nem tão pouco sobre GNU/Linux e sim te mostrar um exemplo de servidor DNS Recursivo implementado pensando em segurança, qualidade e resiliência. Usaremos em todas as nossas documentações o [https://www.debian.org/ Debian GNU/Linux], por ser uma distribuição que considero uma obra de arte criada por uma enorme comunidade séria, com vasta experiência de anos, qualidade no empacotamento dos programas, estável e com uma equipe de segurança excelente e ativa. Caso você leitor, utilize alguma outra distribuição GNU/Linux, todo conteúdo apresentado aqui pode ser aplicado em outras distros, desde que respeitando as particularidades de cada uma.&lt;br /&gt;
&lt;br /&gt;
Aqui construiremos um sistema do tipo '''Anycast''', ou seja, terás o serviço rodando em diversas localidades da sua Rede utilizando o mesmo endereçamento IP e que atenderá seu cliente mais próximo. Em caso de falhas, seus clientes automaticamente e de forma transparente continuarão consultando o DNS mais próximo deles. Para que ele funcione dessa forma você precisará ter uma '''Rede OSPF''' implementada no seu Provedor Internet ou algum outro protocolo como por exemplo o '''ISIS,''' mas esse documento não irá abordar o '''ISIS'''. Também utilizaremos o '''Hyperlocal''' como recurso adicional para gerar algumas proteções de segurança e velocidade na resposta relacionada aos servidores de DNS Raiz da Internet.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
Para exemplificar nosso servidor de DNS Recursivo, usaremos como base das explicações um diagrama demonstrando o uso do DNS Recursivo em uma Rede fictícia. Adotaremos IPs privados e reservados para demonstrar todo o ambiente do Provedor de Internet.&lt;br /&gt;
[[Arquivo:Recursivo99.png|esquerda|miniaturadaimagem|695x695px]]&lt;br /&gt;
Nesse diagrama podemos observar alguns detalhes técnicos como por exemplo: existem '''3 servidores de DNS Recursivo''' posicionados em locais diferentes, que poderiam estar em bairros diferentes e até em cidades diferentes. Em cada servidor teremos '''2 loopbacks''' com os IPs:&lt;br /&gt;
&lt;br /&gt;
'''10.10.10.10/32 - fd00::10:10:10:10/128'''&lt;br /&gt;
&lt;br /&gt;
'''10.10.9.9/32 - fd00::10:10:9:9/128'''&lt;br /&gt;
&lt;br /&gt;
Esses IPs serão entregues pelos concentradores '''PPPoE''' ou '''IPoE''' ('''BNG''') para seus clientes como '''DNS primário''' e '''secundário'''. Podemos usar IPs privados como DNS primário e secundário em um ambiente real? Sim podemos, desde que não sejam IPs que possam ter problemas com as redes privadas dos clientes. Ex.: rede do cliente usando '''192.168.0.0/24'''. Se entregarmos o DNS sendo '''192.168.0.10''' e '''192.168.0.20''' teremos problemas e o cliente ficará sem Internet, porque '''192.168.0.10''' e '''192.168.0.20''' fazem parte da rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
Agora entregando '''10.10.10.10,''' '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9''' não teríamos problemas com a rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
'''Motivos para usarmos IPs privados:'''&lt;br /&gt;
* O principal motivo está relacionado com a segurança, uma vez que sendo um IP privado, não pode sofrer ataques DDoS direcionados diretamente para ele, vindos da Internet.&lt;br /&gt;
* Nem mesmo o cliente da sua rede conhece os '''IPs públicos''' utilizados para recursividade na Internet.&lt;br /&gt;
* Memorizar os IPs '''10.10.10.10''' e '''10.10.9.9''' é tão fácil quanto memorizar o '''8.8.8.8''' e o '''1.1.1.1'''. Mais fácil para o seu técnico guardar essa informação e utilizar onde for necessário.&lt;br /&gt;
Cada servidor DNS Recursivo possui um '''IPv4 público''', aqui representado por '''198.18.x.x/27''' e um '''IPv6 global''' representado por um IP dentro do prefixo '''2001:db8::/32'''. Cada servidor precisa ter os seus próprios IPs e são através destes IPs que as consultas de DNS serão realizadas na Internet.&lt;br /&gt;
&lt;br /&gt;
Nessa topologia usando '''Anycast''', o cliente será sempre atendido pelo '''DNS Recursivo''' mais próximo, desde que os pesos no '''OSPF''' estejam ajustados corretamente.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
== Dados do servidor ==&lt;br /&gt;
Podemos utilizar um sistema virtualizado ou não. Sistemas virtualizados são bem vindos pois são mais simples quando precisamos fazer backups, levantar outros sistemas sem complicações e se precisarmos restaurar rapidamente algum sistema que ficou indisponível por algum motivo. A configuração abaixo tem capacidade para atender algo em torno a '''50.000 assinantes ou mais'''. O DNS Recursivo é um serviço que pode ser utilizado até mesmo em um '''Raspberry Pi''' e atender operações pequenas, nesse caso com o intuito de economizar energia e espaço. Nosso foco aqui é montar uma rede de '''DNS Recursivo Anycast com HyperLocal'''. Como comentei acima o servidor deve ficar o mais próximo dos clientes para termos a '''menor latência possível''' e '''sempre menor que 5ms''' entre o cliente e o servidor.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!CPU&lt;br /&gt;
!Memória&lt;br /&gt;
!Disco&lt;br /&gt;
!Sistema&lt;br /&gt;
|-&lt;br /&gt;
|2.4Ghz 8 cores&lt;br /&gt;
|16G DDR4&lt;br /&gt;
|30G&lt;br /&gt;
|Debian 13 amd64 (Trixie)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Softwares utilizados ==&lt;br /&gt;
* Debian 13 amd64 (Trixie) instalação mínima.&lt;br /&gt;
&lt;br /&gt;
* [https://frrouting.org/ FRRouting].&lt;br /&gt;
* Unbound.&lt;br /&gt;
* Chrony (NTP/NTS).&lt;br /&gt;
* Shell script em bash.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades que teremos ==&lt;br /&gt;
* Sistema em Anycast.&lt;br /&gt;
* Hyperlocal.&lt;br /&gt;
* Controle de acesso por &amp;lt;abbr&amp;gt;ACL&amp;lt;/abbr&amp;gt;.&lt;br /&gt;
* RPZ (Response Policy Zone).&lt;br /&gt;
* Bloqueio de consultas do tipo ANY.&lt;br /&gt;
* QNAME minimization habilitado. (habilitado por default no Unbound)&lt;br /&gt;
* Recursividade em IPv4 e IPv6.&lt;br /&gt;
* DNSSEC habilitado.&lt;br /&gt;
* &amp;lt;abbr&amp;gt;DoH (DNS&amp;lt;/abbr&amp;gt; over HTTPS) habilitado.&lt;br /&gt;
&lt;br /&gt;
== Monitoramento ==&lt;br /&gt;
O monitoramento é algo bem específico e não é o foco deste documento mas é extremamente importante que você monitore seus servidores de DNS por alguma ferramenta como o Zabbix. Aqui mostrarei apenas como enviar as informações para o Zabbix. Algumas coisas que você deveria monitorar nos servidores de DNS Recursivo:&lt;br /&gt;
* Serviço do unbound parou.&lt;br /&gt;
* Perda de pacotes.&lt;br /&gt;
* Latência alta de pacotes.&lt;br /&gt;
* Lentidão na resolução de queries.&lt;br /&gt;
* CPU alta.&lt;br /&gt;
* Load alto.&lt;br /&gt;
* Memória com uso alto.&lt;br /&gt;
* Disco com pouco espaço.&lt;br /&gt;
* Queda brusca nas queries.&lt;br /&gt;
* A recursividade parou de funcionar.&lt;br /&gt;
* A recursividade voltou a funcionar.&lt;br /&gt;
Este abaixo é um exemplo de monitoramento de um sistema de DNS Recursivo que atende 50.000 assinantes:&lt;br /&gt;
[[Arquivo:Grafana dns.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Configurando a Rede ==&lt;br /&gt;
Nossa documentação será baseada no diagrama apresentado acima e por isso configuraremos apenas um dos três servidores, porque os outros serão configurados da mesma forma, só que com dados diferentes. Para tanto assumirei que já temos um sistema Debian instalado com o mínimo de pacotes e somente com sshd, para que possamos acessar remotamente mais tarde. '''Não instale um ambiente gráfico no servidor''', você não deve querer fazer isso por diversos motivos e os principais: primeiro porque não é um Desktop e segundo porque o ambiente gráfico devoraria toda a memória com recursos que não seriam úteis aqui.&lt;br /&gt;
&lt;br /&gt;
Em '''/etc/network/interfaces''' deixaremos assim:&lt;br /&gt;
 # This file describes the network interfaces available on your system&lt;br /&gt;
 # and how to activate them. For more information, see interfaces(5).&lt;br /&gt;
  &lt;br /&gt;
 source /etc/network/interfaces.d/*&lt;br /&gt;
  &lt;br /&gt;
 # The loopback network interface&lt;br /&gt;
 auto lo&lt;br /&gt;
 iface lo inet loopback&lt;br /&gt;
  &lt;br /&gt;
 auto lo:0&lt;br /&gt;
 iface lo:0 inet static&lt;br /&gt;
       address 10.10.10.10/32&lt;br /&gt;
  &lt;br /&gt;
 auto lo:1&lt;br /&gt;
 iface lo:1 inet static&lt;br /&gt;
       address 10.10.9.9/32&lt;br /&gt;
 &lt;br /&gt;
 auto lo:2&lt;br /&gt;
 iface lo:2 inet6 static&lt;br /&gt;
       address fd00::10:10:10:10/128&lt;br /&gt;
 &lt;br /&gt;
 auto lo:3&lt;br /&gt;
 iface lo:3 inet6 static&lt;br /&gt;
       address fd00::10:10:9:9/128&lt;br /&gt;
  &lt;br /&gt;
 # The primary network interface&lt;br /&gt;
 auto ens18&lt;br /&gt;
 iface ens18 inet static&lt;br /&gt;
         address 198.18.1.10/27&lt;br /&gt;
         gateway 198.18.1.1&lt;br /&gt;
  &lt;br /&gt;
 iface ens18 inet6 static&lt;br /&gt;
         address 2001:db8::faca:198:18:1:10/64&lt;br /&gt;
         gateway 2001:db8::faca:198:18:1:1&lt;br /&gt;
  &lt;br /&gt;
 # The secondary network interface&lt;br /&gt;
 auto ens18:0&lt;br /&gt;
 iface ens18:0 inet static&lt;br /&gt;
         address 172.16.0.6/30&lt;br /&gt;
Nesse cenário temos as duas '''loopbacks''' com os IPs '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10''' e '''fd00::10:10:9:9''' que serão anunciados via OSPF para a rede e serem entregues aos clientes via BNG. Os IPs '''198.18.1.10''' e '''2001:db8::faca:198:18:1:10''' serão usados para fazerem a recursividade na Internet tanto em IPv4 quanto em IPv6. Esses IPs não devem ser divulgados para clientes; os IPs públicos são dedicados apenas para essa finalidade.&lt;br /&gt;
&lt;br /&gt;
== Configuração dos repositórios Debian ==&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://security.debian.org/debian-security/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-security&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-updates&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian-backports.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-backports&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
&lt;br /&gt;
 # rm /etc/apt/sources.list&lt;br /&gt;
Após a configuração vamos instalar alguns pacotes necessários e outros úteis:&lt;br /&gt;
 # apt update &amp;amp;&amp;amp; apt full-upgrade&lt;br /&gt;
 # apt install net-tools nftables htop iotop sipcalc tcpdump curl gnupg rsync wget host dnsutils mtr-tiny bmon sudo tmux whois ethtool dnstop&lt;br /&gt;
&lt;br /&gt;
== Fazendo algum tuning no sistema ==&lt;br /&gt;
Em '''/etc/sysctl.d/100-tuning.conf''' adicionamos essas instruções:&lt;br /&gt;
 net.core.rmem_max = 2147483647&lt;br /&gt;
 net.core.wmem_max = 2147483647&lt;br /&gt;
 net.ipv4.tcp_rmem = 4096 87380 2147483647&lt;br /&gt;
 net.ipv4.tcp_wmem = 4096 65536 2147483647&lt;br /&gt;
 net.netfilter.nf_conntrack_buckets = 512000&lt;br /&gt;
 net.netfilter.nf_conntrack_max = 4096000&lt;br /&gt;
 vm.swappiness=10&lt;br /&gt;
Estamos fazendo algumas melhorias de memória, algumas relacionadas a '''conntrack''' porque se for usar um filtro de pacotes stateful, como o '''Netfilter/IPTables''' ou '''Netfilter/NFTables''', o valor default da tabela é pequeno e dependendo da situação, se estourar essa tabela, as consultas de DNS terão problemas também. O DNS Recursivo não deve ficar aberto para qualquer um na Internet, ele deve ser liberado apenas para seus clientes. Podemos fazer através das ACLs do Unbound e pelo filtro de pacotes. O último parâmetro diz respeito ao uso de swap, por padrão o Debian permite o uso de swap após 40% do uso da memória, nesse caso estamos dizendo para o sistema usar o swap com 90% de uso da memória.&lt;br /&gt;
&lt;br /&gt;
Precisamos adicionar o módulo '''nf_conntrack''' em '''/etc/modules''' para que seja carregado em tempo de boot, senão os parâmetros de '''conntrack''' que colocamos em '''/etc/sysctl.conf''' não serão carregados.&lt;br /&gt;
 # echo nf_conntrack &amp;gt;&amp;gt; /etc/modules&lt;br /&gt;
 # modprobe nf_conntrack&lt;br /&gt;
 # sysctl -p&lt;br /&gt;
&lt;br /&gt;
== Instalando o FRRouting ==&lt;br /&gt;
O FRRouting é o programa que usaremos para fazer os anúncios das nossas loopbacks via OSPF. Nesse documento usaremos a versão 10.x:&lt;br /&gt;
 # apt install frr frr-doc frr-pythontools&lt;br /&gt;
Aconselho depois de instalar os pacotes, marcá-los para não atualizar juntamente com os demais pacotes, isso é para evitar de ocorrer alguma atualização no FRRouting, que torne o serviço instável por algum motivo. Não que isso vá ocorrer, mas é melhor fazer essa atualização quando realmente for necessário.&lt;br /&gt;
 # apt-mark hold frr frr-doc frr-pythontools&lt;br /&gt;
Após esse comando acima, o sistema manterá a instalação original do pacote intacta. Para desbloquear basta executar o comando abaixo:&lt;br /&gt;
 # apt-mark unhold frr frr-doc frr-pythontools&lt;br /&gt;
&lt;br /&gt;
== Removendo o APPARMOR ==&lt;br /&gt;
O '''APPARMOR''' às vezes causa mais problemas que solução e se não for fazer uma completa configuração nele, é melhor desabilitá-lo. Para fazer isso efetivamente, o procedimento é esse abaixo:&lt;br /&gt;
 # mkdir -p /etc/default/grub.d&lt;br /&gt;
 # echo 'GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;$GRUB_CMDLINE_LINUX_DEFAULT apparmor=0&amp;quot;' | tee /etc/default/grub.d/apparmor.cfg&lt;br /&gt;
 # update-grub&lt;br /&gt;
 # reboot&lt;br /&gt;
&lt;br /&gt;
== Instalando o Unbound ==&lt;br /&gt;
Nesse momento ainda não iremos configurar o Unbound, apenas instalar o pacote e acertar o ambiente. Vamos instalar o unbound do backports porque este já possui suporte ao DoH que veremos mais à frente.&lt;br /&gt;
 # apt install unbound dns-root-data&lt;br /&gt;
 # mkdir -p /var/log/unbound&lt;br /&gt;
 # touch /var/log/unbound/unbound.log&lt;br /&gt;
 # chown -R unbound:unbound /var/log/unbound/&lt;br /&gt;
 # systemctl restart unbound&lt;br /&gt;
Configurando o logrotate:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/logrotate.d/unbound&lt;br /&gt;
 /var/log/unbound/unbound.log {&lt;br /&gt;
     rotate 5&lt;br /&gt;
     weekly&lt;br /&gt;
     postrotate&lt;br /&gt;
         unbound-control log_reopen&lt;br /&gt;
     endscript&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
Reiniciando o serviço:&lt;br /&gt;
 # systemctl restart logrotate.service&lt;br /&gt;
&lt;br /&gt;
== Desabilitando THP (Transparente Huge Pages) em arquitetura AMD64 ==&lt;br /&gt;
No Debian o '''THP''' vem habilitado como '''always''' e o '''unbound''' por trabalhar bastante com alterações do cache em memória, isso pode acabar causando um consumo crescente de uso de RAM sem necessidade. É uma boa prática desabilitá-lo com os passos abaixo:&lt;br /&gt;
&lt;br /&gt;
https://github.com/NLnetLabs/unbound/issues/724&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/systemd/system/disable-thp.service&lt;br /&gt;
 [Unit]&lt;br /&gt;
 Description=Desabilita Transparent Huge Pages (THP)&lt;br /&gt;
 After=network.target&lt;br /&gt;
 &lt;br /&gt;
 [Service]&lt;br /&gt;
 Type=oneshot&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled&amp;quot;&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/defrag&amp;quot;&lt;br /&gt;
 RemainAfterExit=yes&lt;br /&gt;
 &lt;br /&gt;
 [Install]&lt;br /&gt;
 WantedBy=multi-user.target&lt;br /&gt;
 EOF&lt;br /&gt;
Acima configuramos o serviço '''disable-thp.service''' para desabilitar o '''THP''' e abaixo habilitamos no '''systemd''' e iniciamos:&lt;br /&gt;
 # systemctl daemon-reload&lt;br /&gt;
 # systemctl enable --now disable-thp&lt;br /&gt;
&lt;br /&gt;
== Preparando o monitoramento do seu DNS Recursivo ==&lt;br /&gt;
O monitoramento do seu DNS Recursivo é muito importante e para isso vamos usar um '''template para Zabbix''', que modifiquei juntamente com o seu shell script e que enviará os dados para o seu Zabbix server via '''zabbix-sender'''. O projeto original está aqui '''https://github.com/jeftedelima/Unbound-DNS&amp;lt;nowiki/&amp;gt;.''' O xml alterado está aqui '''https://github.com/gondimcodes/template_zabbix_dns_unbound'''. Embora seja antigo é perfeitamente importável no Zabbix 6.0, por exemplo.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;nowiki/&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Teremos um shell script que você precisará colocar no seu '''/etc/crontab'''. No exemplo abaixo assumi que o shell script está em '''/root/scripts'''. De 5 em 5 minutos os dados serão enviados para o seu Zabbix server.&lt;br /&gt;
 */5 * * * *     root    /root/scripts/unboundSend.sh '''IP_zabbix_server''' '''nome_do_host''' 1&amp;gt; /dev/null&lt;br /&gt;
Na linha acima, troque o '''IP_zabbix_server''' pelo '''IP do seu servidor Zabbix''' e o '''nome_do_host''' pelo '''hostname''' '''do seu DNS Recursivo'''. Você precisará instalar o pacote '''zabbix-sender''' no seu DNS Recursivo pois ele será usado para enviar os dados para o Zabbix server.&lt;br /&gt;
&lt;br /&gt;
Abaixo o '''unboundSend.sh''' também alterado com inclusão de mais dados:&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 #       @Jefte de Lima Ferreira&lt;br /&gt;
 #       jeftedelima at gmail dot com&lt;br /&gt;
 #       CRON Example&lt;br /&gt;
 #       Contributor: Marcelo Gondim - gondim at gmail dot com&lt;br /&gt;
 #       */5   **** root sh /home/dir/unboundSend.sh 192.168.10.1 Unbound 1&amp;gt; /dev/null&lt;br /&gt;
  &lt;br /&gt;
 if [ -z ${1} ] || [ -z ${2} ] ; then&lt;br /&gt;
         echo &amp;quot;You need to specify the IP address of zabbix server and hostname of your DNS Unbound on zabbix&amp;quot;&lt;br /&gt;
         echo &amp;quot;Usage example: ./unboundSend.sh 192.168.10.1 UnboundServer&amp;quot;&lt;br /&gt;
         exit 1&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 # ZABBIX_SERVER IP&lt;br /&gt;
 IP_ZABBIX=$1&lt;br /&gt;
 # NAME Unbound on Zabbix&lt;br /&gt;
 NAME_HOST=$2&lt;br /&gt;
 DIR_TEMP=/var/tmp/&lt;br /&gt;
 FILE=&amp;quot;${DIR_TEMP}dump_unbound_control_stats.txt&amp;quot;&lt;br /&gt;
 unbound-control stats &amp;gt; ${FILE}&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_NUM_QUERIES=$(cat ${FILE} | grep -w 'total.num.queries' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEHITS=$(cat ${FILE} | grep -w 'total.num.cachehits' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEMISS=$(cat ${FILE} | grep -w 'total.num.cachemiss' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_PREFETCH=$(cat ${FILE} | grep -w 'total.num.prefetch' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_RECURSIVEREPLIES=$(cat ${FILE} | grep -w 'total.num.recursivereplies' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_REQ_MAX=$(cat ${FILE} | grep -w 'total.requestlist.max' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_AVG=$(cat ${FILE} | grep -w 'total.requestlist.avg' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_OVERWRITTEN=$(cat ${FILE} | grep -w 'total.requestlist.overwritten' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_EXCEEDED=$(cat ${FILE} | grep -w 'total.requestlist.exceeded' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_ALL=$(cat ${FILE} | grep -w 'total.requestlist.current.all' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_USER=$(cat ${FILE} | grep -w 'total.requestlist.current.user' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_TCPUSAGE=$(cat ${FILE} | grep -w 'total.tcpusage' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_QUERY_TYPE_A=$(cat ${FILE} | grep -w 'num.query.type.A' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NS=$(cat ${FILE} | grep -w 'num.query.type.NS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_MX=$(cat ${FILE} | grep -w 'num.query.type.MX' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TXT=$(cat ${FILE} | grep -w 'num.query.type.TXT' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_PTR=$(cat ${FILE} | grep -w 'num.query.type.PTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_AAAA=$(cat ${FILE} | grep -w 'num.query.type.AAAA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SRV=$(cat ${FILE} | grep -w 'num.query.type.SRV' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SOA=$(cat ${FILE} | grep -w 'num.query.type.SOA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HTTPS=$(cat ${FILE} | grep -w 'num.query.type.HTTPS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TYPE0=$(cat ${FILE} | grep -w 'num.query.type.TYPE0' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_CNAME=$(cat ${FILE} | grep -w 'num.query.type.CNAME' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_WKS=$(cat ${FILE} | grep -w 'num.query.type.WKS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HINFO=$(cat ${FILE} | grep -w 'num.query.type.HINFO' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_X25=$(cat ${FILE} | grep -w 'num.query.type.X25' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NAPTR=$(cat ${FILE} | grep -w 'num.query.type.NAPTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DS=$(cat ${FILE} | grep -w 'num.query.type.DS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DNSKEY=$(cat ${FILE} | grep -w 'num.query.type.DNSKEY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TLSA=$(cat ${FILE} | grep -w 'num.query.type.TLSA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SVCB=$(cat ${FILE} | grep -w 'num.query.type.SVCB' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SPF=$(cat ${FILE} | grep -w 'num.query.type.SPF' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_ANY=$(cat ${FILE} | grep -w 'num.query.type.ANY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_OTHER=$(cat ${FILE} | grep -w 'num.query.type.other' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_ANSWER_RCODE_NOERROR=$(cat ${FILE} | grep -w 'num.answer.rcode.NOERROR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_NXDOMAIN=$(cat ${FILE} | grep -w 'num.answer.rcode.NXDOMAIN' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_SERVFAIL=$(cat ${FILE} | grep -w 'num.answer.rcode.SERVFAIL' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_REFUSED=$(cat ${FILE} | grep -w 'num.answer.rcode.REFUSED' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_nodata=$(cat ${FILE} | grep -w 'num.answer.rcode.nodata' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_secure=$(cat ${FILE} | grep -w 'num.answer.secure' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 #       Sending info to zabbix_server.&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.queries -o $(( ${TOTAL_NUM_QUERIES:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachehits -o $(( ${TOTAL_NUM_CACHEHITS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachemiss -o $(( ${TOTAL_NUM_CACHEMISS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.prefetch -o $(( ${TOTAL_NUM_PREFETCH:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.recursivereplies -o $(( ${TOTAL_NUM_RECURSIVEREPLIES:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.max -o $(( ${TOTAL_REQ_MAX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.avg -o $(( ${TOTAL_REQ_AVG:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.overwritten -o $(( ${TOTAL_REQ_OVERWRITTEN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.exceeded -o $(( ${TOTAL_REQ_EXCEEDED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.all -o $(( ${TOTAL_REQ_CURRENT_ALL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.user -o $(( ${TOTAL_REQ_CURRENT_USER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.tcpusage -o $(( ${TOTAL_TCPUSAGE:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.a -o $(( ${NUM_QUERY_TYPE_A:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ns -o $(( ${NUM_QUERY_TYPE_NS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.mx -o $(( ${NUM_QUERY_TYPE_MX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.txt -o $(( ${NUM_QUERY_TYPE_TXT:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ptr -o $(( ${NUM_QUERY_TYPE_PTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.aaaa -o $(( ${NUM_QUERY_TYPE_AAAA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.srv -o $(( ${NUM_QUERY_TYPE_SRV:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.soa -o $(( ${NUM_QUERY_TYPE_SOA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.https -o $(( ${NUM_QUERY_TYPE_HTTPS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.type0 -o $(( ${NUM_QUERY_TYPE_TYPE0:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.cname -o $(( ${NUM_QUERY_TYPE_CNAME:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.wks -o $(( ${NUM_QUERY_TYPE_WKS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.hinfo -o $(( ${NUM_QUERY_TYPE_HINFO:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.X25 -o $(( ${NUM_QUERY_TYPE_X25:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.naptr -o $(( ${NUM_QUERY_TYPE_NAPTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ds -o $(( ${NUM_QUERY_TYPE_DS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.dnskey -o $(( ${NUM_QUERY_TYPE_DNSKEY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.tlsa -o $(( ${NUM_QUERY_TYPE_TLSA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.svcb -o $(( ${NUM_QUERY_TYPE_SVCB:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.spf -o $(( ${NUM_QUERY_TYPE_SPF:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.any -o $(( ${NUM_QUERY_TYPE_ANY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.other -o $(( ${NUM_QUERY_TYPE_OTHER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NOERROR -o $(( ${NUM_ANSWER_RCODE_NOERROR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NXDOMAIN -o $(( ${NUM_ANSWER_RCODE_NXDOMAIN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.SERVFAIL -o $(( ${NUM_ANSWER_RCODE_SERVFAIL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.REFUSED -o $(( ${NUM_ANSWER_RCODE_REFUSED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.nodata -o $(( ${NUM_ANSWER_RCODE_nodata:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.secure -o $(( ${NUM_ANSWER_secure:-0} / 300 ))&lt;br /&gt;
No Zabbix será registrado dados como esses abaixo e posteriormente pode ser montado um Grafana com eles:&lt;br /&gt;
[[Arquivo:Zabbix dns01.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns02.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns03.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns04.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Mantendo a hora certa ==&lt;br /&gt;
Vamos instalar agora o Chrony para manter a data e hora certas no sistema:&lt;br /&gt;
 # apt install chrony&lt;br /&gt;
Após a instalação do Chrony edite o arquivo /etc/chrony/chrony.conf, comente e a linha abaixo e adicione seus servidores NTP. Caso não tenha servidores NTP, estou colocando os do NIC.br aqui.&lt;br /&gt;
 #pool 2.debian.pool.ntp.org iburst&lt;br /&gt;
 server a.st1.ntp.br iburst nts&lt;br /&gt;
 server b.st1.ntp.br iburst nts&lt;br /&gt;
 server c.st1.ntp.br iburst nts&lt;br /&gt;
 server d.st1.ntp.br iburst nts&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart chronyd.service&lt;br /&gt;
Cheque com o '''chronyc''' se os servidores estão OK:&lt;br /&gt;
 # chronyc sourcestats&lt;br /&gt;
 Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev&lt;br /&gt;
 ==============================================================================&lt;br /&gt;
 a.st1.ntp.br               10   5  155m     -0.027      0.030    -71us    51us&lt;br /&gt;
 b.st1.ntp.br               11   7  344m     +0.068      0.079    +23ms   382us&lt;br /&gt;
 c.st1.ntp.br                6   3  344m     +0.026      0.037   -124us    92us&lt;br /&gt;
 200.20.186.76               9   3  138m     -0.022      0.031   +172us    42us&lt;br /&gt;
&lt;br /&gt;
 # chronyc sources&lt;br /&gt;
 MS Name/IP address         Stratum Poll Reach LastRx Last sample&lt;br /&gt;
 ===============================================================================&lt;br /&gt;
 ^* a.st1.ntp.br                  1  10   377   588   +487us[ +397us] +/-   12ms&lt;br /&gt;
 ^- b.st1.ntp.br                  2  10   377   830    +23ms[  +23ms] +/-   49ms&lt;br /&gt;
 ^+ c.st1.ntp.br                  2  10    21  1038   -147us[ -242us] +/-   17ms&lt;br /&gt;
 ^+ 200.20.186.76                 1  10   377  1032   +381us[ +285us] +/-   15ms&lt;br /&gt;
&lt;br /&gt;
== Configurando o FRRouting ==&lt;br /&gt;
Nesse ponto iremos configurar o '''FRRouting''' para enviar os IPs das '''loopbacks''' e o '''/30''' para o nosso PE do diagrama. Em '''/etc/frr/daemons''' habilite o parâmetro conforme abaixo:&lt;br /&gt;
 ospfd=yes&lt;br /&gt;
 ospf6d=yes&lt;br /&gt;
Edite o arquivo '''/etc/frr/frr.conf''' e deixe com o conteúdo abaixo, para ficar conforme nosso diagrama do projeto. Apenas troque '''&amp;lt;SENHA&amp;gt;''' por uma senha para fechar o OSPF com mais segurança. Essa senha deve ser usada dos dois lados.&lt;br /&gt;
 frr version 10.3&lt;br /&gt;
 frr defaults traditional&lt;br /&gt;
 hostname dns-recursivo-01&lt;br /&gt;
 log syslog informational&lt;br /&gt;
 no ip forwarding&lt;br /&gt;
 no ipv6 forwarding&lt;br /&gt;
 service integrated-vtysh-config&lt;br /&gt;
 !&lt;br /&gt;
 interface ens18&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf message-digest-key 5 md5 &amp;lt;SENHA&amp;gt;&lt;br /&gt;
  ip ospf network point-to-point&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 network point-to-point&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 interface lo&lt;br /&gt;
  description LOOPBACKS&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf passive&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 passive&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf&lt;br /&gt;
  ospf router-id 172.16.0.6&lt;br /&gt;
  area 0.0.0.0 authentication message-digest&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf6&lt;br /&gt;
  ospf6 router-id 172.16.0.6&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart frr.service&lt;br /&gt;
Cheque se está tudo OK com o OSPF e verifique no PE se está recebendo os prefixos anunciados.&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL&lt;br /&gt;
 172.16.0.5     1 Full/-          10m49s            35.310s 172.16.0.5   ens18:172.16.0.6                  0     0     0&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri    DeadTime    State/IfState         Duration I/F[State]&lt;br /&gt;
 172.16.0.5       1    00:00:30     Full/PointToPoint 25d22:53:47 ens18[PointToPoint]&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor detail'&lt;br /&gt;
 &lt;br /&gt;
  Neighbor 172.16.0.5, interface address 172.16.0.5&lt;br /&gt;
     In the area 0.0.0.0 via interface ens18&lt;br /&gt;
     Neighbor priority is 1, State is Full/-, 5 state changes&lt;br /&gt;
     Most recent state change statistics:&lt;br /&gt;
       Progressive change 21w3d15h ago&lt;br /&gt;
     DR is 0.0.0.0, BDR is 0.0.0.0&lt;br /&gt;
     Options 18 *|-|-|EA|-|-|E|-&lt;br /&gt;
     Dead timer due in 34.685s&lt;br /&gt;
     Database Summary List 0&lt;br /&gt;
     Link State Request List 0&lt;br /&gt;
     Link State Retransmission List 0&lt;br /&gt;
     Thread Inactivity Timer on&lt;br /&gt;
     Thread Database Description Retransmision off&lt;br /&gt;
     Thread Link State Request Retransmission on&lt;br /&gt;
     Thread Link State Update Retransmission on&lt;br /&gt;
 &lt;br /&gt;
     Graceful restart Helper info:&lt;br /&gt;
       Graceful Restart HELPER Status : None&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor detail'&lt;br /&gt;
  Neighbor 172.16.0.5%ens18&lt;br /&gt;
     Area 0.0.0.0 via interface ens18 (ifindex 4)&lt;br /&gt;
     His IfIndex: 60 Link-local address: fe80::469b:c1ff:fed6:43ee&lt;br /&gt;
     State Full for a duration of 25d22:57:14&lt;br /&gt;
     His choice of DR/BDR 0.0.0.0/0.0.0.0, Priority 1&lt;br /&gt;
     DbDesc status: Master SeqNum: 0xb94b0000&lt;br /&gt;
     Summary-List: 0 LSAs&lt;br /&gt;
     Request-List: 0 LSAs&lt;br /&gt;
     Retrans-List: 0 LSAs&lt;br /&gt;
     0 Pending LSAs for DbDesc in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSReq in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSAck in Time 00:00:00 [thread off]&lt;br /&gt;
     Authentication header not present&lt;br /&gt;
&lt;br /&gt;
== Configurando o Unbound ==&lt;br /&gt;
Abaixo a configuração que usaremos nos servidores atentando para o detalhe do '''num-threads''', esse deve ter o valor igual ao número de CPUs do servidor.&lt;br /&gt;
&lt;br /&gt;
Também os IPs utilizados em '''outgoing-interface''' que serão diferentes em cada servidor, esses serão os IPs usados para '''recursividade'''. Consulte o manual do Unbound para obter mais informações sobre cada parâmetro listado na configuração.&lt;br /&gt;
&lt;br /&gt;
O tuning no Unbound pode ser alterado conforme abaixo:&lt;br /&gt;
 num-threads = nº CPUs&lt;br /&gt;
 so-reuseport = yes&lt;br /&gt;
 *-slabs = potência de 2 próximo ao num-threads&lt;br /&gt;
 msg-cache-size = 1g (quantidade de memória pra usar de cache)&lt;br /&gt;
 rrset-cache-size = 2 * msg-cache-size&lt;br /&gt;
 outgoing-range = 8192&lt;br /&gt;
 num-queries-per-thread = 4096&lt;br /&gt;
 so-rcvbuf e so-sndbuf = 4m ou 8m para servidores com muita requisição&lt;br /&gt;
Agora vamos criar nosso arquivo de configuração base em '''/etc/unbound/unbound.conf.d/local.conf''':&lt;br /&gt;
 server:&lt;br /&gt;
         verbosity: 1&lt;br /&gt;
         statistics-interval: 0&lt;br /&gt;
         statistics-cumulative: no&lt;br /&gt;
         extended-statistics: yes&lt;br /&gt;
         num-threads: 8&lt;br /&gt;
         serve-expired: yes&lt;br /&gt;
         interface: 127.0.0.1&lt;br /&gt;
         interface: 10.10.10.10&lt;br /&gt;
         interface: 10.10.9.9&lt;br /&gt;
         interface: 172.16.0.6&lt;br /&gt;
         interface: fd00::10:10:10:10&lt;br /&gt;
         interface: fd00::10:10:9:9&lt;br /&gt;
         interface: ::1&lt;br /&gt;
         interface-automatic: no&lt;br /&gt;
         outgoing-interface: 198.18.1.10&lt;br /&gt;
         outgoing-interface: 2001:db8::faca:198:18:1:10&lt;br /&gt;
         outgoing-range: 8192&lt;br /&gt;
         outgoing-num-tcp: 1024&lt;br /&gt;
         incoming-num-tcp: 2048&lt;br /&gt;
         so-rcvbuf: 4m&lt;br /&gt;
         so-sndbuf: 4m&lt;br /&gt;
         so-reuseport: yes&lt;br /&gt;
         edns-buffer-size: 1232&lt;br /&gt;
         msg-cache-size: 512m&lt;br /&gt;
         msg-cache-slabs: 4&lt;br /&gt;
         num-queries-per-thread: 4096&lt;br /&gt;
         rrset-cache-size: 1g&lt;br /&gt;
         rrset-cache-slabs: 4&lt;br /&gt;
         infra-cache-slabs: 4&lt;br /&gt;
         do-ip4: yes&lt;br /&gt;
         do-ip6: yes&lt;br /&gt;
         do-udp: yes&lt;br /&gt;
         do-tcp: yes&lt;br /&gt;
         chroot: &amp;quot;&amp;quot;&lt;br /&gt;
         username: &amp;quot;unbound&amp;quot;&lt;br /&gt;
         directory: &amp;quot;/etc/unbound&amp;quot;&lt;br /&gt;
         logfile: &amp;quot;/var/log/unbound/unbound.log&amp;quot;&lt;br /&gt;
         use-syslog: no&lt;br /&gt;
         log-time-ascii: yes&lt;br /&gt;
         log-queries: no&lt;br /&gt;
         pidfile: &amp;quot;/var/run/unbound.pid&amp;quot;&lt;br /&gt;
         root-hints: &amp;quot;/usr/share/dns/root.hints&amp;quot;&lt;br /&gt;
         hide-identity: yes&lt;br /&gt;
         hide-version: yes&lt;br /&gt;
         unwanted-reply-threshold: 10000000&lt;br /&gt;
         prefetch: yes&lt;br /&gt;
         prefetch-key: yes&lt;br /&gt;
         rrset-roundrobin: yes&lt;br /&gt;
         minimal-responses: yes&lt;br /&gt;
         module-config: &amp;quot;respip validator iterator&amp;quot;&lt;br /&gt;
         val-clean-additional: yes&lt;br /&gt;
         val-log-level: 1&lt;br /&gt;
         key-cache-slabs: 4&lt;br /&gt;
         deny-any: yes&lt;br /&gt;
         cache-min-ttl: 60&lt;br /&gt;
         key-cache-size: 128m&lt;br /&gt;
         neg-cache-size: 64m&lt;br /&gt;
         cache-max-ttl: 86400&lt;br /&gt;
         infra-cache-numhosts: 100000&lt;br /&gt;
         access-control: 198.18.0.0/22 allow&lt;br /&gt;
         access-control: 2001:db8::/32 allow&lt;br /&gt;
  &lt;br /&gt;
 rpz:&lt;br /&gt;
   name: rpz.block.host.local.zone&lt;br /&gt;
   zonefile: /etc/unbound/rpz.block.hosts.zone&lt;br /&gt;
   rpz-action-override: nxdomain&lt;br /&gt;
  &lt;br /&gt;
 python:&lt;br /&gt;
  &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;.&amp;quot;&lt;br /&gt;
     master: &amp;quot;b.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;c.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;d.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;f.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;g.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;k.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/root.zone&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;arpa.&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/arpa.zone&amp;quot;&lt;br /&gt;
No parâmetro '''interface''' colocamos os IPs que serão usados para consulta dos clientes como o '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9'''. Ali repare que coloquei também o IP privado '''172.16.0.6''', isso porque cada servidor terá o seu IP privado e este deve ser usado pelo seu sistema de monitoramento para checar cada servidor. No '''outgoing-interface''' teremos os IPs, tanto '''IPv4''' quanto '''IPv6''', para que seja feita a recursividade na Internet utilizando eles. Não tem '''IPv6''' ainda na sua rede? Dê uma olhada nesse artigo. Outro parâmetro importante é o '''access-control''' e é através dele que liberamos os prefixos IP para consultarem no nosso DNS Recursivo. No exemplo estou liberando todo o prefixo '''198.18.0.0/22''' e o prefixo '''2001:db8::/32'''. Além da ACL no Unbound, recomendo que crie um filtro de pacotes com iptables ou nftables protegendo seu sistema e liberando as portas '''53/UDP''', '''53/TCP,'''  '''443/TCP e 853/TCP''' apenas para seus clientes. Falarei sobre a '''443/TCP e 853/TCP''' mais para frente nessa mesma documentação.&lt;br /&gt;
&lt;br /&gt;
Agora criaremos o arquivo '''RPZ''' ('''Response Policy Zones'''). Esse arquivo contém os sites que serão bloqueados via '''&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; Recursivo'''. São aqueles sites que às vezes você recebe um Ofício da Justiça solicitando o bloqueio deles. Não entrarei no mérito da efetividade desses bloqueios, porque muitos de vocês sabem que tecnicamente, existem formas de se fazer um bypass através desses bloqueios. Contudo vamos deixar nosso ambiente preparado para esses bloqueios e por isso crie o arquivo '''/etc/unbound/rpz.block.hosts.zone''' com esse conteúdo de exemplo:&lt;br /&gt;
 $TTL 2h&lt;br /&gt;
 @ IN SOA localhost. root.localhost. (2 6h 1h 1w 2h)&lt;br /&gt;
   IN NS  localhost.&lt;br /&gt;
 ; RPZ manual block hosts&lt;br /&gt;
 *.josedascoves.com CNAME .&lt;br /&gt;
 josedascoves.com CNAME .&lt;br /&gt;
No exemplo acima estamos bloqueando qualquer consulta de DNS para '''josedascoves.com''' ou qualquer coisa '''.josedascoves.com'''.&lt;br /&gt;
&lt;br /&gt;
Para testar podemos fazer assim do próprio servidor:&lt;br /&gt;
 # host josedascoves.com ::1&lt;br /&gt;
 Using domain server:&lt;br /&gt;
 Name: ::1&lt;br /&gt;
 Address: ::1#53&lt;br /&gt;
 Aliases:&lt;br /&gt;
 &lt;br /&gt;
 Host josedascoves.com not found: 3(NXDOMAIN)&lt;br /&gt;
Se a resposta for '''NXDOMAIN''' então está funcionando o bloqueio. Para incluir novos bloqueios basta adicionar os domínios, um abaixo do outro, conforme o exemplo que coloquei no arquivo RPZ.&lt;br /&gt;
&lt;br /&gt;
== Acertando o resolv.conf ==&lt;br /&gt;
Vamos modificar nosso /etc/resolv.conf para utilizar DNS externo. Sim você deve estar se perguntando em qual situação isso seria utilizado. Primeiro entenda que o Unbound não irá utilizar o DNS externo para fazer as consultas na Internet e sim, qualquer teste que você faça do servidor precisará apontar para o Unbound usando os IPs '''127.0.0.1''' ou '''::1'''. Faremos isso pela seguinte situação: imagine que o daemon unbound morreu mas você ainda continua com conectividade na Internet. Você conseguiria acessar qualquer local na Internet através do IP mas não através do hostname porque não conseguiria resolver nomes, seu unbound estaria fora do ar. Imagine ainda que você gostaria que seu servidor te avisasse do problema via Telegram ou e-mail. Por isso estamos utilizando um DNS externo no '''/etc/resolv.conf''', apenas para essas situações. Se você não quiser utilizar desse recurso, pode usar o '''127.0.0.1''' e '''::1''' no lugar.&lt;br /&gt;
 nameserver 8.8.8.8&lt;br /&gt;
 nameserver 8.8.4.4&lt;br /&gt;
 nameserver 2001:4860:4860::8888&lt;br /&gt;
&lt;br /&gt;
== Script de teste de recursividade ==&lt;br /&gt;
Estamos montando uma '''Rede de DNS Recursivo Anycast''', então é muito importante que você monitore essa rede para saber se algum node morreu e iniciar o troubleshooting, resolver o problema e levantar o sistema novamente. Tudo isso é importante mas o cliente não deve ficar esperando até você resolver o problema, seu sistema precisa ser inteligente o suficiente para se remover da Rede quando tiver um problema e se inserir novamente, quando o problema estiver sido solucionado. Se você montar uma Rede de DNS e um dos nodes apresentar algum problema, todos os clientes atendidos por aquele node migrarão automaticamente e transparentemente para outro '''DNS Recursivo Anycast''' mais próximo. Isso se chama '''disponibilidade'''.&lt;br /&gt;
&lt;br /&gt;
O script '''/root/scripts/checa_dns.sh''' abaixo tem a função de fazer os testes de recursividade e checar se o daemon do unbound continua rodando. Se algo acontecer, ele para o anúncio do '''10.10.10.10''' e '''10.10.9.9''' e retorna eles quando tudo estiver resolvido.&lt;br /&gt;
 # mkdir /root/scripts&lt;br /&gt;
&lt;br /&gt;
 #!/usr/bin/env bash&lt;br /&gt;
 #Script para teste de DNS v2.1&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 #Informe um domínio por linha:&lt;br /&gt;
 dominios_testar=(&lt;br /&gt;
 www.google.com&lt;br /&gt;
 www.terra.com.br&lt;br /&gt;
 www.uol.com.br&lt;br /&gt;
 www.globo.com&lt;br /&gt;
 www.facebook.com&lt;br /&gt;
 www.youtube.com&lt;br /&gt;
 www.twitch.com&lt;br /&gt;
 www.discord.com&lt;br /&gt;
 www.debian.org&lt;br /&gt;
 www.redhat.com&lt;br /&gt;
 )&lt;br /&gt;
 corte_taxa_falha=100 #Porcentagem de falha para executar uma ação&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 remove_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; != &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no description' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME morreu!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 adiciona_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; == &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'description LOOPBACKS' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME retornou do inferno!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
 if [ $? -ne 0 ]; then&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME morreu DNS mas tentando levantar!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    systemctl restart unbound&lt;br /&gt;
    systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
    if [ $? -ne 0 ]; then&lt;br /&gt;
       remove_ospf&lt;br /&gt;
       exit&lt;br /&gt;
    fi&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME servico DNS voltou mas tinha morrido!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 qt_falhas=0&lt;br /&gt;
 qt_total=&amp;quot;${#dominios_testar[@]}&amp;quot;&lt;br /&gt;
 echo &amp;quot;total_dominios: $qt_total&amp;quot;&lt;br /&gt;
 for site in &amp;quot;${dominios_testar[@]}&amp;quot;&lt;br /&gt;
 do&lt;br /&gt;
   unbound-control flush $site &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   resolver=&amp;quot;127.0.0.1&amp;quot;&lt;br /&gt;
   echo -e &amp;quot; - dominio $site - $resolver - \c&amp;quot;&lt;br /&gt;
   host $site $resolver &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   if [ $? -ne 0 ]; then&lt;br /&gt;
      ((qt_falhas++))&lt;br /&gt;
      echo -e &amp;quot;[Falhou]&amp;quot;&lt;br /&gt;
   else&lt;br /&gt;
      echo -e &amp;quot;[OK]&amp;quot;&lt;br /&gt;
   fi&lt;br /&gt;
 done&lt;br /&gt;
  &lt;br /&gt;
 taxa_falha=$((qt_falhas*100/qt_total))&lt;br /&gt;
 echo &amp;quot;Falhas $qt_falhas/$qt_total ($taxa_falha%)&amp;quot;&lt;br /&gt;
  &lt;br /&gt;
 if [ &amp;quot;$taxa_falha&amp;quot; -ge &amp;quot;$corte_taxa_falha&amp;quot; ]; then&lt;br /&gt;
    remove_ospf&lt;br /&gt;
    exit&lt;br /&gt;
 fi&lt;br /&gt;
 adiciona_ospf&lt;br /&gt;
Se rodarmos o script manualmente veremos isto:&lt;br /&gt;
 # /root/scripts/checa_dns.sh&lt;br /&gt;
 total_dominios: 10&lt;br /&gt;
  - dominio www.google.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.terra.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.uol.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.globo.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.facebook.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.youtube.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.twitch.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.discord.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.debian.org - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.redhat.com - 127.0.0.1 - [OK]&lt;br /&gt;
 Falhas 0/10 (0%)&lt;br /&gt;
Se acontecer 100% de falhas o script irá remover os anúncios do OSPF. Se o daemon do unbound morrer, ele tentará reiniciá-lo. Se tudo normalizar o script irá retornar os anúncios para o OSPF. Deixei comentado no script as partes que enviariam uma notificação para o Telegram. Existem diversas documentações sobre isso na Internet, eu mesmo tenho uma. Assim que eu publicar aqui, atualizo essa documentação e sinta-se à vontade de modificar como desejar.&lt;br /&gt;
 # chmod 700 /root/scripts/checa_dns.sh&lt;br /&gt;
Adicione a linha abaixo em seu '''/etc/crontab''':&lt;br /&gt;
 */1 *   * * *   root    /root/scripts/checa_dns.sh&lt;br /&gt;
&lt;br /&gt;
== Habilitando o DoH (&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; over HTTPS) - opcional ==&lt;br /&gt;
Para habilitar o '''DoH''' no Unbound é bem simples. O recurso do '''DoH''' vem para trazer mais segurança e privacidade para o usuário. É um recurso muito pouco utilizado ainda mas que seu cliente pode vir a pedir algum dia.&lt;br /&gt;
&lt;br /&gt;
Você precisará gerar certificados SSL legítimos e para isso você poderá usar o '''Let's Encrypt''' só que de uma forma não tão convencional.&lt;br /&gt;
&lt;br /&gt;
Na sequência vamos instalar o Let's Encrypt para gerarmos nosso certificado SSL:&lt;br /&gt;
 # apt install letsencrypt&lt;br /&gt;
Escolha um '''hostname''' para ser usado no nosso '''DoH''' e aponte ele no seu DNS Autoritativo para seus IPs 10.10.10.10 e 10.10.9.9. Aqui vamos usar o seguinte como exemplo: '''doh.brasilpeeringforum.org'''. Para gerarmos nosso certificado iremos usar o tipo '''DNS-01''', ele não necessita que tenhamos um servidor web rodando no servidor e nem tão pouco levanta um serviço na porta 80 para checar o hostname. Ele utiliza o DNS como validador e vai te solicitar que crie um registro '''CNAME''' no seu '''DNS Autoritativo''' para provar que você tem o controle sobre aquele hostname. Antes disso vamos instalar um programa em Python para podermos automatizar nossa renovação de certificado no futuro. Esse programa se encontra '''[https://github.com/joohoi/acme-dns-certbot-joohoi/raw/master/acme-dns-auth.py aqui]''' mas vou deixá-lo abaixo já modificado o interpretador.&lt;br /&gt;
&lt;br /&gt;
Crie o arquivo '''/etc/letsencrypt/acme-dns-auth.py''' com o conteúdo abaixo:&lt;br /&gt;
 #!/usr/bin/env python3&lt;br /&gt;
 import json&lt;br /&gt;
 import os&lt;br /&gt;
 import requests&lt;br /&gt;
 import sys&lt;br /&gt;
 &lt;br /&gt;
 ### EDIT THESE: Configuration values ###&lt;br /&gt;
 &lt;br /&gt;
 # URL to acme-dns instance&lt;br /&gt;
 ACMEDNS_URL = &amp;quot;&amp;lt;nowiki&amp;gt;https://auth.acme-dns.io&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
 # Path for acme-dns credential storage&lt;br /&gt;
 STORAGE_PATH = &amp;quot;/etc/letsencrypt/acmedns.json&amp;quot;&lt;br /&gt;
 # Whitelist for address ranges to allow the updates from&lt;br /&gt;
 # Example: ALLOW_FROM = [&amp;quot;192.168.10.0/24&amp;quot;, &amp;quot;::1/128&amp;quot;]&lt;br /&gt;
 ALLOW_FROM = []&lt;br /&gt;
 # Force re-registration. Overwrites the already existing acme-dns accounts.&lt;br /&gt;
 FORCE_REGISTER = False&lt;br /&gt;
 &lt;br /&gt;
 ###   DO NOT EDIT BELOW THIS POINT   ###&lt;br /&gt;
 ###         HERE BE DRAGONS          ###&lt;br /&gt;
 &lt;br /&gt;
 DOMAIN = os.environ[&amp;quot;CERTBOT_DOMAIN&amp;quot;]&lt;br /&gt;
 if DOMAIN.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
     DOMAIN = DOMAIN[2:]&lt;br /&gt;
 VALIDATION_DOMAIN = &amp;quot;_acme-challenge.&amp;quot;+DOMAIN&lt;br /&gt;
 VALIDATION_TOKEN = os.environ[&amp;quot;CERTBOT_VALIDATION&amp;quot;]&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 class AcmeDnsClient(object):&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
     Handles the communication with ACME-DNS API&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
     def __init__(self, acmedns_url):&lt;br /&gt;
         self.acmedns_url = acmedns_url&lt;br /&gt;
 &lt;br /&gt;
     def register_account(self, allowfrom):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Registers a new ACME-DNS account&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
         if allowfrom:&lt;br /&gt;
             # Include whitelisted networks to the registration call&lt;br /&gt;
             reg_data = {&amp;quot;allowfrom&amp;quot;: allowfrom}&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;,&lt;br /&gt;
                                 data=json.dumps(reg_data))&lt;br /&gt;
         else:&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;)&lt;br /&gt;
         if res.status_code == 201:&lt;br /&gt;
             # The request was successful&lt;br /&gt;
             return res.json()&lt;br /&gt;
         else:&lt;br /&gt;
             # Encountered an error&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to register a new acme-dns &amp;quot;&lt;br /&gt;
                    &amp;quot;account. HTTP status {}, Response body: {}&amp;quot;)&lt;br /&gt;
             print(msg.format(res.status_code, res.text))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def update_txt_record(self, account, txt):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Updates the TXT challenge record to ACME-DNS subdomain.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         update = {&amp;quot;subdomain&amp;quot;: account['subdomain'], &amp;quot;txt&amp;quot;: txt}&lt;br /&gt;
         headers = {&amp;quot;X-Api-User&amp;quot;: account['username'],&lt;br /&gt;
                    &amp;quot;X-Api-Key&amp;quot;: account['password'],&lt;br /&gt;
                    &amp;quot;Content-Type&amp;quot;: &amp;quot;application/json&amp;quot;}&lt;br /&gt;
         res = requests.post(self.acmedns_url+&amp;quot;/update&amp;quot;,&lt;br /&gt;
                             headers=headers,&lt;br /&gt;
                             data=json.dumps(update))&lt;br /&gt;
         if res.status_code == 200:&lt;br /&gt;
             # Successful update&lt;br /&gt;
             return&lt;br /&gt;
         else:&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to update TXT record in &amp;quot;&lt;br /&gt;
                    &amp;quot;acme-dns. \n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request headers:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request body:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response HTTP status: {}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response body: {}&amp;quot;)&lt;br /&gt;
             s_headers = json.dumps(headers, indent=2, sort_keys=True)&lt;br /&gt;
             s_update = json.dumps(update, indent=2, sort_keys=True)&lt;br /&gt;
             s_body = json.dumps(res.json(), indent=2, sort_keys=True)&lt;br /&gt;
             print(msg.format(s_headers, s_update, res.status_code, s_body))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
 class Storage(object):&lt;br /&gt;
     def __init__(self, storagepath):&lt;br /&gt;
         self.storagepath = storagepath&lt;br /&gt;
         self._data = self.load()&lt;br /&gt;
 &lt;br /&gt;
     def load(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Reads the storage content from the disk to a dict structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         data = dict()&lt;br /&gt;
         filedata = &amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             with open(self.storagepath, 'r') as fh:&lt;br /&gt;
                 filedata = fh.read()&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             if os.path.isfile(self.storagepath):&lt;br /&gt;
                 # Only error out if file exists, but cannot be read&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage file exists but cannot be read&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         try:&lt;br /&gt;
             data = json.loads(filedata)&lt;br /&gt;
         except ValueError:&lt;br /&gt;
             if len(filedata) &amp;gt; 0:&lt;br /&gt;
                 # Storage file is corrupted&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage JSON is corrupted&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         return data&lt;br /&gt;
 &lt;br /&gt;
     def save(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Saves the storage content to disk&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         serialized = json.dumps(self._data)&lt;br /&gt;
         try:&lt;br /&gt;
             with os.fdopen(os.open(self.storagepath,&lt;br /&gt;
                                    os.O_WRONLY | os.O_CREAT, 0o600), 'w') as fh:&lt;br /&gt;
                 fh.truncate()&lt;br /&gt;
                 fh.write(serialized)&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             print(&amp;quot;ERROR: Could not write storage file.&amp;quot;)&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def put(self, key, value):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Puts the configuration value to storage and sanitize it&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         # If wildcard domain, remove the wildcard part as this will use the&lt;br /&gt;
         # same validation record name as the base domain&lt;br /&gt;
         if key.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
             key = key[2:]&lt;br /&gt;
         self._data[key] = value&lt;br /&gt;
 &lt;br /&gt;
     def fetch(self, key):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Gets configuration value from storage&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             return self._data[key]&lt;br /&gt;
         except KeyError:&lt;br /&gt;
             return None&lt;br /&gt;
 &lt;br /&gt;
 if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
     # Init&lt;br /&gt;
     client = AcmeDnsClient(ACMEDNS_URL)&lt;br /&gt;
     storage = Storage(STORAGE_PATH)&lt;br /&gt;
 &lt;br /&gt;
     # Check if an account already exists in storage&lt;br /&gt;
     account = storage.fetch(DOMAIN)&lt;br /&gt;
     if FORCE_REGISTER or not account:&lt;br /&gt;
         # Create and save the new account&lt;br /&gt;
         account = client.register_account(ALLOW_FROM)&lt;br /&gt;
         storage.put(DOMAIN, account)&lt;br /&gt;
         storage.save()&lt;br /&gt;
 &lt;br /&gt;
         # Display the notification for the user to update the main zone&lt;br /&gt;
         msg = &amp;quot;Please add the following CNAME record to your main DNS zone:\n{}&amp;quot;&lt;br /&gt;
         cname = &amp;quot;{} CNAME {}.&amp;quot;.format(VALIDATION_DOMAIN, account[&amp;quot;fulldomain&amp;quot;])&lt;br /&gt;
         print(msg.format(cname))&lt;br /&gt;
 &lt;br /&gt;
     # Update the TXT record in acme-dns instance&lt;br /&gt;
     client.update_txt_record(account, VALIDATION_TOKEN)&lt;br /&gt;
&lt;br /&gt;
 # chmod +x /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
Usaremos a seguinte instrução para criar nosso certificado:&lt;br /&gt;
 # certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d doh.brasilpeeringforum.org&lt;br /&gt;
 Saving debug log to /var/log/letsencrypt/letsencrypt.log&lt;br /&gt;
 Plugins selected: Authenticator manual, Installer None&lt;br /&gt;
 Cert is due for renewal, auto-renewing...&lt;br /&gt;
 Renewing an existing certificate for doh.brasilpeeringforum.org&lt;br /&gt;
 Performing the following challenges:&lt;br /&gt;
 dns-01 challenge for doh.brasilpeeringforum.org&lt;br /&gt;
 Running manual-auth-hook command: /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
 Output from manual-auth-hook command acme-dns-auth.py:&lt;br /&gt;
 Please add the following CNAME record to your main DNS zone:&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
 &lt;br /&gt;
 Waiting for verification...&lt;br /&gt;
 &lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Challenges loaded. Press continue to submit to CA. Pass &amp;quot;-v&amp;quot; for more info about&lt;br /&gt;
 challenges.&lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Press Enter to Continue&lt;br /&gt;
Nesse momento você cria o registro '''CNAME''' no seu DNS Autoritativo conforme ele solicitou: '''_acme-challenge.doh.brasilpeeringforum.org IN CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.''' e somente depois de criado e checado no DNS, você pressiona o '''Enter''' para continuar. Você pode checar dessa forma:&lt;br /&gt;
 # host -t cname _acme-challenge.doh.brasilpeeringforum.org&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org is an alias for b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
Para que nosso certificado seja automaticamente renovado colocaremos no '''/etc/crontab''' a seguinte linha abaixo:&lt;br /&gt;
 00 00   1 * *   root    /usr/bin/certbot -q renew --deploy-hook &amp;quot;/usr/sbin/unbound-control reload_keep_cache&amp;quot;&lt;br /&gt;
Acima temos a instrução para renovação automática do certificado. Repare que você vai precisar também copiar esse certificado para seus outros servidores, escolha um servidor para manter o certificado sempre atualizado e crie um script que faça a mesma cópia remotamente para os outros servidores. O '''scp''' e o '''rsync''' são seus aliados nisso.&lt;br /&gt;
&lt;br /&gt;
=== Configurando o Unbound ===&lt;br /&gt;
Em nosso '''/etc/unbound/unbound.conf.d/local.conf''', adicionaremos no bloco &amp;quot;'''server:'''&amp;quot; o seguinte:&lt;br /&gt;
 interface: 10.10.10.10@443 &lt;br /&gt;
 interface: 10.10.9.9@443&lt;br /&gt;
 interface: fd00::10:10:10:10@443&lt;br /&gt;
 interface: fd00::10:10:9:9@443&lt;br /&gt;
 tls-service-key: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/privkey.pem&amp;quot; &lt;br /&gt;
 tls-service-pem: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/fullchain.pem&amp;quot;&lt;br /&gt;
Para usar o recurso do '''DoH''' você precisará habilitar o recurso no seu navegador e informar a URL. Vou colocar o exemplo do '''Google Chrome''': Digite '''chrome://settings/security?search=dns''' no seu Chrome e ative '''Usar DNS seguro''', selecione '''Personalizado''' e adicione nossa URL:&lt;br /&gt;
[[Arquivo:Doh bpf2.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Finalizando ==&lt;br /&gt;
Aqui finalizamos nosso projeto para uma Rede de DNS(s) Recursivos Anycast com Hyperlocal. Esse projeto é escalável, seguro, resiliente e você entregará muito mais qualidade de Internet para o seu cliente. Pare de entregar o '''8.8.8.8''' para os seus clientes, você está contribuindo para uma Internet mais lenta, sem a qualidade que o seu cliente merece. Investi meu tempo, que é muito pouco, para deixar esse documento para a comunidade, para você melhorar o seu ISP, para dar um UP! nele, então vamos começar 2023 com o pé direito. O que acha?&lt;br /&gt;
&lt;br /&gt;
Como prova de conceito, uma imagem abaixo onde temos uma Rede em produção de DNS(s) Recursivos Anycast e apontando exatamente o momento em que houve alguma situação que fez com que as queries de DNS, convergissem de um node para outro, de forma transparente e automática para o cliente. Podemos notar também que ao ser resolvido o problema, o tráfego retornou para o seu node correto:&lt;br /&gt;
[[Arquivo:Convergencia.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== KINDNS (Stands for Knowledge-Sharing and Instantiating Norms for DNS and Naming Security) ==&lt;br /&gt;
Achou que havia terminado? Agora que você tem a capacidade de montar uma '''Rede de DNS Recursivo''' com todas essas features acima, com todas as ferramentas que foram comentadas, o que acha de certificar o que fez?&lt;br /&gt;
&lt;br /&gt;
Assim como o [https://www.manrs.org/ MANRS] veio para certificar nosso sistema de roteamento na Internet, agora temos o [https://kindns.org/ KINDNS] para certificar que nossos sistemas de DNS estão bem feitos e dentro dos padrões de segurança. Existem '''7 ações''' que podem ser certificadas para nossos DNS Recursivos e estão aqui em https://kindns.org/shared-private-resolvers/. Com essa nossa documentação, se bem aplicada, você pode se candidatar ao KINDNS e ter seu ASN listado aqui https://kindns.org/participants/&lt;br /&gt;
&lt;br /&gt;
Obter e manter o '''MANRS''' e '''KINDNS''' demonstra seu compromisso com as Boas Práticas, contribui para termos uma '''Internet''' mais segura e te abre portas para novos negócios que possam exigir essas conformidades.&lt;br /&gt;
&lt;br /&gt;
Autor: [[Usuário:Gondim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Infraestrutura]]&lt;br /&gt;
__FORCARTDC__&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=4004</id>
		<title>DNS Recursivo Anycast Hyperlocal</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=4004"/>
		<updated>2025-12-26T14:00:01Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
==Introdução==&lt;br /&gt;
Você sabe como funciona a Internet? Essa é uma pergunta que meu amigo '''Thiago Ayub''' sempre faz aos seus candidatos à vagas de emprego e não importa o quanto tenham de experiência em '''Engenharia de Redes''', todos sempre travam nesse momento. Todos estão sempre prontos e preparados para resolver os problemas mais cabeludos em '''BGP''', '''OSPF''', '''MPLS''', etc mas travam com essa simples pergunta. Para contextualizar e visualizarmos melhor vamos nos atentar à imagem abaixo e uma explicação simplificada de como funciona:&lt;br /&gt;
[[Arquivo:Dns hierarquia.png|esquerda|commoldura]]&lt;br /&gt;
Tudo começa com um usuário sentado confortavelmente e querendo acessar um conteúdo disponível na Internet. Ele digita em seu navegador preferido a URL: '''&amp;lt;nowiki&amp;gt;https://wiki.brasilpeeringforum.org&amp;lt;/nowiki&amp;gt;''',&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;1)&amp;lt;/big&amp;gt;''' &amp;lt;big&amp;gt;O&amp;lt;/big&amp;gt; &amp;lt;big&amp;gt;navegador irá requisitar do '''DNS Recursivo''' utilizado pelo usuário, o '''endereço IP''' que responde pelo nome '''wiki.'''&amp;lt;/big&amp;gt;'''brasilpeeringforum.org'''&amp;lt;big&amp;gt;. Isso porque todos os acessos se dão na Internet através do '''endereço''' '''IP''' e não através do '''nome'''. Imaginem se tivéssemos que decorar os endereços IPs de todos os sites e serviços que quiséssemos acessar na Internet?&amp;lt;/big&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;big&amp;gt;'''2)''' Nosso DNS Recursivo checa se a informação consta em seu cache.&amp;lt;/big&amp;gt; Se a informação existir ela é devolvida ao navegador do usuário e aí este consegue acessar o site.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Do contrário o DNS Recursivo pergunta ao '''Root Server''' quem é o '''TLD (Top Level Domain)''' responsável para atender a requisição. &lt;br /&gt;
&lt;br /&gt;
'''4)''' O '''Root Server''' informa ao DNS Recursivo o endereço do '''TLD responsável'''. No Brasil o '''TLD''' responsável pelo '''.br''' seria o '''Registro.br'''.&lt;br /&gt;
&lt;br /&gt;
'''5)''' O DNS Recursivo pergunta ao '''TLD''' sobre '''wiki.brasilpeeringforum.org''' e este responde com os endereços IP dos '''DNS Autoritativos''' responsáveis pelo domínio '''brasilpeeringforum.org.'''&lt;br /&gt;
&lt;br /&gt;
'''6)''' O DNS Recursivo pergunta aos '''DNS Autoritativos''' pelo '''wiki.brasilpeeringforum.org''' e este responde com o '''endereço IP'''.&lt;br /&gt;
&lt;br /&gt;
'''7)''' Por último o DNS Recursivo devolve a informação para o navegador do usuário.&lt;br /&gt;
&lt;br /&gt;
Como que se dá a comunicação entre os '''DNS(s) Recursivos, Root Servers, TLDs''' e '''Autoritativos'''? Como que o navegador do usuário, após receber o IP do site, consegue chegar no servidor que tem o conteúdo? Isso só é possível devido ao protocolo chamado '''BGP (Border Gateway Protocol)''', todos os caminhos que conhecemos como rotas de destino, são anunciadas por milhares de participantes na '''Internet''' conhecidos como '''AS (Autonomous System)''', esses participantes se interligam para disponibilizar conteúdos e acessos pelo mundo aos milhares de usuários. É uma imensa rede colaborativa formada por Empresas, Universidades, Governos e todos que queiram se interconectar. Percebam que sem o '''BGP''', que serve de caminho para chegarmos nos conteúdos e sem o '''DNS (Domain Name System)''' para traduzir o nome para o endereço IP, a '''Internet''' não funcionaria e por isso precisamos cuidar muito bem desses dois serviços.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Mas não acaba por aí. O '''DNS Recursivo''' tem um papel muito importante para o Provedor de Internet e que envolve segurança, qualidade de acesso à Internet e a disponibilidade do serviço entregue ao cliente. Quando bem configurado acelera as consultas dos acessos graças ao seu cache interno, mas para que isso seja percebido pelo assinante, é necessário que esteja o mais próximo possível do seu cliente.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Um erro que destrói a qualidade do nosso serviço ==&lt;br /&gt;
Um erro muito comum que muitas operadoras cometem é utilizar DNS Recursivo externo, como o '''8.8.8.8''', '''1.1.1.1''' e outros, para seus clientes. Quanto mais próximo dos seus clientes, mais qualidade de serviço estará entregando a eles. Conteúdos serão entregues mais rapidamente pois serão resolvidos e armazenados em caches locais e não consultados remotamente na Internet. Para falar mais sobre isso, te convido leitor desse documento, que assista essa palestra do '''Thiago Ayub''' no '''GTER 51/GTS 37''' (2022) '''8.888 MOTIVOS PARA NÃO USAR DNS RECURSIVO EXTERNO EM SEU AS''': https://www.youtube.com/watch?v=Rsvpu5uF2Io&lt;br /&gt;
&lt;br /&gt;
== Objetivo ==&lt;br /&gt;
O objetivo desta documentação não é te ensinar tudo sobre '''DNS''', '''BGP''', '''OSPF''' e nem tão pouco sobre GNU/Linux e sim te mostrar um exemplo de servidor DNS Recursivo implementado pensando em segurança, qualidade e resiliência. Usaremos em todas as nossas documentações o [https://www.debian.org/ Debian GNU/Linux], por ser uma distribuição que considero uma obra de arte criada por uma enorme comunidade séria, com vasta experiência de anos, qualidade no empacotamento dos programas, estável e com uma equipe de segurança excelente e ativa. Caso você leitor, utilize alguma outra distribuição GNU/Linux, todo conteúdo apresentado aqui pode ser aplicado em outras distros, desde que respeitando as particularidades de cada uma.&lt;br /&gt;
&lt;br /&gt;
Aqui construiremos um sistema do tipo '''Anycast''', ou seja, terás o serviço rodando em diversas localidades da sua Rede utilizando o mesmo endereçamento IP e que atenderá seu cliente mais próximo. Em caso de falhas, seus clientes automaticamente e de forma transparente continuarão consultando o DNS mais próximo deles. Para que ele funcione dessa forma você precisará ter uma '''Rede OSPF''' implementada no seu Provedor Internet ou algum outro protocolo como por exemplo o '''ISIS,''' mas esse documento não irá abordar o '''ISIS'''. Também utilizaremos o '''Hyperlocal''' como recurso adicional para gerar algumas proteções de segurança e velocidade na resposta relacionada aos servidores de DNS Raiz da Internet.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
Para exemplificar nosso servidor de DNS Recursivo, usaremos como base das explicações um diagrama demonstrando o uso do DNS Recursivo em uma Rede fictícia. Adotaremos IPs privados e reservados para demonstrar todo o ambiente do Provedor de Internet.&lt;br /&gt;
[[Arquivo:Recursivo99.png|esquerda|miniaturadaimagem|695x695px]]&lt;br /&gt;
Nesse diagrama podemos observar alguns detalhes técnicos como por exemplo: existem '''3 servidores de DNS Recursivo''' posicionados em locais diferentes, que poderiam estar em bairros diferentes e até em cidades diferentes. Em cada servidor teremos '''2 loopbacks''' com os IPs:&lt;br /&gt;
&lt;br /&gt;
'''10.10.10.10/32 - fd00::10:10:10:10/128'''&lt;br /&gt;
&lt;br /&gt;
'''10.10.9.9/32 - fd00::10:10:9:9/128'''&lt;br /&gt;
&lt;br /&gt;
Esses IPs serão entregues pelos concentradores '''PPPoE''' ou '''IPoE''' ('''BNG''') para seus clientes como '''DNS primário''' e '''secundário'''. Podemos usar IPs privados como DNS primário e secundário em um ambiente real? Sim podemos, desde que não sejam IPs que possam ter problemas com as redes privadas dos clientes. Ex.: rede do cliente usando '''192.168.0.0/24'''. Se entregarmos o DNS sendo '''192.168.0.10''' e '''192.168.0.20''' teremos problemas e o cliente ficará sem Internet, porque '''192.168.0.10''' e '''192.168.0.20''' fazem parte da rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
Agora entregando '''10.10.10.10,''' '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9''' não teríamos problemas com a rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
'''Motivos para usarmos IPs privados:'''&lt;br /&gt;
* O principal motivo está relacionado com a segurança, uma vez que sendo um IP privado, não pode sofrer ataques DDoS direcionados diretamente para ele, vindos da Internet.&lt;br /&gt;
* Nem mesmo o cliente da sua rede conhece os '''IPs públicos''' utilizados para recursividade na Internet.&lt;br /&gt;
* Memorizar os IPs '''10.10.10.10''' e '''10.10.9.9''' é tão fácil quanto memorizar o '''8.8.8.8''' e o '''1.1.1.1'''. Mais fácil para o seu técnico guardar essa informação e utilizar onde for necessário.&lt;br /&gt;
Cada servidor DNS Recursivo possui um '''IPv4 público''', aqui representado por '''198.18.x.x/27''' e um '''IPv6 global''' representado por um IP dentro do prefixo '''2001:db8::/32'''. Cada servidor precisa ter os seus próprios IPs e são através destes IPs que as consultas de DNS serão realizadas na Internet.&lt;br /&gt;
&lt;br /&gt;
Nessa topologia usando '''Anycast''', o cliente será sempre atendido pelo '''DNS Recursivo''' mais próximo, desde que os pesos no '''OSPF''' estejam ajustados corretamente.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
== Dados do servidor ==&lt;br /&gt;
Podemos utilizar um sistema virtualizado ou não. Sistemas virtualizados são bem vindos pois são mais simples quando precisamos fazer backups, levantar outros sistemas sem complicações e se precisarmos restaurar rapidamente algum sistema que ficou indisponível por algum motivo. A configuração abaixo tem capacidade para atender algo em torno a '''50.000 assinantes ou mais'''. O DNS Recursivo é um serviço que pode ser utilizado até mesmo em um '''Raspberry Pi''' e atender operações pequenas, nesse caso com o intuito de economizar energia e espaço. Nosso foco aqui é montar uma rede de '''DNS Recursivo Anycast com HyperLocal'''. Como comentei acima o servidor deve ficar o mais próximo dos clientes para termos a '''menor latência possível''' e '''sempre menor que 5ms''' entre o cliente e o servidor.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!CPU&lt;br /&gt;
!Memória&lt;br /&gt;
!Disco&lt;br /&gt;
!Sistema&lt;br /&gt;
|-&lt;br /&gt;
|2.4Ghz 8 cores&lt;br /&gt;
|16G DDR4&lt;br /&gt;
|30G&lt;br /&gt;
|Debian 13 amd64 (Trixie)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Softwares utilizados ==&lt;br /&gt;
* Debian 13 amd64 (Trixie) instalação mínima.&lt;br /&gt;
&lt;br /&gt;
* [https://frrouting.org/ FRRouting].&lt;br /&gt;
* Unbound.&lt;br /&gt;
* Chrony (NTP/NTS).&lt;br /&gt;
* Shell script em bash.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades que teremos ==&lt;br /&gt;
* Sistema em Anycast.&lt;br /&gt;
* Hyperlocal.&lt;br /&gt;
* Controle de acesso por &amp;lt;abbr&amp;gt;ACL&amp;lt;/abbr&amp;gt;.&lt;br /&gt;
* RPZ (Response Policy Zone).&lt;br /&gt;
* Bloqueio de consultas do tipo ANY.&lt;br /&gt;
* QNAME minimization habilitado. (habilitado por default no Unbound)&lt;br /&gt;
* Recursividade em IPv4 e IPv6.&lt;br /&gt;
* DNSSEC habilitado.&lt;br /&gt;
* &amp;lt;abbr&amp;gt;DoH (DNS&amp;lt;/abbr&amp;gt; over HTTPS) habilitado.&lt;br /&gt;
&lt;br /&gt;
== Monitoramento ==&lt;br /&gt;
O monitoramento é algo bem específico e não é o foco deste documento mas é extremamente importante que você monitore seus servidores de DNS por alguma ferramenta como o Zabbix. Aqui mostrarei apenas como enviar as informações para o Zabbix. Algumas coisas que você deveria monitorar nos servidores de DNS Recursivo:&lt;br /&gt;
* Serviço do unbound parou.&lt;br /&gt;
* Perda de pacotes.&lt;br /&gt;
* Latência alta de pacotes.&lt;br /&gt;
* Lentidão na resolução de queries.&lt;br /&gt;
* CPU alta.&lt;br /&gt;
* Load alto.&lt;br /&gt;
* Memória com uso alto.&lt;br /&gt;
* Disco com pouco espaço.&lt;br /&gt;
* Queda brusca nas queries.&lt;br /&gt;
* A recursividade parou de funcionar.&lt;br /&gt;
* A recursividade voltou a funcionar.&lt;br /&gt;
Este abaixo é um exemplo de monitoramento de um sistema de DNS Recursivo que atende 50.000 assinantes:&lt;br /&gt;
[[Arquivo:Grafana dns.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Configurando a Rede ==&lt;br /&gt;
Nossa documentação será baseada no diagrama apresentado acima e por isso configuraremos apenas um dos três servidores, porque os outros serão configurados da mesma forma, só que com dados diferentes. Para tanto assumirei que já temos um sistema Debian instalado com o mínimo de pacotes e somente com sshd, para que possamos acessar remotamente mais tarde. '''Não instale um ambiente gráfico no servidor''', você não deve querer fazer isso por diversos motivos e os principais: primeiro porque não é um Desktop e segundo porque o ambiente gráfico devoraria toda a memória com recursos que não seriam úteis aqui.&lt;br /&gt;
&lt;br /&gt;
Em '''/etc/network/interfaces''' deixaremos assim:&lt;br /&gt;
 # This file describes the network interfaces available on your system&lt;br /&gt;
 # and how to activate them. For more information, see interfaces(5).&lt;br /&gt;
  &lt;br /&gt;
 source /etc/network/interfaces.d/*&lt;br /&gt;
  &lt;br /&gt;
 # The loopback network interface&lt;br /&gt;
 auto lo&lt;br /&gt;
 iface lo inet loopback&lt;br /&gt;
  &lt;br /&gt;
 auto lo:0&lt;br /&gt;
 iface lo:0 inet static&lt;br /&gt;
       address 10.10.10.10/32&lt;br /&gt;
  &lt;br /&gt;
 auto lo:1&lt;br /&gt;
 iface lo:1 inet static&lt;br /&gt;
       address 10.10.9.9/32&lt;br /&gt;
 &lt;br /&gt;
 auto lo:2&lt;br /&gt;
 iface lo:2 inet6 static&lt;br /&gt;
       address fd00::10:10:10:10/128&lt;br /&gt;
 &lt;br /&gt;
 auto lo:3&lt;br /&gt;
 iface lo:3 inet6 static&lt;br /&gt;
       address fd00::10:10:9:9/128&lt;br /&gt;
  &lt;br /&gt;
 # The primary network interface&lt;br /&gt;
 auto ens18&lt;br /&gt;
 iface ens18 inet static&lt;br /&gt;
         address 198.18.1.10/27&lt;br /&gt;
         gateway 198.18.1.1&lt;br /&gt;
  &lt;br /&gt;
 iface ens18 inet6 static&lt;br /&gt;
         address 2001:db8::faca:198:18:1:10/64&lt;br /&gt;
         gateway 2001:db8::faca:198:18:1:1&lt;br /&gt;
  &lt;br /&gt;
 # The secondary network interface&lt;br /&gt;
 auto ens18:0&lt;br /&gt;
 iface ens18:0 inet static&lt;br /&gt;
         address 172.16.0.6/30&lt;br /&gt;
Nesse cenário temos as duas '''loopbacks''' com os IPs '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10''' e '''fd00::10:10:9:9''' que serão anunciados via OSPF para a rede e serem entregues aos clientes via BNG. Os IPs '''198.18.1.10''' e '''2001:db8::faca:198:18:1:10''' serão usados para fazerem a recursividade na Internet tanto em IPv4 quanto em IPv6. Esses IPs não devem ser divulgados para clientes; os IPs públicos são dedicados apenas para essa finalidade.&lt;br /&gt;
&lt;br /&gt;
== Configuração dos repositórios Debian ==&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://security.debian.org/debian-security/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-security&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-updates&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian-backports.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-backports&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
&lt;br /&gt;
 # rm /etc/apt/sources.list&lt;br /&gt;
Após a configuração vamos instalar alguns pacotes necessários e outros úteis:&lt;br /&gt;
 # apt update &amp;amp;&amp;amp; apt full-upgrade&lt;br /&gt;
 # apt install net-tools nftables htop iotop sipcalc tcpdump curl gnupg rsync wget host dnsutils mtr-tiny bmon sudo tmux whois ethtool dnstop&lt;br /&gt;
&lt;br /&gt;
== Fazendo algum tuning no sistema ==&lt;br /&gt;
Em '''/etc/sysctl.d/100-tuning.conf''' adicionamos essas instruções:&lt;br /&gt;
 net.core.rmem_max = 2147483647&lt;br /&gt;
 net.core.wmem_max = 2147483647&lt;br /&gt;
 net.ipv4.tcp_rmem = 4096 87380 2147483647&lt;br /&gt;
 net.ipv4.tcp_wmem = 4096 65536 2147483647&lt;br /&gt;
 net.netfilter.nf_conntrack_buckets = 512000&lt;br /&gt;
 net.netfilter.nf_conntrack_max = 4096000&lt;br /&gt;
 vm.swappiness=10&lt;br /&gt;
Estamos fazendo algumas melhorias de memória, algumas relacionadas a '''conntrack''' porque se for usar um filtro de pacotes stateful, como o '''Netfilter/IPTables''' ou '''Netfilter/NFTables''', o valor default da tabela é pequeno e dependendo da situação, se estourar essa tabela, as consultas de DNS terão problemas também. O DNS Recursivo não deve ficar aberto para qualquer um na Internet, ele deve ser liberado apenas para seus clientes. Podemos fazer através das ACLs do Unbound e pelo filtro de pacotes. O último parâmetro diz respeito ao uso de swap, por padrão o Debian permite o uso de swap após 40% do uso da memória, nesse caso estamos dizendo para o sistema usar o swap com 90% de uso da memória.&lt;br /&gt;
&lt;br /&gt;
Precisamos adicionar o módulo '''nf_conntrack''' em '''/etc/modules''' para que seja carregado em tempo de boot, senão os parâmetros de '''conntrack''' que colocamos em '''/etc/sysctl.conf''' não serão carregados.&lt;br /&gt;
 # echo nf_conntrack &amp;gt;&amp;gt; /etc/modules&lt;br /&gt;
 # modprobe nf_conntrack&lt;br /&gt;
 # sysctl -p&lt;br /&gt;
&lt;br /&gt;
== Instalando o FRRouting ==&lt;br /&gt;
O FRRouting é o programa que usaremos para fazer os anúncios das nossas loopbacks via OSPF. Nesse documento usaremos a versão 10.x:&lt;br /&gt;
 # apt install frr frr-doc frr-pythontools&lt;br /&gt;
Aconselho depois de instalar os pacotes, marcá-los para não atualizar juntamente com os demais pacotes, isso é para evitar de ocorrer alguma atualização no FRRouting, que torne o serviço instável por algum motivo. Não que isso vá ocorrer, mas é melhor fazer essa atualização quando realmente for necessário.&lt;br /&gt;
 # apt-mark hold frr frr-doc frr-pythontools&lt;br /&gt;
Após esse comando acima, o sistema manterá a instalação original do pacote intacta. Para desbloquear basta executar o comando abaixo:&lt;br /&gt;
 # apt-mark unhold frr frr-doc frr-pythontools&lt;br /&gt;
&lt;br /&gt;
== Removendo o APPARMOR ==&lt;br /&gt;
O '''APPARMOR''' às vezes causa mais problemas que solução e se não for fazer uma completa configuração nele, é melhor desabilitá-lo. Para fazer isso efetivamente, o procedimento é esse abaixo:&lt;br /&gt;
 # mkdir -p /etc/default/grub.d&lt;br /&gt;
 # echo 'GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;$GRUB_CMDLINE_LINUX_DEFAULT apparmor=0&amp;quot;' | tee /etc/default/grub.d/apparmor.cfg&lt;br /&gt;
 # update-grub&lt;br /&gt;
 # reboot&lt;br /&gt;
&lt;br /&gt;
== Instalando o Unbound ==&lt;br /&gt;
Nesse momento ainda não iremos configurar o Unbound, apenas instalar o pacote e acertar o ambiente. Vamos instalar o unbound do backports porque este já possui suporte ao DoH que veremos mais à frente.&lt;br /&gt;
 # apt install unbound dns-root-data&lt;br /&gt;
 # mkdir -p /var/log/unbound&lt;br /&gt;
 # touch /var/log/unbound/unbound.log&lt;br /&gt;
 # chown -R unbound:unbound /var/log/unbound/&lt;br /&gt;
 # systemctl restart unbound&lt;br /&gt;
Configurando o logrotate:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/logrotate.d/unbound&lt;br /&gt;
 /var/log/unbound/unbound.log {&lt;br /&gt;
     rotate 5&lt;br /&gt;
     weekly&lt;br /&gt;
     postrotate&lt;br /&gt;
         unbound-control log_reopen&lt;br /&gt;
     endscript&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
Reiniciando o serviço:&lt;br /&gt;
 # systemctl restart logrotate.service&lt;br /&gt;
&lt;br /&gt;
== Desabilitando THP (Transparente Huge Pages) em arquitetura AMD64 ==&lt;br /&gt;
No Debian o '''THP''' vem habilitado como '''always''' e o '''unbound''' por trabalhar bastante com alterações do cache em memória, isso pode acabar causando um consumo crescente de uso de RAM sem necessidade. É uma boa prática desabilitá-lo com os passos abaixo:&lt;br /&gt;
&lt;br /&gt;
https://github.com/NLnetLabs/unbound/issues/724&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/systemd/system/disable-thp.service&lt;br /&gt;
 [Unit]&lt;br /&gt;
 Description=Desabilita Transparent Huge Pages (THP)&lt;br /&gt;
 After=network.target&lt;br /&gt;
 &lt;br /&gt;
 [Service]&lt;br /&gt;
 Type=oneshot&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled&amp;quot;&lt;br /&gt;
 RemainAfterExit=yes&lt;br /&gt;
 &lt;br /&gt;
 [Install]&lt;br /&gt;
 WantedBy=multi-user.target&lt;br /&gt;
 EOF&lt;br /&gt;
Acima configuramos o serviço '''disable-thp.service''' para desabilitar o '''THP''' e abaixo habilitamos no '''systemd''' e iniciamos:&lt;br /&gt;
 # systemctl daemon-reload&lt;br /&gt;
 # systemctl enable --now disable-thp&lt;br /&gt;
&lt;br /&gt;
== Preparando o monitoramento do seu DNS Recursivo ==&lt;br /&gt;
O monitoramento do seu DNS Recursivo é muito importante e para isso vamos usar um '''template para Zabbix''', que modifiquei juntamente com o seu shell script e que enviará os dados para o seu Zabbix server via '''zabbix-sender'''. O projeto original está aqui '''https://github.com/jeftedelima/Unbound-DNS&amp;lt;nowiki/&amp;gt;.''' O xml alterado está aqui '''https://github.com/gondimcodes/template_zabbix_dns_unbound'''. Embora seja antigo é perfeitamente importável no Zabbix 6.0, por exemplo.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;nowiki/&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Teremos um shell script que você precisará colocar no seu '''/etc/crontab'''. No exemplo abaixo assumi que o shell script está em '''/root/scripts'''. De 5 em 5 minutos os dados serão enviados para o seu Zabbix server.&lt;br /&gt;
 */5 * * * *     root    /root/scripts/unboundSend.sh '''IP_zabbix_server''' '''nome_do_host''' 1&amp;gt; /dev/null&lt;br /&gt;
Na linha acima, troque o '''IP_zabbix_server''' pelo '''IP do seu servidor Zabbix''' e o '''nome_do_host''' pelo '''hostname''' '''do seu DNS Recursivo'''. Você precisará instalar o pacote '''zabbix-sender''' no seu DNS Recursivo pois ele será usado para enviar os dados para o Zabbix server.&lt;br /&gt;
&lt;br /&gt;
Abaixo o '''unboundSend.sh''' também alterado com inclusão de mais dados:&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 #       @Jefte de Lima Ferreira&lt;br /&gt;
 #       jeftedelima at gmail dot com&lt;br /&gt;
 #       CRON Example&lt;br /&gt;
 #       Contributor: Marcelo Gondim - gondim at gmail dot com&lt;br /&gt;
 #       */5   **** root sh /home/dir/unboundSend.sh 192.168.10.1 Unbound 1&amp;gt; /dev/null&lt;br /&gt;
  &lt;br /&gt;
 if [ -z ${1} ] || [ -z ${2} ] ; then&lt;br /&gt;
         echo &amp;quot;You need to specify the IP address of zabbix server and hostname of your DNS Unbound on zabbix&amp;quot;&lt;br /&gt;
         echo &amp;quot;Usage example: ./unboundSend.sh 192.168.10.1 UnboundServer&amp;quot;&lt;br /&gt;
         exit 1&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 # ZABBIX_SERVER IP&lt;br /&gt;
 IP_ZABBIX=$1&lt;br /&gt;
 # NAME Unbound on Zabbix&lt;br /&gt;
 NAME_HOST=$2&lt;br /&gt;
 DIR_TEMP=/var/tmp/&lt;br /&gt;
 FILE=&amp;quot;${DIR_TEMP}dump_unbound_control_stats.txt&amp;quot;&lt;br /&gt;
 unbound-control stats &amp;gt; ${FILE}&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_NUM_QUERIES=$(cat ${FILE} | grep -w 'total.num.queries' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEHITS=$(cat ${FILE} | grep -w 'total.num.cachehits' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEMISS=$(cat ${FILE} | grep -w 'total.num.cachemiss' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_PREFETCH=$(cat ${FILE} | grep -w 'total.num.prefetch' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_RECURSIVEREPLIES=$(cat ${FILE} | grep -w 'total.num.recursivereplies' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_REQ_MAX=$(cat ${FILE} | grep -w 'total.requestlist.max' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_AVG=$(cat ${FILE} | grep -w 'total.requestlist.avg' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_OVERWRITTEN=$(cat ${FILE} | grep -w 'total.requestlist.overwritten' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_EXCEEDED=$(cat ${FILE} | grep -w 'total.requestlist.exceeded' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_ALL=$(cat ${FILE} | grep -w 'total.requestlist.current.all' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_USER=$(cat ${FILE} | grep -w 'total.requestlist.current.user' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_TCPUSAGE=$(cat ${FILE} | grep -w 'total.tcpusage' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_QUERY_TYPE_A=$(cat ${FILE} | grep -w 'num.query.type.A' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NS=$(cat ${FILE} | grep -w 'num.query.type.NS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_MX=$(cat ${FILE} | grep -w 'num.query.type.MX' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TXT=$(cat ${FILE} | grep -w 'num.query.type.TXT' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_PTR=$(cat ${FILE} | grep -w 'num.query.type.PTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_AAAA=$(cat ${FILE} | grep -w 'num.query.type.AAAA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SRV=$(cat ${FILE} | grep -w 'num.query.type.SRV' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SOA=$(cat ${FILE} | grep -w 'num.query.type.SOA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HTTPS=$(cat ${FILE} | grep -w 'num.query.type.HTTPS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TYPE0=$(cat ${FILE} | grep -w 'num.query.type.TYPE0' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_CNAME=$(cat ${FILE} | grep -w 'num.query.type.CNAME' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_WKS=$(cat ${FILE} | grep -w 'num.query.type.WKS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HINFO=$(cat ${FILE} | grep -w 'num.query.type.HINFO' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_X25=$(cat ${FILE} | grep -w 'num.query.type.X25' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NAPTR=$(cat ${FILE} | grep -w 'num.query.type.NAPTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DS=$(cat ${FILE} | grep -w 'num.query.type.DS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DNSKEY=$(cat ${FILE} | grep -w 'num.query.type.DNSKEY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TLSA=$(cat ${FILE} | grep -w 'num.query.type.TLSA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SVCB=$(cat ${FILE} | grep -w 'num.query.type.SVCB' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SPF=$(cat ${FILE} | grep -w 'num.query.type.SPF' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_ANY=$(cat ${FILE} | grep -w 'num.query.type.ANY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_OTHER=$(cat ${FILE} | grep -w 'num.query.type.other' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_ANSWER_RCODE_NOERROR=$(cat ${FILE} | grep -w 'num.answer.rcode.NOERROR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_NXDOMAIN=$(cat ${FILE} | grep -w 'num.answer.rcode.NXDOMAIN' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_SERVFAIL=$(cat ${FILE} | grep -w 'num.answer.rcode.SERVFAIL' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_REFUSED=$(cat ${FILE} | grep -w 'num.answer.rcode.REFUSED' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_nodata=$(cat ${FILE} | grep -w 'num.answer.rcode.nodata' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_secure=$(cat ${FILE} | grep -w 'num.answer.secure' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 #       Sending info to zabbix_server.&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.queries -o $(( ${TOTAL_NUM_QUERIES:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachehits -o $(( ${TOTAL_NUM_CACHEHITS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachemiss -o $(( ${TOTAL_NUM_CACHEMISS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.prefetch -o $(( ${TOTAL_NUM_PREFETCH:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.recursivereplies -o $(( ${TOTAL_NUM_RECURSIVEREPLIES:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.max -o $(( ${TOTAL_REQ_MAX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.avg -o $(( ${TOTAL_REQ_AVG:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.overwritten -o $(( ${TOTAL_REQ_OVERWRITTEN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.exceeded -o $(( ${TOTAL_REQ_EXCEEDED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.all -o $(( ${TOTAL_REQ_CURRENT_ALL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.user -o $(( ${TOTAL_REQ_CURRENT_USER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.tcpusage -o $(( ${TOTAL_TCPUSAGE:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.a -o $(( ${NUM_QUERY_TYPE_A:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ns -o $(( ${NUM_QUERY_TYPE_NS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.mx -o $(( ${NUM_QUERY_TYPE_MX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.txt -o $(( ${NUM_QUERY_TYPE_TXT:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ptr -o $(( ${NUM_QUERY_TYPE_PTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.aaaa -o $(( ${NUM_QUERY_TYPE_AAAA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.srv -o $(( ${NUM_QUERY_TYPE_SRV:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.soa -o $(( ${NUM_QUERY_TYPE_SOA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.https -o $(( ${NUM_QUERY_TYPE_HTTPS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.type0 -o $(( ${NUM_QUERY_TYPE_TYPE0:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.cname -o $(( ${NUM_QUERY_TYPE_CNAME:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.wks -o $(( ${NUM_QUERY_TYPE_WKS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.hinfo -o $(( ${NUM_QUERY_TYPE_HINFO:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.X25 -o $(( ${NUM_QUERY_TYPE_X25:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.naptr -o $(( ${NUM_QUERY_TYPE_NAPTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ds -o $(( ${NUM_QUERY_TYPE_DS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.dnskey -o $(( ${NUM_QUERY_TYPE_DNSKEY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.tlsa -o $(( ${NUM_QUERY_TYPE_TLSA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.svcb -o $(( ${NUM_QUERY_TYPE_SVCB:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.spf -o $(( ${NUM_QUERY_TYPE_SPF:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.any -o $(( ${NUM_QUERY_TYPE_ANY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.other -o $(( ${NUM_QUERY_TYPE_OTHER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NOERROR -o $(( ${NUM_ANSWER_RCODE_NOERROR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NXDOMAIN -o $(( ${NUM_ANSWER_RCODE_NXDOMAIN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.SERVFAIL -o $(( ${NUM_ANSWER_RCODE_SERVFAIL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.REFUSED -o $(( ${NUM_ANSWER_RCODE_REFUSED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.nodata -o $(( ${NUM_ANSWER_RCODE_nodata:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.secure -o $(( ${NUM_ANSWER_secure:-0} / 300 ))&lt;br /&gt;
No Zabbix será registrado dados como esses abaixo e posteriormente pode ser montado um Grafana com eles:&lt;br /&gt;
[[Arquivo:Zabbix dns01.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns02.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns03.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns04.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Mantendo a hora certa ==&lt;br /&gt;
Vamos instalar agora o Chrony para manter a data e hora certas no sistema:&lt;br /&gt;
 # apt install chrony&lt;br /&gt;
Após a instalação do Chrony edite o arquivo /etc/chrony/chrony.conf, comente e a linha abaixo e adicione seus servidores NTP. Caso não tenha servidores NTP, estou colocando os do NIC.br aqui.&lt;br /&gt;
 #pool 2.debian.pool.ntp.org iburst&lt;br /&gt;
 server a.st1.ntp.br iburst nts&lt;br /&gt;
 server b.st1.ntp.br iburst nts&lt;br /&gt;
 server c.st1.ntp.br iburst nts&lt;br /&gt;
 server d.st1.ntp.br iburst nts&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart chronyd.service&lt;br /&gt;
Cheque com o '''chronyc''' se os servidores estão OK:&lt;br /&gt;
 # chronyc sourcestats&lt;br /&gt;
 Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev&lt;br /&gt;
 ==============================================================================&lt;br /&gt;
 a.st1.ntp.br               10   5  155m     -0.027      0.030    -71us    51us&lt;br /&gt;
 b.st1.ntp.br               11   7  344m     +0.068      0.079    +23ms   382us&lt;br /&gt;
 c.st1.ntp.br                6   3  344m     +0.026      0.037   -124us    92us&lt;br /&gt;
 200.20.186.76               9   3  138m     -0.022      0.031   +172us    42us&lt;br /&gt;
&lt;br /&gt;
 # chronyc sources&lt;br /&gt;
 MS Name/IP address         Stratum Poll Reach LastRx Last sample&lt;br /&gt;
 ===============================================================================&lt;br /&gt;
 ^* a.st1.ntp.br                  1  10   377   588   +487us[ +397us] +/-   12ms&lt;br /&gt;
 ^- b.st1.ntp.br                  2  10   377   830    +23ms[  +23ms] +/-   49ms&lt;br /&gt;
 ^+ c.st1.ntp.br                  2  10    21  1038   -147us[ -242us] +/-   17ms&lt;br /&gt;
 ^+ 200.20.186.76                 1  10   377  1032   +381us[ +285us] +/-   15ms&lt;br /&gt;
&lt;br /&gt;
== Configurando o FRRouting ==&lt;br /&gt;
Nesse ponto iremos configurar o '''FRRouting''' para enviar os IPs das '''loopbacks''' e o '''/30''' para o nosso PE do diagrama. Em '''/etc/frr/daemons''' habilite o parâmetro conforme abaixo:&lt;br /&gt;
 ospfd=yes&lt;br /&gt;
 ospf6d=yes&lt;br /&gt;
Edite o arquivo '''/etc/frr/frr.conf''' e deixe com o conteúdo abaixo, para ficar conforme nosso diagrama do projeto. Apenas troque '''&amp;lt;SENHA&amp;gt;''' por uma senha para fechar o OSPF com mais segurança. Essa senha deve ser usada dos dois lados.&lt;br /&gt;
 frr version 10.3&lt;br /&gt;
 frr defaults traditional&lt;br /&gt;
 hostname dns-recursivo-01&lt;br /&gt;
 log syslog informational&lt;br /&gt;
 no ip forwarding&lt;br /&gt;
 no ipv6 forwarding&lt;br /&gt;
 service integrated-vtysh-config&lt;br /&gt;
 !&lt;br /&gt;
 interface ens18&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf message-digest-key 5 md5 &amp;lt;SENHA&amp;gt;&lt;br /&gt;
  ip ospf network point-to-point&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 network point-to-point&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 interface lo&lt;br /&gt;
  description LOOPBACKS&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf passive&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 passive&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf&lt;br /&gt;
  ospf router-id 172.16.0.6&lt;br /&gt;
  area 0.0.0.0 authentication message-digest&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf6&lt;br /&gt;
  ospf6 router-id 172.16.0.6&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart frr.service&lt;br /&gt;
Cheque se está tudo OK com o OSPF e verifique no PE se está recebendo os prefixos anunciados.&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL&lt;br /&gt;
 172.16.0.5     1 Full/-          10m49s            35.310s 172.16.0.5   ens18:172.16.0.6                  0     0     0&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri    DeadTime    State/IfState         Duration I/F[State]&lt;br /&gt;
 172.16.0.5       1    00:00:30     Full/PointToPoint 25d22:53:47 ens18[PointToPoint]&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor detail'&lt;br /&gt;
 &lt;br /&gt;
  Neighbor 172.16.0.5, interface address 172.16.0.5&lt;br /&gt;
     In the area 0.0.0.0 via interface ens18&lt;br /&gt;
     Neighbor priority is 1, State is Full/-, 5 state changes&lt;br /&gt;
     Most recent state change statistics:&lt;br /&gt;
       Progressive change 21w3d15h ago&lt;br /&gt;
     DR is 0.0.0.0, BDR is 0.0.0.0&lt;br /&gt;
     Options 18 *|-|-|EA|-|-|E|-&lt;br /&gt;
     Dead timer due in 34.685s&lt;br /&gt;
     Database Summary List 0&lt;br /&gt;
     Link State Request List 0&lt;br /&gt;
     Link State Retransmission List 0&lt;br /&gt;
     Thread Inactivity Timer on&lt;br /&gt;
     Thread Database Description Retransmision off&lt;br /&gt;
     Thread Link State Request Retransmission on&lt;br /&gt;
     Thread Link State Update Retransmission on&lt;br /&gt;
 &lt;br /&gt;
     Graceful restart Helper info:&lt;br /&gt;
       Graceful Restart HELPER Status : None&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor detail'&lt;br /&gt;
  Neighbor 172.16.0.5%ens18&lt;br /&gt;
     Area 0.0.0.0 via interface ens18 (ifindex 4)&lt;br /&gt;
     His IfIndex: 60 Link-local address: fe80::469b:c1ff:fed6:43ee&lt;br /&gt;
     State Full for a duration of 25d22:57:14&lt;br /&gt;
     His choice of DR/BDR 0.0.0.0/0.0.0.0, Priority 1&lt;br /&gt;
     DbDesc status: Master SeqNum: 0xb94b0000&lt;br /&gt;
     Summary-List: 0 LSAs&lt;br /&gt;
     Request-List: 0 LSAs&lt;br /&gt;
     Retrans-List: 0 LSAs&lt;br /&gt;
     0 Pending LSAs for DbDesc in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSReq in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSAck in Time 00:00:00 [thread off]&lt;br /&gt;
     Authentication header not present&lt;br /&gt;
&lt;br /&gt;
== Configurando o Unbound ==&lt;br /&gt;
Abaixo a configuração que usaremos nos servidores atentando para o detalhe do '''num-threads''', esse deve ter o valor igual ao número de CPUs do servidor.&lt;br /&gt;
&lt;br /&gt;
Também os IPs utilizados em '''outgoing-interface''' que serão diferentes em cada servidor, esses serão os IPs usados para '''recursividade'''. Consulte o manual do Unbound para obter mais informações sobre cada parâmetro listado na configuração.&lt;br /&gt;
&lt;br /&gt;
O tuning no Unbound pode ser alterado conforme abaixo:&lt;br /&gt;
 num-threads = nº CPUs&lt;br /&gt;
 so-reuseport = yes&lt;br /&gt;
 *-slabs = potência de 2 próximo ao num-threads&lt;br /&gt;
 msg-cache-size = 1g (quantidade de memória pra usar de cache)&lt;br /&gt;
 rrset-cache-size = 2 * msg-cache-size&lt;br /&gt;
 outgoing-range = 8192&lt;br /&gt;
 num-queries-per-thread = 4096&lt;br /&gt;
 so-rcvbuf e so-sndbuf = 4m ou 8m para servidores com muita requisição&lt;br /&gt;
Agora vamos criar nosso arquivo de configuração base em '''/etc/unbound/unbound.conf.d/local.conf''':&lt;br /&gt;
 server:&lt;br /&gt;
         verbosity: 1&lt;br /&gt;
         statistics-interval: 0&lt;br /&gt;
         statistics-cumulative: no&lt;br /&gt;
         extended-statistics: yes&lt;br /&gt;
         num-threads: 8&lt;br /&gt;
         serve-expired: yes&lt;br /&gt;
         interface: 127.0.0.1&lt;br /&gt;
         interface: 10.10.10.10&lt;br /&gt;
         interface: 10.10.9.9&lt;br /&gt;
         interface: 172.16.0.6&lt;br /&gt;
         interface: fd00::10:10:10:10&lt;br /&gt;
         interface: fd00::10:10:9:9&lt;br /&gt;
         interface: ::1&lt;br /&gt;
         interface-automatic: no&lt;br /&gt;
         outgoing-interface: 198.18.1.10&lt;br /&gt;
         outgoing-interface: 2001:db8::faca:198:18:1:10&lt;br /&gt;
         outgoing-range: 8192&lt;br /&gt;
         outgoing-num-tcp: 1024&lt;br /&gt;
         incoming-num-tcp: 2048&lt;br /&gt;
         so-rcvbuf: 4m&lt;br /&gt;
         so-sndbuf: 4m&lt;br /&gt;
         so-reuseport: yes&lt;br /&gt;
         edns-buffer-size: 1232&lt;br /&gt;
         msg-cache-size: 512m&lt;br /&gt;
         msg-cache-slabs: 4&lt;br /&gt;
         num-queries-per-thread: 4096&lt;br /&gt;
         rrset-cache-size: 1g&lt;br /&gt;
         rrset-cache-slabs: 4&lt;br /&gt;
         infra-cache-slabs: 4&lt;br /&gt;
         do-ip4: yes&lt;br /&gt;
         do-ip6: yes&lt;br /&gt;
         do-udp: yes&lt;br /&gt;
         do-tcp: yes&lt;br /&gt;
         chroot: &amp;quot;&amp;quot;&lt;br /&gt;
         username: &amp;quot;unbound&amp;quot;&lt;br /&gt;
         directory: &amp;quot;/etc/unbound&amp;quot;&lt;br /&gt;
         logfile: &amp;quot;/var/log/unbound/unbound.log&amp;quot;&lt;br /&gt;
         use-syslog: no&lt;br /&gt;
         log-time-ascii: yes&lt;br /&gt;
         log-queries: no&lt;br /&gt;
         pidfile: &amp;quot;/var/run/unbound.pid&amp;quot;&lt;br /&gt;
         root-hints: &amp;quot;/usr/share/dns/root.hints&amp;quot;&lt;br /&gt;
         hide-identity: yes&lt;br /&gt;
         hide-version: yes&lt;br /&gt;
         unwanted-reply-threshold: 10000000&lt;br /&gt;
         prefetch: yes&lt;br /&gt;
         prefetch-key: yes&lt;br /&gt;
         rrset-roundrobin: yes&lt;br /&gt;
         minimal-responses: yes&lt;br /&gt;
         module-config: &amp;quot;respip validator iterator&amp;quot;&lt;br /&gt;
         val-clean-additional: yes&lt;br /&gt;
         val-log-level: 1&lt;br /&gt;
         key-cache-slabs: 4&lt;br /&gt;
         deny-any: yes&lt;br /&gt;
         cache-min-ttl: 60&lt;br /&gt;
         key-cache-size: 128m&lt;br /&gt;
         neg-cache-size: 64m&lt;br /&gt;
         cache-max-ttl: 86400&lt;br /&gt;
         infra-cache-numhosts: 100000&lt;br /&gt;
         access-control: 198.18.0.0/22 allow&lt;br /&gt;
         access-control: 2001:db8::/32 allow&lt;br /&gt;
  &lt;br /&gt;
 rpz:&lt;br /&gt;
   name: rpz.block.host.local.zone&lt;br /&gt;
   zonefile: /etc/unbound/rpz.block.hosts.zone&lt;br /&gt;
   rpz-action-override: nxdomain&lt;br /&gt;
  &lt;br /&gt;
 python:&lt;br /&gt;
  &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;.&amp;quot;&lt;br /&gt;
     master: &amp;quot;b.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;c.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;d.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;f.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;g.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;k.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/root.zone&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;arpa.&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/arpa.zone&amp;quot;&lt;br /&gt;
No parâmetro '''interface''' colocamos os IPs que serão usados para consulta dos clientes como o '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9'''. Ali repare que coloquei também o IP privado '''172.16.0.6''', isso porque cada servidor terá o seu IP privado e este deve ser usado pelo seu sistema de monitoramento para checar cada servidor. No '''outgoing-interface''' teremos os IPs, tanto '''IPv4''' quanto '''IPv6''', para que seja feita a recursividade na Internet utilizando eles. Não tem '''IPv6''' ainda na sua rede? Dê uma olhada nesse artigo. Outro parâmetro importante é o '''access-control''' e é através dele que liberamos os prefixos IP para consultarem no nosso DNS Recursivo. No exemplo estou liberando todo o prefixo '''198.18.0.0/22''' e o prefixo '''2001:db8::/32'''. Além da ACL no Unbound, recomendo que crie um filtro de pacotes com iptables ou nftables protegendo seu sistema e liberando as portas '''53/UDP''', '''53/TCP,'''  '''443/TCP e 853/TCP''' apenas para seus clientes. Falarei sobre a '''443/TCP e 853/TCP''' mais para frente nessa mesma documentação.&lt;br /&gt;
&lt;br /&gt;
Agora criaremos o arquivo '''RPZ''' ('''Response Policy Zones'''). Esse arquivo contém os sites que serão bloqueados via '''&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; Recursivo'''. São aqueles sites que às vezes você recebe um Ofício da Justiça solicitando o bloqueio deles. Não entrarei no mérito da efetividade desses bloqueios, porque muitos de vocês sabem que tecnicamente, existem formas de se fazer um bypass através desses bloqueios. Contudo vamos deixar nosso ambiente preparado para esses bloqueios e por isso crie o arquivo '''/etc/unbound/rpz.block.hosts.zone''' com esse conteúdo de exemplo:&lt;br /&gt;
 $TTL 2h&lt;br /&gt;
 @ IN SOA localhost. root.localhost. (2 6h 1h 1w 2h)&lt;br /&gt;
   IN NS  localhost.&lt;br /&gt;
 ; RPZ manual block hosts&lt;br /&gt;
 *.josedascoves.com CNAME .&lt;br /&gt;
 josedascoves.com CNAME .&lt;br /&gt;
No exemplo acima estamos bloqueando qualquer consulta de DNS para '''josedascoves.com''' ou qualquer coisa '''.josedascoves.com'''.&lt;br /&gt;
&lt;br /&gt;
Para testar podemos fazer assim do próprio servidor:&lt;br /&gt;
 # host josedascoves.com ::1&lt;br /&gt;
 Using domain server:&lt;br /&gt;
 Name: ::1&lt;br /&gt;
 Address: ::1#53&lt;br /&gt;
 Aliases:&lt;br /&gt;
 &lt;br /&gt;
 Host josedascoves.com not found: 3(NXDOMAIN)&lt;br /&gt;
Se a resposta for '''NXDOMAIN''' então está funcionando o bloqueio. Para incluir novos bloqueios basta adicionar os domínios, um abaixo do outro, conforme o exemplo que coloquei no arquivo RPZ.&lt;br /&gt;
&lt;br /&gt;
== Acertando o resolv.conf ==&lt;br /&gt;
Vamos modificar nosso /etc/resolv.conf para utilizar DNS externo. Sim você deve estar se perguntando em qual situação isso seria utilizado. Primeiro entenda que o Unbound não irá utilizar o DNS externo para fazer as consultas na Internet e sim, qualquer teste que você faça do servidor precisará apontar para o Unbound usando os IPs '''127.0.0.1''' ou '''::1'''. Faremos isso pela seguinte situação: imagine que o daemon unbound morreu mas você ainda continua com conectividade na Internet. Você conseguiria acessar qualquer local na Internet através do IP mas não através do hostname porque não conseguiria resolver nomes, seu unbound estaria fora do ar. Imagine ainda que você gostaria que seu servidor te avisasse do problema via Telegram ou e-mail. Por isso estamos utilizando um DNS externo no '''/etc/resolv.conf''', apenas para essas situações. Se você não quiser utilizar desse recurso, pode usar o '''127.0.0.1''' e '''::1''' no lugar.&lt;br /&gt;
 nameserver 8.8.8.8&lt;br /&gt;
 nameserver 8.8.4.4&lt;br /&gt;
 nameserver 2001:4860:4860::8888&lt;br /&gt;
&lt;br /&gt;
== Script de teste de recursividade ==&lt;br /&gt;
Estamos montando uma '''Rede de DNS Recursivo Anycast''', então é muito importante que você monitore essa rede para saber se algum node morreu e iniciar o troubleshooting, resolver o problema e levantar o sistema novamente. Tudo isso é importante mas o cliente não deve ficar esperando até você resolver o problema, seu sistema precisa ser inteligente o suficiente para se remover da Rede quando tiver um problema e se inserir novamente, quando o problema estiver sido solucionado. Se você montar uma Rede de DNS e um dos nodes apresentar algum problema, todos os clientes atendidos por aquele node migrarão automaticamente e transparentemente para outro '''DNS Recursivo Anycast''' mais próximo. Isso se chama '''disponibilidade'''.&lt;br /&gt;
&lt;br /&gt;
O script '''/root/scripts/checa_dns.sh''' abaixo tem a função de fazer os testes de recursividade e checar se o daemon do unbound continua rodando. Se algo acontecer, ele para o anúncio do '''10.10.10.10''' e '''10.10.9.9''' e retorna eles quando tudo estiver resolvido.&lt;br /&gt;
 # mkdir /root/scripts&lt;br /&gt;
&lt;br /&gt;
 #!/usr/bin/env bash&lt;br /&gt;
 #Script para teste de DNS v2.1&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 #Informe um domínio por linha:&lt;br /&gt;
 dominios_testar=(&lt;br /&gt;
 www.google.com&lt;br /&gt;
 www.terra.com.br&lt;br /&gt;
 www.uol.com.br&lt;br /&gt;
 www.globo.com&lt;br /&gt;
 www.facebook.com&lt;br /&gt;
 www.youtube.com&lt;br /&gt;
 www.twitch.com&lt;br /&gt;
 www.discord.com&lt;br /&gt;
 www.debian.org&lt;br /&gt;
 www.redhat.com&lt;br /&gt;
 )&lt;br /&gt;
 corte_taxa_falha=100 #Porcentagem de falha para executar uma ação&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 remove_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; != &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no description' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME morreu!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 adiciona_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; == &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'description LOOPBACKS' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME retornou do inferno!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
 if [ $? -ne 0 ]; then&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME morreu DNS mas tentando levantar!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    systemctl restart unbound&lt;br /&gt;
    systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
    if [ $? -ne 0 ]; then&lt;br /&gt;
       remove_ospf&lt;br /&gt;
       exit&lt;br /&gt;
    fi&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME servico DNS voltou mas tinha morrido!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 qt_falhas=0&lt;br /&gt;
 qt_total=&amp;quot;${#dominios_testar[@]}&amp;quot;&lt;br /&gt;
 echo &amp;quot;total_dominios: $qt_total&amp;quot;&lt;br /&gt;
 for site in &amp;quot;${dominios_testar[@]}&amp;quot;&lt;br /&gt;
 do&lt;br /&gt;
   unbound-control flush $site &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   resolver=&amp;quot;127.0.0.1&amp;quot;&lt;br /&gt;
   echo -e &amp;quot; - dominio $site - $resolver - \c&amp;quot;&lt;br /&gt;
   host $site $resolver &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   if [ $? -ne 0 ]; then&lt;br /&gt;
      ((qt_falhas++))&lt;br /&gt;
      echo -e &amp;quot;[Falhou]&amp;quot;&lt;br /&gt;
   else&lt;br /&gt;
      echo -e &amp;quot;[OK]&amp;quot;&lt;br /&gt;
   fi&lt;br /&gt;
 done&lt;br /&gt;
  &lt;br /&gt;
 taxa_falha=$((qt_falhas*100/qt_total))&lt;br /&gt;
 echo &amp;quot;Falhas $qt_falhas/$qt_total ($taxa_falha%)&amp;quot;&lt;br /&gt;
  &lt;br /&gt;
 if [ &amp;quot;$taxa_falha&amp;quot; -ge &amp;quot;$corte_taxa_falha&amp;quot; ]; then&lt;br /&gt;
    remove_ospf&lt;br /&gt;
    exit&lt;br /&gt;
 fi&lt;br /&gt;
 adiciona_ospf&lt;br /&gt;
Se rodarmos o script manualmente veremos isto:&lt;br /&gt;
 # /root/scripts/checa_dns.sh&lt;br /&gt;
 total_dominios: 10&lt;br /&gt;
  - dominio www.google.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.terra.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.uol.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.globo.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.facebook.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.youtube.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.twitch.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.discord.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.debian.org - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.redhat.com - 127.0.0.1 - [OK]&lt;br /&gt;
 Falhas 0/10 (0%)&lt;br /&gt;
Se acontecer 100% de falhas o script irá remover os anúncios do OSPF. Se o daemon do unbound morrer, ele tentará reiniciá-lo. Se tudo normalizar o script irá retornar os anúncios para o OSPF. Deixei comentado no script as partes que enviariam uma notificação para o Telegram. Existem diversas documentações sobre isso na Internet, eu mesmo tenho uma. Assim que eu publicar aqui, atualizo essa documentação e sinta-se à vontade de modificar como desejar.&lt;br /&gt;
 # chmod 700 /root/scripts/checa_dns.sh&lt;br /&gt;
Adicione a linha abaixo em seu '''/etc/crontab''':&lt;br /&gt;
 */1 *   * * *   root    /root/scripts/checa_dns.sh&lt;br /&gt;
&lt;br /&gt;
== Habilitando o DoH (&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; over HTTPS) - opcional ==&lt;br /&gt;
Para habilitar o '''DoH''' no Unbound é bem simples. O recurso do '''DoH''' vem para trazer mais segurança e privacidade para o usuário. É um recurso muito pouco utilizado ainda mas que seu cliente pode vir a pedir algum dia.&lt;br /&gt;
&lt;br /&gt;
Você precisará gerar certificados SSL legítimos e para isso você poderá usar o '''Let's Encrypt''' só que de uma forma não tão convencional.&lt;br /&gt;
&lt;br /&gt;
Na sequência vamos instalar o Let's Encrypt para gerarmos nosso certificado SSL:&lt;br /&gt;
 # apt install letsencrypt&lt;br /&gt;
Escolha um '''hostname''' para ser usado no nosso '''DoH''' e aponte ele no seu DNS Autoritativo para seus IPs 10.10.10.10 e 10.10.9.9. Aqui vamos usar o seguinte como exemplo: '''doh.brasilpeeringforum.org'''. Para gerarmos nosso certificado iremos usar o tipo '''DNS-01''', ele não necessita que tenhamos um servidor web rodando no servidor e nem tão pouco levanta um serviço na porta 80 para checar o hostname. Ele utiliza o DNS como validador e vai te solicitar que crie um registro '''CNAME''' no seu '''DNS Autoritativo''' para provar que você tem o controle sobre aquele hostname. Antes disso vamos instalar um programa em Python para podermos automatizar nossa renovação de certificado no futuro. Esse programa se encontra '''[https://github.com/joohoi/acme-dns-certbot-joohoi/raw/master/acme-dns-auth.py aqui]''' mas vou deixá-lo abaixo já modificado o interpretador.&lt;br /&gt;
&lt;br /&gt;
Crie o arquivo '''/etc/letsencrypt/acme-dns-auth.py''' com o conteúdo abaixo:&lt;br /&gt;
 #!/usr/bin/env python3&lt;br /&gt;
 import json&lt;br /&gt;
 import os&lt;br /&gt;
 import requests&lt;br /&gt;
 import sys&lt;br /&gt;
 &lt;br /&gt;
 ### EDIT THESE: Configuration values ###&lt;br /&gt;
 &lt;br /&gt;
 # URL to acme-dns instance&lt;br /&gt;
 ACMEDNS_URL = &amp;quot;&amp;lt;nowiki&amp;gt;https://auth.acme-dns.io&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
 # Path for acme-dns credential storage&lt;br /&gt;
 STORAGE_PATH = &amp;quot;/etc/letsencrypt/acmedns.json&amp;quot;&lt;br /&gt;
 # Whitelist for address ranges to allow the updates from&lt;br /&gt;
 # Example: ALLOW_FROM = [&amp;quot;192.168.10.0/24&amp;quot;, &amp;quot;::1/128&amp;quot;]&lt;br /&gt;
 ALLOW_FROM = []&lt;br /&gt;
 # Force re-registration. Overwrites the already existing acme-dns accounts.&lt;br /&gt;
 FORCE_REGISTER = False&lt;br /&gt;
 &lt;br /&gt;
 ###   DO NOT EDIT BELOW THIS POINT   ###&lt;br /&gt;
 ###         HERE BE DRAGONS          ###&lt;br /&gt;
 &lt;br /&gt;
 DOMAIN = os.environ[&amp;quot;CERTBOT_DOMAIN&amp;quot;]&lt;br /&gt;
 if DOMAIN.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
     DOMAIN = DOMAIN[2:]&lt;br /&gt;
 VALIDATION_DOMAIN = &amp;quot;_acme-challenge.&amp;quot;+DOMAIN&lt;br /&gt;
 VALIDATION_TOKEN = os.environ[&amp;quot;CERTBOT_VALIDATION&amp;quot;]&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 class AcmeDnsClient(object):&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
     Handles the communication with ACME-DNS API&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
     def __init__(self, acmedns_url):&lt;br /&gt;
         self.acmedns_url = acmedns_url&lt;br /&gt;
 &lt;br /&gt;
     def register_account(self, allowfrom):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Registers a new ACME-DNS account&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
         if allowfrom:&lt;br /&gt;
             # Include whitelisted networks to the registration call&lt;br /&gt;
             reg_data = {&amp;quot;allowfrom&amp;quot;: allowfrom}&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;,&lt;br /&gt;
                                 data=json.dumps(reg_data))&lt;br /&gt;
         else:&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;)&lt;br /&gt;
         if res.status_code == 201:&lt;br /&gt;
             # The request was successful&lt;br /&gt;
             return res.json()&lt;br /&gt;
         else:&lt;br /&gt;
             # Encountered an error&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to register a new acme-dns &amp;quot;&lt;br /&gt;
                    &amp;quot;account. HTTP status {}, Response body: {}&amp;quot;)&lt;br /&gt;
             print(msg.format(res.status_code, res.text))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def update_txt_record(self, account, txt):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Updates the TXT challenge record to ACME-DNS subdomain.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         update = {&amp;quot;subdomain&amp;quot;: account['subdomain'], &amp;quot;txt&amp;quot;: txt}&lt;br /&gt;
         headers = {&amp;quot;X-Api-User&amp;quot;: account['username'],&lt;br /&gt;
                    &amp;quot;X-Api-Key&amp;quot;: account['password'],&lt;br /&gt;
                    &amp;quot;Content-Type&amp;quot;: &amp;quot;application/json&amp;quot;}&lt;br /&gt;
         res = requests.post(self.acmedns_url+&amp;quot;/update&amp;quot;,&lt;br /&gt;
                             headers=headers,&lt;br /&gt;
                             data=json.dumps(update))&lt;br /&gt;
         if res.status_code == 200:&lt;br /&gt;
             # Successful update&lt;br /&gt;
             return&lt;br /&gt;
         else:&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to update TXT record in &amp;quot;&lt;br /&gt;
                    &amp;quot;acme-dns. \n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request headers:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request body:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response HTTP status: {}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response body: {}&amp;quot;)&lt;br /&gt;
             s_headers = json.dumps(headers, indent=2, sort_keys=True)&lt;br /&gt;
             s_update = json.dumps(update, indent=2, sort_keys=True)&lt;br /&gt;
             s_body = json.dumps(res.json(), indent=2, sort_keys=True)&lt;br /&gt;
             print(msg.format(s_headers, s_update, res.status_code, s_body))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
 class Storage(object):&lt;br /&gt;
     def __init__(self, storagepath):&lt;br /&gt;
         self.storagepath = storagepath&lt;br /&gt;
         self._data = self.load()&lt;br /&gt;
 &lt;br /&gt;
     def load(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Reads the storage content from the disk to a dict structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         data = dict()&lt;br /&gt;
         filedata = &amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             with open(self.storagepath, 'r') as fh:&lt;br /&gt;
                 filedata = fh.read()&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             if os.path.isfile(self.storagepath):&lt;br /&gt;
                 # Only error out if file exists, but cannot be read&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage file exists but cannot be read&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         try:&lt;br /&gt;
             data = json.loads(filedata)&lt;br /&gt;
         except ValueError:&lt;br /&gt;
             if len(filedata) &amp;gt; 0:&lt;br /&gt;
                 # Storage file is corrupted&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage JSON is corrupted&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         return data&lt;br /&gt;
 &lt;br /&gt;
     def save(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Saves the storage content to disk&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         serialized = json.dumps(self._data)&lt;br /&gt;
         try:&lt;br /&gt;
             with os.fdopen(os.open(self.storagepath,&lt;br /&gt;
                                    os.O_WRONLY | os.O_CREAT, 0o600), 'w') as fh:&lt;br /&gt;
                 fh.truncate()&lt;br /&gt;
                 fh.write(serialized)&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             print(&amp;quot;ERROR: Could not write storage file.&amp;quot;)&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def put(self, key, value):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Puts the configuration value to storage and sanitize it&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         # If wildcard domain, remove the wildcard part as this will use the&lt;br /&gt;
         # same validation record name as the base domain&lt;br /&gt;
         if key.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
             key = key[2:]&lt;br /&gt;
         self._data[key] = value&lt;br /&gt;
 &lt;br /&gt;
     def fetch(self, key):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Gets configuration value from storage&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             return self._data[key]&lt;br /&gt;
         except KeyError:&lt;br /&gt;
             return None&lt;br /&gt;
 &lt;br /&gt;
 if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
     # Init&lt;br /&gt;
     client = AcmeDnsClient(ACMEDNS_URL)&lt;br /&gt;
     storage = Storage(STORAGE_PATH)&lt;br /&gt;
 &lt;br /&gt;
     # Check if an account already exists in storage&lt;br /&gt;
     account = storage.fetch(DOMAIN)&lt;br /&gt;
     if FORCE_REGISTER or not account:&lt;br /&gt;
         # Create and save the new account&lt;br /&gt;
         account = client.register_account(ALLOW_FROM)&lt;br /&gt;
         storage.put(DOMAIN, account)&lt;br /&gt;
         storage.save()&lt;br /&gt;
 &lt;br /&gt;
         # Display the notification for the user to update the main zone&lt;br /&gt;
         msg = &amp;quot;Please add the following CNAME record to your main DNS zone:\n{}&amp;quot;&lt;br /&gt;
         cname = &amp;quot;{} CNAME {}.&amp;quot;.format(VALIDATION_DOMAIN, account[&amp;quot;fulldomain&amp;quot;])&lt;br /&gt;
         print(msg.format(cname))&lt;br /&gt;
 &lt;br /&gt;
     # Update the TXT record in acme-dns instance&lt;br /&gt;
     client.update_txt_record(account, VALIDATION_TOKEN)&lt;br /&gt;
&lt;br /&gt;
 # chmod +x /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
Usaremos a seguinte instrução para criar nosso certificado:&lt;br /&gt;
 # certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d doh.brasilpeeringforum.org&lt;br /&gt;
 Saving debug log to /var/log/letsencrypt/letsencrypt.log&lt;br /&gt;
 Plugins selected: Authenticator manual, Installer None&lt;br /&gt;
 Cert is due for renewal, auto-renewing...&lt;br /&gt;
 Renewing an existing certificate for doh.brasilpeeringforum.org&lt;br /&gt;
 Performing the following challenges:&lt;br /&gt;
 dns-01 challenge for doh.brasilpeeringforum.org&lt;br /&gt;
 Running manual-auth-hook command: /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
 Output from manual-auth-hook command acme-dns-auth.py:&lt;br /&gt;
 Please add the following CNAME record to your main DNS zone:&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
 &lt;br /&gt;
 Waiting for verification...&lt;br /&gt;
 &lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Challenges loaded. Press continue to submit to CA. Pass &amp;quot;-v&amp;quot; for more info about&lt;br /&gt;
 challenges.&lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Press Enter to Continue&lt;br /&gt;
Nesse momento você cria o registro '''CNAME''' no seu DNS Autoritativo conforme ele solicitou: '''_acme-challenge.doh.brasilpeeringforum.org IN CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.''' e somente depois de criado e checado no DNS, você pressiona o '''Enter''' para continuar. Você pode checar dessa forma:&lt;br /&gt;
 # host -t cname _acme-challenge.doh.brasilpeeringforum.org&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org is an alias for b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
Para que nosso certificado seja automaticamente renovado colocaremos no '''/etc/crontab''' a seguinte linha abaixo:&lt;br /&gt;
 00 00   1 * *   root    /usr/bin/certbot -q renew --deploy-hook &amp;quot;/usr/sbin/unbound-control reload_keep_cache&amp;quot;&lt;br /&gt;
Acima temos a instrução para renovação automática do certificado. Repare que você vai precisar também copiar esse certificado para seus outros servidores, escolha um servidor para manter o certificado sempre atualizado e crie um script que faça a mesma cópia remotamente para os outros servidores. O '''scp''' e o '''rsync''' são seus aliados nisso.&lt;br /&gt;
&lt;br /&gt;
=== Configurando o Unbound ===&lt;br /&gt;
Em nosso '''/etc/unbound/unbound.conf.d/local.conf''', adicionaremos no bloco &amp;quot;'''server:'''&amp;quot; o seguinte:&lt;br /&gt;
 interface: 10.10.10.10@443 &lt;br /&gt;
 interface: 10.10.9.9@443&lt;br /&gt;
 interface: fd00::10:10:10:10@443&lt;br /&gt;
 interface: fd00::10:10:9:9@443&lt;br /&gt;
 tls-service-key: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/privkey.pem&amp;quot; &lt;br /&gt;
 tls-service-pem: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/fullchain.pem&amp;quot;&lt;br /&gt;
Para usar o recurso do '''DoH''' você precisará habilitar o recurso no seu navegador e informar a URL. Vou colocar o exemplo do '''Google Chrome''': Digite '''chrome://settings/security?search=dns''' no seu Chrome e ative '''Usar DNS seguro''', selecione '''Personalizado''' e adicione nossa URL:&lt;br /&gt;
[[Arquivo:Doh bpf2.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Finalizando ==&lt;br /&gt;
Aqui finalizamos nosso projeto para uma Rede de DNS(s) Recursivos Anycast com Hyperlocal. Esse projeto é escalável, seguro, resiliente e você entregará muito mais qualidade de Internet para o seu cliente. Pare de entregar o '''8.8.8.8''' para os seus clientes, você está contribuindo para uma Internet mais lenta, sem a qualidade que o seu cliente merece. Investi meu tempo, que é muito pouco, para deixar esse documento para a comunidade, para você melhorar o seu ISP, para dar um UP! nele, então vamos começar 2023 com o pé direito. O que acha?&lt;br /&gt;
&lt;br /&gt;
Como prova de conceito, uma imagem abaixo onde temos uma Rede em produção de DNS(s) Recursivos Anycast e apontando exatamente o momento em que houve alguma situação que fez com que as queries de DNS, convergissem de um node para outro, de forma transparente e automática para o cliente. Podemos notar também que ao ser resolvido o problema, o tráfego retornou para o seu node correto:&lt;br /&gt;
[[Arquivo:Convergencia.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== KINDNS (Stands for Knowledge-Sharing and Instantiating Norms for DNS and Naming Security) ==&lt;br /&gt;
Achou que havia terminado? Agora que você tem a capacidade de montar uma '''Rede de DNS Recursivo''' com todas essas features acima, com todas as ferramentas que foram comentadas, o que acha de certificar o que fez?&lt;br /&gt;
&lt;br /&gt;
Assim como o [https://www.manrs.org/ MANRS] veio para certificar nosso sistema de roteamento na Internet, agora temos o [https://kindns.org/ KINDNS] para certificar que nossos sistemas de DNS estão bem feitos e dentro dos padrões de segurança. Existem '''7 ações''' que podem ser certificadas para nossos DNS Recursivos e estão aqui em https://kindns.org/shared-private-resolvers/. Com essa nossa documentação, se bem aplicada, você pode se candidatar ao KINDNS e ter seu ASN listado aqui https://kindns.org/participants/&lt;br /&gt;
&lt;br /&gt;
Obter e manter o '''MANRS''' e '''KINDNS''' demonstra seu compromisso com as Boas Práticas, contribui para termos uma '''Internet''' mais segura e te abre portas para novos negócios que possam exigir essas conformidades.&lt;br /&gt;
&lt;br /&gt;
Autor: [[Usuário:Gondim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Infraestrutura]]&lt;br /&gt;
__FORCARTDC__&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=4003</id>
		<title>DNS Recursivo Anycast Hyperlocal</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=4003"/>
		<updated>2025-12-26T13:38:10Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
==Introdução==&lt;br /&gt;
Você sabe como funciona a Internet? Essa é uma pergunta que meu amigo '''Thiago Ayub''' sempre faz aos seus candidatos à vagas de emprego e não importa o quanto tenham de experiência em '''Engenharia de Redes''', todos sempre travam nesse momento. Todos estão sempre prontos e preparados para resolver os problemas mais cabeludos em '''BGP''', '''OSPF''', '''MPLS''', etc mas travam com essa simples pergunta. Para contextualizar e visualizarmos melhor vamos nos atentar à imagem abaixo e uma explicação simplificada de como funciona:&lt;br /&gt;
[[Arquivo:Dns hierarquia.png|esquerda|commoldura]]&lt;br /&gt;
Tudo começa com um usuário sentado confortavelmente e querendo acessar um conteúdo disponível na Internet. Ele digita em seu navegador preferido a URL: '''&amp;lt;nowiki&amp;gt;https://wiki.brasilpeeringforum.org&amp;lt;/nowiki&amp;gt;''',&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;1)&amp;lt;/big&amp;gt;''' &amp;lt;big&amp;gt;O&amp;lt;/big&amp;gt; &amp;lt;big&amp;gt;navegador irá requisitar do '''DNS Recursivo''' utilizado pelo usuário, o '''endereço IP''' que responde pelo nome '''wiki.'''&amp;lt;/big&amp;gt;'''brasilpeeringforum.org'''&amp;lt;big&amp;gt;. Isso porque todos os acessos se dão na Internet através do '''endereço''' '''IP''' e não através do '''nome'''. Imaginem se tivéssemos que decorar os endereços IPs de todos os sites e serviços que quiséssemos acessar na Internet?&amp;lt;/big&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;big&amp;gt;'''2)''' Nosso DNS Recursivo checa se a informação consta em seu cache.&amp;lt;/big&amp;gt; Se a informação existir ela é devolvida ao navegador do usuário e aí este consegue acessar o site.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Do contrário o DNS Recursivo pergunta ao '''Root Server''' quem é o '''TLD (Top Level Domain)''' responsável para atender a requisição. &lt;br /&gt;
&lt;br /&gt;
'''4)''' O '''Root Server''' informa ao DNS Recursivo o endereço do '''TLD responsável'''. No Brasil o '''TLD''' responsável pelo '''.br''' seria o '''Registro.br'''.&lt;br /&gt;
&lt;br /&gt;
'''5)''' O DNS Recursivo pergunta ao '''TLD''' sobre '''wiki.brasilpeeringforum.org''' e este responde com os endereços IP dos '''DNS Autoritativos''' responsáveis pelo domínio '''brasilpeeringforum.org.'''&lt;br /&gt;
&lt;br /&gt;
'''6)''' O DNS Recursivo pergunta aos '''DNS Autoritativos''' pelo '''wiki.brasilpeeringforum.org''' e este responde com o '''endereço IP'''.&lt;br /&gt;
&lt;br /&gt;
'''7)''' Por último o DNS Recursivo devolve a informação para o navegador do usuário.&lt;br /&gt;
&lt;br /&gt;
Como que se dá a comunicação entre os '''DNS(s) Recursivos, Root Servers, TLDs''' e '''Autoritativos'''? Como que o navegador do usuário, após receber o IP do site, consegue chegar no servidor que tem o conteúdo? Isso só é possível devido ao protocolo chamado '''BGP (Border Gateway Protocol)''', todos os caminhos que conhecemos como rotas de destino, são anunciadas por milhares de participantes na '''Internet''' conhecidos como '''AS (Autonomous System)''', esses participantes se interligam para disponibilizar conteúdos e acessos pelo mundo aos milhares de usuários. É uma imensa rede colaborativa formada por Empresas, Universidades, Governos e todos que queiram se interconectar. Percebam que sem o '''BGP''', que serve de caminho para chegarmos nos conteúdos e sem o '''DNS (Domain Name System)''' para traduzir o nome para o endereço IP, a '''Internet''' não funcionaria e por isso precisamos cuidar muito bem desses dois serviços.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Mas não acaba por aí. O '''DNS Recursivo''' tem um papel muito importante para o Provedor de Internet e que envolve segurança, qualidade de acesso à Internet e a disponibilidade do serviço entregue ao cliente. Quando bem configurado acelera as consultas dos acessos graças ao seu cache interno, mas para que isso seja percebido pelo assinante, é necessário que esteja o mais próximo possível do seu cliente.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Um erro que destrói a qualidade do nosso serviço ==&lt;br /&gt;
Um erro muito comum que muitas operadoras cometem é utilizar DNS Recursivo externo, como o '''8.8.8.8''', '''1.1.1.1''' e outros, para seus clientes. Quanto mais próximo dos seus clientes, mais qualidade de serviço estará entregando a eles. Conteúdos serão entregues mais rapidamente pois serão resolvidos e armazenados em caches locais e não consultados remotamente na Internet. Para falar mais sobre isso, te convido leitor desse documento, que assista essa palestra do '''Thiago Ayub''' no '''GTER 51/GTS 37''' (2022) '''8.888 MOTIVOS PARA NÃO USAR DNS RECURSIVO EXTERNO EM SEU AS''': https://www.youtube.com/watch?v=Rsvpu5uF2Io&lt;br /&gt;
&lt;br /&gt;
== Objetivo ==&lt;br /&gt;
O objetivo desta documentação não é te ensinar tudo sobre '''DNS''', '''BGP''', '''OSPF''' e nem tão pouco sobre GNU/Linux e sim te mostrar um exemplo de servidor DNS Recursivo implementado pensando em segurança, qualidade e resiliência. Usaremos em todas as nossas documentações o [https://www.debian.org/ Debian GNU/Linux], por ser uma distribuição que considero uma obra de arte criada por uma enorme comunidade séria, com vasta experiência de anos, qualidade no empacotamento dos programas, estável e com uma equipe de segurança excelente e ativa. Caso você leitor, utilize alguma outra distribuição GNU/Linux, todo conteúdo apresentado aqui pode ser aplicado em outras distros, desde que respeitando as particularidades de cada uma.&lt;br /&gt;
&lt;br /&gt;
Aqui construiremos um sistema do tipo '''Anycast''', ou seja, terás o serviço rodando em diversas localidades da sua Rede utilizando o mesmo endereçamento IP e que atenderá seu cliente mais próximo. Em caso de falhas, seus clientes automaticamente e de forma transparente continuarão consultando o DNS mais próximo deles. Para que ele funcione dessa forma você precisará ter uma '''Rede OSPF''' implementada no seu Provedor Internet ou algum outro protocolo como por exemplo o '''ISIS,''' mas esse documento não irá abordar o '''ISIS'''. Também utilizaremos o '''Hyperlocal''' como recurso adicional para gerar algumas proteções de segurança e velocidade na resposta relacionada aos servidores de DNS Raiz da Internet.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
Para exemplificar nosso servidor de DNS Recursivo, usaremos como base das explicações um diagrama demonstrando o uso do DNS Recursivo em uma Rede fictícia. Adotaremos IPs privados e reservados para demonstrar todo o ambiente do Provedor de Internet.&lt;br /&gt;
[[Arquivo:Recursivo99.png|esquerda|miniaturadaimagem|695x695px]]&lt;br /&gt;
Nesse diagrama podemos observar alguns detalhes técnicos como por exemplo: existem '''3 servidores de DNS Recursivo''' posicionados em locais diferentes, que poderiam estar em bairros diferentes e até em cidades diferentes. Em cada servidor teremos '''2 loopbacks''' com os IPs:&lt;br /&gt;
&lt;br /&gt;
'''10.10.10.10/32 - fd00::10:10:10:10/128'''&lt;br /&gt;
&lt;br /&gt;
'''10.10.9.9/32 - fd00::10:10:9:9/128'''&lt;br /&gt;
&lt;br /&gt;
Esses IPs serão entregues pelos concentradores '''PPPoE''' ou '''IPoE''' ('''BNG''') para seus clientes como '''DNS primário''' e '''secundário'''. Podemos usar IPs privados como DNS primário e secundário em um ambiente real? Sim podemos, desde que não sejam IPs que possam ter problemas com as redes privadas dos clientes. Ex.: rede do cliente usando '''192.168.0.0/24'''. Se entregarmos o DNS sendo '''192.168.0.10''' e '''192.168.0.20''' teremos problemas e o cliente ficará sem Internet, porque '''192.168.0.10''' e '''192.168.0.20''' fazem parte da rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
Agora entregando '''10.10.10.10,''' '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9''' não teríamos problemas com a rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
'''Motivos para usarmos IPs privados:'''&lt;br /&gt;
* O principal motivo está relacionado com a segurança, uma vez que sendo um IP privado, não pode sofrer ataques DDoS direcionados diretamente para ele, vindos da Internet.&lt;br /&gt;
* Nem mesmo o cliente da sua rede conhece os '''IPs públicos''' utilizados para recursividade na Internet.&lt;br /&gt;
* Memorizar os IPs '''10.10.10.10''' e '''10.10.9.9''' é tão fácil quanto memorizar o '''8.8.8.8''' e o '''1.1.1.1'''. Mais fácil para o seu técnico guardar essa informação e utilizar onde for necessário.&lt;br /&gt;
Cada servidor DNS Recursivo possui um '''IPv4 público''', aqui representado por '''198.18.x.x/27''' e um '''IPv6 global''' representado por um IP dentro do prefixo '''2001:db8::/32'''. Cada servidor precisa ter os seus próprios IPs e são através destes IPs que as consultas de DNS serão realizadas na Internet.&lt;br /&gt;
&lt;br /&gt;
Nessa topologia usando '''Anycast''', o cliente será sempre atendido pelo '''DNS Recursivo''' mais próximo, desde que os pesos no '''OSPF''' estejam ajustados corretamente.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
== Dados do servidor ==&lt;br /&gt;
Podemos utilizar um sistema virtualizado ou não. Sistemas virtualizados são bem vindos pois são mais simples quando precisamos fazer backups, levantar outros sistemas sem complicações e se precisarmos restaurar rapidamente algum sistema que ficou indisponível por algum motivo. A configuração abaixo tem capacidade para atender algo em torno a '''50.000 assinantes ou mais'''. O DNS Recursivo é um serviço que pode ser utilizado até mesmo em um '''Raspberry Pi''' e atender operações pequenas, nesse caso com o intuito de economizar energia e espaço. Nosso foco aqui é montar uma rede de '''DNS Recursivo Anycast com HyperLocal'''. Como comentei acima o servidor deve ficar o mais próximo dos clientes para termos a '''menor latência possível''' e '''sempre menor que 5ms''' entre o cliente e o servidor.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!CPU&lt;br /&gt;
!Memória&lt;br /&gt;
!Disco&lt;br /&gt;
!Sistema&lt;br /&gt;
|-&lt;br /&gt;
|2.4Ghz 8 cores&lt;br /&gt;
|16G DDR4&lt;br /&gt;
|30G&lt;br /&gt;
|Debian 13 amd64 (Trixie)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Softwares utilizados ==&lt;br /&gt;
* Debian 13 amd64 (Trixie) instalação mínima.&lt;br /&gt;
&lt;br /&gt;
* [https://frrouting.org/ FRRouting].&lt;br /&gt;
* Unbound.&lt;br /&gt;
* Chrony (NTP/NTS).&lt;br /&gt;
* Shell script em bash.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades que teremos ==&lt;br /&gt;
* Sistema em Anycast.&lt;br /&gt;
* Hyperlocal.&lt;br /&gt;
* Controle de acesso por &amp;lt;abbr&amp;gt;ACL&amp;lt;/abbr&amp;gt;.&lt;br /&gt;
* RPZ (Response Policy Zone).&lt;br /&gt;
* Bloqueio de consultas do tipo ANY.&lt;br /&gt;
* QNAME minimization habilitado. (habilitado por default no Unbound)&lt;br /&gt;
* Recursividade em IPv4 e IPv6.&lt;br /&gt;
* DNSSEC habilitado.&lt;br /&gt;
* &amp;lt;abbr&amp;gt;DoH (DNS&amp;lt;/abbr&amp;gt; over HTTPS) habilitado.&lt;br /&gt;
&lt;br /&gt;
== Monitoramento ==&lt;br /&gt;
O monitoramento é algo bem específico e não é o foco deste documento mas é extremamente importante que você monitore seus servidores de DNS por alguma ferramenta como o Zabbix. Aqui mostrarei apenas como enviar as informações para o Zabbix. Algumas coisas que você deveria monitorar nos servidores de DNS Recursivo:&lt;br /&gt;
* Serviço do unbound parou.&lt;br /&gt;
* Perda de pacotes.&lt;br /&gt;
* Latência alta de pacotes.&lt;br /&gt;
* Lentidão na resolução de queries.&lt;br /&gt;
* CPU alta.&lt;br /&gt;
* Load alto.&lt;br /&gt;
* Memória com uso alto.&lt;br /&gt;
* Disco com pouco espaço.&lt;br /&gt;
* Queda brusca nas queries.&lt;br /&gt;
* A recursividade parou de funcionar.&lt;br /&gt;
* A recursividade voltou a funcionar.&lt;br /&gt;
Este abaixo é um exemplo de monitoramento de um sistema de DNS Recursivo que atende 50.000 assinantes:&lt;br /&gt;
[[Arquivo:Grafana dns.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Configurando a Rede ==&lt;br /&gt;
Nossa documentação será baseada no diagrama apresentado acima e por isso configuraremos apenas um dos três servidores, porque os outros serão configurados da mesma forma, só que com dados diferentes. Para tanto assumirei que já temos um sistema Debian instalado com o mínimo de pacotes e somente com sshd, para que possamos acessar remotamente mais tarde. '''Não instale um ambiente gráfico no servidor''', você não deve querer fazer isso por diversos motivos e os principais: primeiro porque não é um Desktop e segundo porque o ambiente gráfico devoraria toda a memória com recursos que não seriam úteis aqui.&lt;br /&gt;
&lt;br /&gt;
Em '''/etc/network/interfaces''' deixaremos assim:&lt;br /&gt;
 # This file describes the network interfaces available on your system&lt;br /&gt;
 # and how to activate them. For more information, see interfaces(5).&lt;br /&gt;
  &lt;br /&gt;
 source /etc/network/interfaces.d/*&lt;br /&gt;
  &lt;br /&gt;
 # The loopback network interface&lt;br /&gt;
 auto lo&lt;br /&gt;
 iface lo inet loopback&lt;br /&gt;
  &lt;br /&gt;
 auto lo:0&lt;br /&gt;
 iface lo:0 inet static&lt;br /&gt;
       address 10.10.10.10/32&lt;br /&gt;
  &lt;br /&gt;
 auto lo:1&lt;br /&gt;
 iface lo:1 inet static&lt;br /&gt;
       address 10.10.9.9/32&lt;br /&gt;
 &lt;br /&gt;
 auto lo:2&lt;br /&gt;
 iface lo:2 inet6 static&lt;br /&gt;
       address fd00::10:10:10:10/128&lt;br /&gt;
 &lt;br /&gt;
 auto lo:3&lt;br /&gt;
 iface lo:3 inet6 static&lt;br /&gt;
       address fd00::10:10:9:9/128&lt;br /&gt;
  &lt;br /&gt;
 # The primary network interface&lt;br /&gt;
 auto ens18&lt;br /&gt;
 iface ens18 inet static&lt;br /&gt;
         address 198.18.1.10/27&lt;br /&gt;
         gateway 198.18.1.1&lt;br /&gt;
  &lt;br /&gt;
 iface ens18 inet6 static&lt;br /&gt;
         address 2001:db8::faca:198:18:1:10/64&lt;br /&gt;
         gateway 2001:db8::faca:198:18:1:1&lt;br /&gt;
  &lt;br /&gt;
 # The secondary network interface&lt;br /&gt;
 auto ens18:0&lt;br /&gt;
 iface ens18:0 inet static&lt;br /&gt;
         address 172.16.0.6/30&lt;br /&gt;
Nesse cenário temos as duas '''loopbacks''' com os IPs '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10''' e '''fd00::10:10:9:9''' que serão anunciados via OSPF para a rede e serem entregues aos clientes via BNG. Os IPs '''198.18.1.10''' e '''2001:db8::faca:198:18:1:10''' serão usados para fazerem a recursividade na Internet tanto em IPv4 quanto em IPv6. Esses IPs não devem ser divulgados para clientes; os IPs públicos são dedicados apenas para essa finalidade.&lt;br /&gt;
&lt;br /&gt;
== Configuração dos repositórios Debian ==&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://security.debian.org/debian-security/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-security&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-updates&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian-backports.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-backports&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
&lt;br /&gt;
 # rm /etc/apt/sources.list&lt;br /&gt;
Após a configuração vamos instalar alguns pacotes necessários e outros úteis:&lt;br /&gt;
 # apt update &amp;amp;&amp;amp; apt full-upgrade&lt;br /&gt;
 # apt install net-tools nftables htop iotop sipcalc tcpdump curl gnupg rsync wget host dnsutils mtr-tiny bmon sudo tmux whois ethtool dnstop&lt;br /&gt;
&lt;br /&gt;
== Fazendo algum tuning no sistema ==&lt;br /&gt;
Em '''/etc/sysctl.d/100-tuning.conf''' adicionamos essas instruções:&lt;br /&gt;
 net.core.rmem_max = 2147483647&lt;br /&gt;
 net.core.wmem_max = 2147483647&lt;br /&gt;
 net.ipv4.tcp_rmem = 4096 87380 2147483647&lt;br /&gt;
 net.ipv4.tcp_wmem = 4096 65536 2147483647&lt;br /&gt;
 net.netfilter.nf_conntrack_buckets = 512000&lt;br /&gt;
 net.netfilter.nf_conntrack_max = 4096000&lt;br /&gt;
 vm.swappiness=10&lt;br /&gt;
Estamos fazendo algumas melhorias de memória, algumas relacionadas a '''conntrack''' porque se for usar um filtro de pacotes stateful, como o '''Netfilter/IPTables''' ou '''Netfilter/NFTables''', o valor default da tabela é pequeno e dependendo da situação, se estourar essa tabela, as consultas de DNS terão problemas também. O DNS Recursivo não deve ficar aberto para qualquer um na Internet, ele deve ser liberado apenas para seus clientes. Podemos fazer através das ACLs do Unbound e pelo filtro de pacotes. O último parâmetro diz respeito ao uso de swap, por padrão o Debian permite o uso de swap após 40% do uso da memória, nesse caso estamos dizendo para o sistema usar o swap com 90% de uso da memória.&lt;br /&gt;
&lt;br /&gt;
Precisamos adicionar o módulo '''nf_conntrack''' em '''/etc/modules''' para que seja carregado em tempo de boot, senão os parâmetros de '''conntrack''' que colocamos em '''/etc/sysctl.conf''' não serão carregados.&lt;br /&gt;
 # echo nf_conntrack &amp;gt;&amp;gt; /etc/modules&lt;br /&gt;
 # modprobe nf_conntrack&lt;br /&gt;
 # sysctl -p&lt;br /&gt;
&lt;br /&gt;
== Instalando o FRRouting ==&lt;br /&gt;
O FRRouting é o programa que usaremos para fazer os anúncios das nossas loopbacks via OSPF. Nesse documento usaremos a versão 10.x:&lt;br /&gt;
 # apt install frr frr-doc frr-pythontools&lt;br /&gt;
Aconselho depois de instalar os pacotes, marcá-los para não atualizar juntamente com os demais pacotes, isso é para evitar de ocorrer alguma atualização no FRRouting, que torne o serviço instável por algum motivo. Não que isso vá ocorrer, mas é melhor fazer essa atualização quando realmente for necessário.&lt;br /&gt;
 # apt-mark hold frr frr-doc frr-pythontools&lt;br /&gt;
Após esse comando acima, o sistema manterá a instalação original do pacote intacta. Para desbloquear basta executar o comando abaixo:&lt;br /&gt;
 # apt-mark unhold frr frr-doc frr-pythontools&lt;br /&gt;
&lt;br /&gt;
== Removendo o APPARMOR ==&lt;br /&gt;
O '''APPARMOR''' às vezes causa mais problemas que solução e se não for fazer uma completa configuração nele, é melhor desabilitá-lo. Para fazer isso efetivamente, o procedimento é esse abaixo:&lt;br /&gt;
 # mkdir -p /etc/default/grub.d&lt;br /&gt;
 # echo 'GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;$GRUB_CMDLINE_LINUX_DEFAULT apparmor=0&amp;quot;' | tee /etc/default/grub.d/apparmor.cfg&lt;br /&gt;
 # update-grub&lt;br /&gt;
 # reboot&lt;br /&gt;
&lt;br /&gt;
== Instalando o Unbound ==&lt;br /&gt;
Nesse momento ainda não iremos configurar o Unbound, apenas instalar o pacote e acertar o ambiente. Vamos instalar o unbound do backports porque este já possui suporte ao DoH que veremos mais à frente.&lt;br /&gt;
 # apt install unbound dns-root-data unbound-anchor&lt;br /&gt;
 # mkdir -p /var/log/unbound&lt;br /&gt;
 # touch /var/log/unbound/unbound.log&lt;br /&gt;
 # chown -R unbound:unbound /var/log/unbound/&lt;br /&gt;
 # systemctl restart unbound&lt;br /&gt;
Configurando o logrotate:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/logrotate.d/unbound&lt;br /&gt;
 /var/log/unbound/unbound.log {&lt;br /&gt;
     rotate 5&lt;br /&gt;
     weekly&lt;br /&gt;
     postrotate&lt;br /&gt;
         unbound-control log_reopen&lt;br /&gt;
     endscript&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
Reiniciando o serviço:&lt;br /&gt;
 # systemctl restart logrotate.service&lt;br /&gt;
&lt;br /&gt;
== Desabilitando THP (Transparente Huge Pages) em arquitetura AMD64 ==&lt;br /&gt;
No Debian o '''THP''' vem habilitado como '''always''' e o '''unbound''' por trabalhar bastante com alterações do cache em memória, isso pode acabar causando um consumo crescente de uso de RAM sem necessidade. É uma boa prática desabilitá-lo com os passos abaixo:&lt;br /&gt;
&lt;br /&gt;
https://github.com/NLnetLabs/unbound/issues/724&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/systemd/system/disable-thp.service&lt;br /&gt;
 [Unit]&lt;br /&gt;
 Description=Desabilita Transparent Huge Pages (THP)&lt;br /&gt;
 After=network.target&lt;br /&gt;
 &lt;br /&gt;
 [Service]&lt;br /&gt;
 Type=oneshot&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled&amp;quot;&lt;br /&gt;
 RemainAfterExit=yes&lt;br /&gt;
 &lt;br /&gt;
 [Install]&lt;br /&gt;
 WantedBy=multi-user.target&lt;br /&gt;
 EOF&lt;br /&gt;
Acima configuramos o serviço '''disable-thp.service''' para desabilitar o '''THP''' e abaixo habilitamos no '''systemd''' e iniciamos:&lt;br /&gt;
 # systemctl daemon-reload&lt;br /&gt;
 # systemctl enable --now disable-thp&lt;br /&gt;
&lt;br /&gt;
== Preparando o monitoramento do seu DNS Recursivo ==&lt;br /&gt;
O monitoramento do seu DNS Recursivo é muito importante e para isso vamos usar um '''template para Zabbix''', que modifiquei juntamente com o seu shell script e que enviará os dados para o seu Zabbix server via '''zabbix-sender'''. O projeto original está aqui '''https://github.com/jeftedelima/Unbound-DNS&amp;lt;nowiki/&amp;gt;.''' O xml alterado está aqui '''https://github.com/gondimcodes/template_zabbix_dns_unbound'''. Embora seja antigo é perfeitamente importável no Zabbix 6.0, por exemplo.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;nowiki/&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Teremos um shell script que você precisará colocar no seu '''/etc/crontab'''. No exemplo abaixo assumi que o shell script está em '''/root/scripts'''. De 5 em 5 minutos os dados serão enviados para o seu Zabbix server.&lt;br /&gt;
 */5 * * * *     root    /root/scripts/unboundSend.sh '''IP_zabbix_server''' '''nome_do_host''' 1&amp;gt; /dev/null&lt;br /&gt;
Na linha acima, troque o '''IP_zabbix_server''' pelo '''IP do seu servidor Zabbix''' e o '''nome_do_host''' pelo '''hostname''' '''do seu DNS Recursivo'''. Você precisará instalar o pacote '''zabbix-sender''' no seu DNS Recursivo pois ele será usado para enviar os dados para o Zabbix server.&lt;br /&gt;
&lt;br /&gt;
Abaixo o '''unboundSend.sh''' também alterado com inclusão de mais dados:&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 #       @Jefte de Lima Ferreira&lt;br /&gt;
 #       jeftedelima at gmail dot com&lt;br /&gt;
 #       CRON Example&lt;br /&gt;
 #       Contributor: Marcelo Gondim - gondim at gmail dot com&lt;br /&gt;
 #       */5   **** root sh /home/dir/unboundSend.sh 192.168.10.1 Unbound 1&amp;gt; /dev/null&lt;br /&gt;
  &lt;br /&gt;
 if [ -z ${1} ] || [ -z ${2} ] ; then&lt;br /&gt;
         echo &amp;quot;You need to specify the IP address of zabbix server and hostname of your DNS Unbound on zabbix&amp;quot;&lt;br /&gt;
         echo &amp;quot;Usage example: ./unboundSend.sh 192.168.10.1 UnboundServer&amp;quot;&lt;br /&gt;
         exit 1&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 # ZABBIX_SERVER IP&lt;br /&gt;
 IP_ZABBIX=$1&lt;br /&gt;
 # NAME Unbound on Zabbix&lt;br /&gt;
 NAME_HOST=$2&lt;br /&gt;
 DIR_TEMP=/var/tmp/&lt;br /&gt;
 FILE=&amp;quot;${DIR_TEMP}dump_unbound_control_stats.txt&amp;quot;&lt;br /&gt;
 unbound-control stats &amp;gt; ${FILE}&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_NUM_QUERIES=$(cat ${FILE} | grep -w 'total.num.queries' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEHITS=$(cat ${FILE} | grep -w 'total.num.cachehits' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEMISS=$(cat ${FILE} | grep -w 'total.num.cachemiss' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_PREFETCH=$(cat ${FILE} | grep -w 'total.num.prefetch' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_RECURSIVEREPLIES=$(cat ${FILE} | grep -w 'total.num.recursivereplies' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_REQ_MAX=$(cat ${FILE} | grep -w 'total.requestlist.max' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_AVG=$(cat ${FILE} | grep -w 'total.requestlist.avg' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_OVERWRITTEN=$(cat ${FILE} | grep -w 'total.requestlist.overwritten' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_EXCEEDED=$(cat ${FILE} | grep -w 'total.requestlist.exceeded' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_ALL=$(cat ${FILE} | grep -w 'total.requestlist.current.all' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_USER=$(cat ${FILE} | grep -w 'total.requestlist.current.user' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_TCPUSAGE=$(cat ${FILE} | grep -w 'total.tcpusage' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_QUERY_TYPE_A=$(cat ${FILE} | grep -w 'num.query.type.A' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NS=$(cat ${FILE} | grep -w 'num.query.type.NS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_MX=$(cat ${FILE} | grep -w 'num.query.type.MX' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TXT=$(cat ${FILE} | grep -w 'num.query.type.TXT' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_PTR=$(cat ${FILE} | grep -w 'num.query.type.PTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_AAAA=$(cat ${FILE} | grep -w 'num.query.type.AAAA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SRV=$(cat ${FILE} | grep -w 'num.query.type.SRV' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SOA=$(cat ${FILE} | grep -w 'num.query.type.SOA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HTTPS=$(cat ${FILE} | grep -w 'num.query.type.HTTPS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TYPE0=$(cat ${FILE} | grep -w 'num.query.type.TYPE0' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_CNAME=$(cat ${FILE} | grep -w 'num.query.type.CNAME' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_WKS=$(cat ${FILE} | grep -w 'num.query.type.WKS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HINFO=$(cat ${FILE} | grep -w 'num.query.type.HINFO' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_X25=$(cat ${FILE} | grep -w 'num.query.type.X25' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NAPTR=$(cat ${FILE} | grep -w 'num.query.type.NAPTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DS=$(cat ${FILE} | grep -w 'num.query.type.DS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DNSKEY=$(cat ${FILE} | grep -w 'num.query.type.DNSKEY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TLSA=$(cat ${FILE} | grep -w 'num.query.type.TLSA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SVCB=$(cat ${FILE} | grep -w 'num.query.type.SVCB' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SPF=$(cat ${FILE} | grep -w 'num.query.type.SPF' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_ANY=$(cat ${FILE} | grep -w 'num.query.type.ANY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_OTHER=$(cat ${FILE} | grep -w 'num.query.type.other' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_ANSWER_RCODE_NOERROR=$(cat ${FILE} | grep -w 'num.answer.rcode.NOERROR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_NXDOMAIN=$(cat ${FILE} | grep -w 'num.answer.rcode.NXDOMAIN' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_SERVFAIL=$(cat ${FILE} | grep -w 'num.answer.rcode.SERVFAIL' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_REFUSED=$(cat ${FILE} | grep -w 'num.answer.rcode.REFUSED' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_nodata=$(cat ${FILE} | grep -w 'num.answer.rcode.nodata' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_secure=$(cat ${FILE} | grep -w 'num.answer.secure' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 #       Sending info to zabbix_server.&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.queries -o $(( ${TOTAL_NUM_QUERIES:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachehits -o $(( ${TOTAL_NUM_CACHEHITS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachemiss -o $(( ${TOTAL_NUM_CACHEMISS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.prefetch -o $(( ${TOTAL_NUM_PREFETCH:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.recursivereplies -o $(( ${TOTAL_NUM_RECURSIVEREPLIES:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.max -o $(( ${TOTAL_REQ_MAX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.avg -o $(( ${TOTAL_REQ_AVG:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.overwritten -o $(( ${TOTAL_REQ_OVERWRITTEN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.exceeded -o $(( ${TOTAL_REQ_EXCEEDED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.all -o $(( ${TOTAL_REQ_CURRENT_ALL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.user -o $(( ${TOTAL_REQ_CURRENT_USER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.tcpusage -o $(( ${TOTAL_TCPUSAGE:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.a -o $(( ${NUM_QUERY_TYPE_A:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ns -o $(( ${NUM_QUERY_TYPE_NS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.mx -o $(( ${NUM_QUERY_TYPE_MX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.txt -o $(( ${NUM_QUERY_TYPE_TXT:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ptr -o $(( ${NUM_QUERY_TYPE_PTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.aaaa -o $(( ${NUM_QUERY_TYPE_AAAA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.srv -o $(( ${NUM_QUERY_TYPE_SRV:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.soa -o $(( ${NUM_QUERY_TYPE_SOA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.https -o $(( ${NUM_QUERY_TYPE_HTTPS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.type0 -o $(( ${NUM_QUERY_TYPE_TYPE0:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.cname -o $(( ${NUM_QUERY_TYPE_CNAME:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.wks -o $(( ${NUM_QUERY_TYPE_WKS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.hinfo -o $(( ${NUM_QUERY_TYPE_HINFO:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.X25 -o $(( ${NUM_QUERY_TYPE_X25:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.naptr -o $(( ${NUM_QUERY_TYPE_NAPTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ds -o $(( ${NUM_QUERY_TYPE_DS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.dnskey -o $(( ${NUM_QUERY_TYPE_DNSKEY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.tlsa -o $(( ${NUM_QUERY_TYPE_TLSA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.svcb -o $(( ${NUM_QUERY_TYPE_SVCB:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.spf -o $(( ${NUM_QUERY_TYPE_SPF:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.any -o $(( ${NUM_QUERY_TYPE_ANY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.other -o $(( ${NUM_QUERY_TYPE_OTHER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NOERROR -o $(( ${NUM_ANSWER_RCODE_NOERROR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NXDOMAIN -o $(( ${NUM_ANSWER_RCODE_NXDOMAIN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.SERVFAIL -o $(( ${NUM_ANSWER_RCODE_SERVFAIL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.REFUSED -o $(( ${NUM_ANSWER_RCODE_REFUSED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.nodata -o $(( ${NUM_ANSWER_RCODE_nodata:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.secure -o $(( ${NUM_ANSWER_secure:-0} / 300 ))&lt;br /&gt;
No Zabbix será registrado dados como esses abaixo e posteriormente pode ser montado um Grafana com eles:&lt;br /&gt;
[[Arquivo:Zabbix dns01.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns02.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns03.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns04.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Mantendo a hora certa ==&lt;br /&gt;
Vamos instalar agora o Chrony para manter a data e hora certas no sistema:&lt;br /&gt;
 # apt install chrony&lt;br /&gt;
Após a instalação do Chrony edite o arquivo /etc/chrony/chrony.conf, comente e a linha abaixo e adicione seus servidores NTP. Caso não tenha servidores NTP, estou colocando os do NIC.br aqui.&lt;br /&gt;
 #pool 2.debian.pool.ntp.org iburst&lt;br /&gt;
 server a.st1.ntp.br iburst nts&lt;br /&gt;
 server b.st1.ntp.br iburst nts&lt;br /&gt;
 server c.st1.ntp.br iburst nts&lt;br /&gt;
 server d.st1.ntp.br iburst nts&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart chronyd.service&lt;br /&gt;
Cheque com o '''chronyc''' se os servidores estão OK:&lt;br /&gt;
 # chronyc sourcestats&lt;br /&gt;
 Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev&lt;br /&gt;
 ==============================================================================&lt;br /&gt;
 a.st1.ntp.br               10   5  155m     -0.027      0.030    -71us    51us&lt;br /&gt;
 b.st1.ntp.br               11   7  344m     +0.068      0.079    +23ms   382us&lt;br /&gt;
 c.st1.ntp.br                6   3  344m     +0.026      0.037   -124us    92us&lt;br /&gt;
 200.20.186.76               9   3  138m     -0.022      0.031   +172us    42us&lt;br /&gt;
&lt;br /&gt;
 # chronyc sources&lt;br /&gt;
 MS Name/IP address         Stratum Poll Reach LastRx Last sample&lt;br /&gt;
 ===============================================================================&lt;br /&gt;
 ^* a.st1.ntp.br                  1  10   377   588   +487us[ +397us] +/-   12ms&lt;br /&gt;
 ^- b.st1.ntp.br                  2  10   377   830    +23ms[  +23ms] +/-   49ms&lt;br /&gt;
 ^+ c.st1.ntp.br                  2  10    21  1038   -147us[ -242us] +/-   17ms&lt;br /&gt;
 ^+ 200.20.186.76                 1  10   377  1032   +381us[ +285us] +/-   15ms&lt;br /&gt;
&lt;br /&gt;
== Configurando o FRRouting ==&lt;br /&gt;
Nesse ponto iremos configurar o '''FRRouting''' para enviar os IPs das '''loopbacks''' e o '''/30''' para o nosso PE do diagrama. Em '''/etc/frr/daemons''' habilite o parâmetro conforme abaixo:&lt;br /&gt;
 ospfd=yes&lt;br /&gt;
 ospf6d=yes&lt;br /&gt;
Edite o arquivo '''/etc/frr/frr.conf''' e deixe com o conteúdo abaixo, para ficar conforme nosso diagrama do projeto. Apenas troque '''&amp;lt;SENHA&amp;gt;''' por uma senha para fechar o OSPF com mais segurança. Essa senha deve ser usada dos dois lados.&lt;br /&gt;
 frr version 10.3&lt;br /&gt;
 frr defaults traditional&lt;br /&gt;
 hostname dns-recursivo-01&lt;br /&gt;
 log syslog informational&lt;br /&gt;
 no ip forwarding&lt;br /&gt;
 no ipv6 forwarding&lt;br /&gt;
 service integrated-vtysh-config&lt;br /&gt;
 !&lt;br /&gt;
 interface ens18&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf message-digest-key 5 md5 &amp;lt;SENHA&amp;gt;&lt;br /&gt;
  ip ospf network point-to-point&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 network point-to-point&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 interface lo&lt;br /&gt;
  description LOOPBACKS&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf passive&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 passive&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf&lt;br /&gt;
  ospf router-id 172.16.0.6&lt;br /&gt;
  area 0.0.0.0 authentication message-digest&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf6&lt;br /&gt;
  ospf6 router-id 172.16.0.6&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart frr.service&lt;br /&gt;
Cheque se está tudo OK com o OSPF e verifique no PE se está recebendo os prefixos anunciados.&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL&lt;br /&gt;
 172.16.0.5     1 Full/-          10m49s            35.310s 172.16.0.5   ens18:172.16.0.6                  0     0     0&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri    DeadTime    State/IfState         Duration I/F[State]&lt;br /&gt;
 172.16.0.5       1    00:00:30     Full/PointToPoint 25d22:53:47 ens18[PointToPoint]&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor detail'&lt;br /&gt;
 &lt;br /&gt;
  Neighbor 172.16.0.5, interface address 172.16.0.5&lt;br /&gt;
     In the area 0.0.0.0 via interface ens18&lt;br /&gt;
     Neighbor priority is 1, State is Full/-, 5 state changes&lt;br /&gt;
     Most recent state change statistics:&lt;br /&gt;
       Progressive change 21w3d15h ago&lt;br /&gt;
     DR is 0.0.0.0, BDR is 0.0.0.0&lt;br /&gt;
     Options 18 *|-|-|EA|-|-|E|-&lt;br /&gt;
     Dead timer due in 34.685s&lt;br /&gt;
     Database Summary List 0&lt;br /&gt;
     Link State Request List 0&lt;br /&gt;
     Link State Retransmission List 0&lt;br /&gt;
     Thread Inactivity Timer on&lt;br /&gt;
     Thread Database Description Retransmision off&lt;br /&gt;
     Thread Link State Request Retransmission on&lt;br /&gt;
     Thread Link State Update Retransmission on&lt;br /&gt;
 &lt;br /&gt;
     Graceful restart Helper info:&lt;br /&gt;
       Graceful Restart HELPER Status : None&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor detail'&lt;br /&gt;
  Neighbor 172.16.0.5%ens18&lt;br /&gt;
     Area 0.0.0.0 via interface ens18 (ifindex 4)&lt;br /&gt;
     His IfIndex: 60 Link-local address: fe80::469b:c1ff:fed6:43ee&lt;br /&gt;
     State Full for a duration of 25d22:57:14&lt;br /&gt;
     His choice of DR/BDR 0.0.0.0/0.0.0.0, Priority 1&lt;br /&gt;
     DbDesc status: Master SeqNum: 0xb94b0000&lt;br /&gt;
     Summary-List: 0 LSAs&lt;br /&gt;
     Request-List: 0 LSAs&lt;br /&gt;
     Retrans-List: 0 LSAs&lt;br /&gt;
     0 Pending LSAs for DbDesc in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSReq in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSAck in Time 00:00:00 [thread off]&lt;br /&gt;
     Authentication header not present&lt;br /&gt;
&lt;br /&gt;
== Configurando o Unbound ==&lt;br /&gt;
Abaixo a configuração que usaremos nos servidores atentando para o detalhe do '''num-threads''', esse deve ter o valor igual ao número de CPUs do servidor.&lt;br /&gt;
&lt;br /&gt;
Também os IPs utilizados em '''outgoing-interface''' que serão diferentes em cada servidor, esses serão os IPs usados para '''recursividade'''. Consulte o manual do Unbound para obter mais informações sobre cada parâmetro listado na configuração.&lt;br /&gt;
&lt;br /&gt;
O tuning no Unbound pode ser alterado conforme abaixo:&lt;br /&gt;
 num-threads = nº CPUs&lt;br /&gt;
 so-reuseport = yes&lt;br /&gt;
 *-slabs = potência de 2 próximo ao num-threads&lt;br /&gt;
 msg-cache-size = 1g (quantidade de memória pra usar de cache)&lt;br /&gt;
 rrset-cache-size = 2 * msg-cache-size&lt;br /&gt;
 outgoing-range = 8192&lt;br /&gt;
 num-queries-per-thread = 4096&lt;br /&gt;
 so-rcvbuf e so-sndbuf = 4m ou 8m para servidores com muita requisição&lt;br /&gt;
Agora vamos criar nosso arquivo de configuração base em '''/etc/unbound/unbound.conf.d/local.conf''':&lt;br /&gt;
 server:&lt;br /&gt;
         verbosity: 1&lt;br /&gt;
         statistics-interval: 0&lt;br /&gt;
         statistics-cumulative: no&lt;br /&gt;
         extended-statistics: yes&lt;br /&gt;
         num-threads: 8&lt;br /&gt;
         serve-expired: yes&lt;br /&gt;
         interface: 127.0.0.1&lt;br /&gt;
         interface: 10.10.10.10&lt;br /&gt;
         interface: 10.10.9.9&lt;br /&gt;
         interface: 172.16.0.6&lt;br /&gt;
         interface: fd00::10:10:10:10&lt;br /&gt;
         interface: fd00::10:10:9:9&lt;br /&gt;
         interface: ::1&lt;br /&gt;
         interface-automatic: no&lt;br /&gt;
         outgoing-interface: 198.18.1.10&lt;br /&gt;
         outgoing-interface: 2001:db8::faca:198:18:1:10&lt;br /&gt;
         outgoing-range: 8192&lt;br /&gt;
         outgoing-num-tcp: 1024&lt;br /&gt;
         incoming-num-tcp: 2048&lt;br /&gt;
         so-rcvbuf: 4m&lt;br /&gt;
         so-sndbuf: 4m&lt;br /&gt;
         so-reuseport: yes&lt;br /&gt;
         edns-buffer-size: 1232&lt;br /&gt;
         msg-cache-size: 512m&lt;br /&gt;
         msg-cache-slabs: 4&lt;br /&gt;
         num-queries-per-thread: 4096&lt;br /&gt;
         rrset-cache-size: 1g&lt;br /&gt;
         rrset-cache-slabs: 4&lt;br /&gt;
         infra-cache-slabs: 4&lt;br /&gt;
         do-ip4: yes&lt;br /&gt;
         do-ip6: yes&lt;br /&gt;
         do-udp: yes&lt;br /&gt;
         do-tcp: yes&lt;br /&gt;
         chroot: &amp;quot;&amp;quot;&lt;br /&gt;
         username: &amp;quot;unbound&amp;quot;&lt;br /&gt;
         directory: &amp;quot;/etc/unbound&amp;quot;&lt;br /&gt;
         logfile: &amp;quot;/var/log/unbound/unbound.log&amp;quot;&lt;br /&gt;
         use-syslog: no&lt;br /&gt;
         log-time-ascii: yes&lt;br /&gt;
         log-queries: no&lt;br /&gt;
         pidfile: &amp;quot;/var/run/unbound.pid&amp;quot;&lt;br /&gt;
         root-hints: &amp;quot;/usr/share/dns/root.hints&amp;quot;&lt;br /&gt;
         hide-identity: yes&lt;br /&gt;
         hide-version: yes&lt;br /&gt;
         unwanted-reply-threshold: 10000000&lt;br /&gt;
         prefetch: yes&lt;br /&gt;
         prefetch-key: yes&lt;br /&gt;
         rrset-roundrobin: yes&lt;br /&gt;
         minimal-responses: yes&lt;br /&gt;
         module-config: &amp;quot;respip validator iterator&amp;quot;&lt;br /&gt;
         val-clean-additional: yes&lt;br /&gt;
         val-log-level: 1&lt;br /&gt;
         key-cache-slabs: 4&lt;br /&gt;
         deny-any: yes&lt;br /&gt;
         cache-min-ttl: 60&lt;br /&gt;
         key-cache-size: 128m&lt;br /&gt;
         neg-cache-size: 64m&lt;br /&gt;
         cache-max-ttl: 86400&lt;br /&gt;
         infra-cache-numhosts: 100000&lt;br /&gt;
         access-control: 198.18.0.0/22 allow&lt;br /&gt;
         access-control: 2001:db8::/32 allow&lt;br /&gt;
  &lt;br /&gt;
 rpz:&lt;br /&gt;
   name: rpz.block.host.local.zone&lt;br /&gt;
   zonefile: /etc/unbound/rpz.block.hosts.zone&lt;br /&gt;
   rpz-action-override: nxdomain&lt;br /&gt;
  &lt;br /&gt;
 python:&lt;br /&gt;
  &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;.&amp;quot;&lt;br /&gt;
     master: &amp;quot;b.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;c.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;d.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;f.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;g.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;k.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/root.zone&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;arpa.&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/arpa.zone&amp;quot;&lt;br /&gt;
No parâmetro '''interface''' colocamos os IPs que serão usados para consulta dos clientes como o '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9'''. Ali repare que coloquei também o IP privado '''172.16.0.6''', isso porque cada servidor terá o seu IP privado e este deve ser usado pelo seu sistema de monitoramento para checar cada servidor. No '''outgoing-interface''' teremos os IPs, tanto '''IPv4''' quanto '''IPv6''', para que seja feita a recursividade na Internet utilizando eles. Não tem '''IPv6''' ainda na sua rede? Dê uma olhada nesse artigo. Outro parâmetro importante é o '''access-control''' e é através dele que liberamos os prefixos IP para consultarem no nosso DNS Recursivo. No exemplo estou liberando todo o prefixo '''198.18.0.0/22''' e o prefixo '''2001:db8::/32'''. Além da ACL no Unbound, recomendo que crie um filtro de pacotes com iptables ou nftables protegendo seu sistema e liberando as portas '''53/UDP''', '''53/TCP,'''  '''443/TCP e 853/TCP''' apenas para seus clientes. Falarei sobre a '''443/TCP e 853/TCP''' mais para frente nessa mesma documentação.&lt;br /&gt;
&lt;br /&gt;
Agora criaremos o arquivo '''RPZ''' ('''Response Policy Zones'''). Esse arquivo contém os sites que serão bloqueados via '''&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; Recursivo'''. São aqueles sites que às vezes você recebe um Ofício da Justiça solicitando o bloqueio deles. Não entrarei no mérito da efetividade desses bloqueios, porque muitos de vocês sabem que tecnicamente, existem formas de se fazer um bypass através desses bloqueios. Contudo vamos deixar nosso ambiente preparado para esses bloqueios e por isso crie o arquivo '''/etc/unbound/rpz.block.hosts.zone''' com esse conteúdo de exemplo:&lt;br /&gt;
 $TTL 2h&lt;br /&gt;
 @ IN SOA localhost. root.localhost. (2 6h 1h 1w 2h)&lt;br /&gt;
   IN NS  localhost.&lt;br /&gt;
 ; RPZ manual block hosts&lt;br /&gt;
 *.josedascoves.com CNAME .&lt;br /&gt;
 josedascoves.com CNAME .&lt;br /&gt;
No exemplo acima estamos bloqueando qualquer consulta de DNS para '''josedascoves.com''' ou qualquer coisa '''.josedascoves.com'''.&lt;br /&gt;
&lt;br /&gt;
Para testar podemos fazer assim do próprio servidor:&lt;br /&gt;
 # host josedascoves.com ::1&lt;br /&gt;
 Using domain server:&lt;br /&gt;
 Name: ::1&lt;br /&gt;
 Address: ::1#53&lt;br /&gt;
 Aliases:&lt;br /&gt;
 &lt;br /&gt;
 Host josedascoves.com not found: 3(NXDOMAIN)&lt;br /&gt;
Se a resposta for '''NXDOMAIN''' então está funcionando o bloqueio. Para incluir novos bloqueios basta adicionar os domínios, um abaixo do outro, conforme o exemplo que coloquei no arquivo RPZ.&lt;br /&gt;
&lt;br /&gt;
== Acertando o resolv.conf ==&lt;br /&gt;
Vamos modificar nosso /etc/resolv.conf para utilizar DNS externo. Sim você deve estar se perguntando em qual situação isso seria utilizado. Primeiro entenda que o Unbound não irá utilizar o DNS externo para fazer as consultas na Internet e sim, qualquer teste que você faça do servidor precisará apontar para o Unbound usando os IPs '''127.0.0.1''' ou '''::1'''. Faremos isso pela seguinte situação: imagine que o daemon unbound morreu mas você ainda continua com conectividade na Internet. Você conseguiria acessar qualquer local na Internet através do IP mas não através do hostname porque não conseguiria resolver nomes, seu unbound estaria fora do ar. Imagine ainda que você gostaria que seu servidor te avisasse do problema via Telegram ou e-mail. Por isso estamos utilizando um DNS externo no '''/etc/resolv.conf''', apenas para essas situações. Se você não quiser utilizar desse recurso, pode usar o '''127.0.0.1''' e '''::1''' no lugar.&lt;br /&gt;
 nameserver 8.8.8.8&lt;br /&gt;
 nameserver 8.8.4.4&lt;br /&gt;
 nameserver 2001:4860:4860::8888&lt;br /&gt;
&lt;br /&gt;
== Script de teste de recursividade ==&lt;br /&gt;
Estamos montando uma '''Rede de DNS Recursivo Anycast''', então é muito importante que você monitore essa rede para saber se algum node morreu e iniciar o troubleshooting, resolver o problema e levantar o sistema novamente. Tudo isso é importante mas o cliente não deve ficar esperando até você resolver o problema, seu sistema precisa ser inteligente o suficiente para se remover da Rede quando tiver um problema e se inserir novamente, quando o problema estiver sido solucionado. Se você montar uma Rede de DNS e um dos nodes apresentar algum problema, todos os clientes atendidos por aquele node migrarão automaticamente e transparentemente para outro '''DNS Recursivo Anycast''' mais próximo. Isso se chama '''disponibilidade'''.&lt;br /&gt;
&lt;br /&gt;
O script '''/root/scripts/checa_dns.sh''' abaixo tem a função de fazer os testes de recursividade e checar se o daemon do unbound continua rodando. Se algo acontecer, ele para o anúncio do '''10.10.10.10''' e '''10.10.9.9''' e retorna eles quando tudo estiver resolvido.&lt;br /&gt;
 # mkdir /root/scripts&lt;br /&gt;
&lt;br /&gt;
 #!/usr/bin/env bash&lt;br /&gt;
 #Script para teste de DNS v2.1&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 #Informe um domínio por linha:&lt;br /&gt;
 dominios_testar=(&lt;br /&gt;
 www.google.com&lt;br /&gt;
 www.terra.com.br&lt;br /&gt;
 www.uol.com.br&lt;br /&gt;
 www.globo.com&lt;br /&gt;
 www.facebook.com&lt;br /&gt;
 www.youtube.com&lt;br /&gt;
 www.twitch.com&lt;br /&gt;
 www.discord.com&lt;br /&gt;
 www.debian.org&lt;br /&gt;
 www.redhat.com&lt;br /&gt;
 )&lt;br /&gt;
 corte_taxa_falha=100 #Porcentagem de falha para executar uma ação&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 remove_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; != &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no description' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME morreu!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 adiciona_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; == &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'description LOOPBACKS' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME retornou do inferno!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
 if [ $? -ne 0 ]; then&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME morreu DNS mas tentando levantar!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    systemctl restart unbound&lt;br /&gt;
    systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
    if [ $? -ne 0 ]; then&lt;br /&gt;
       remove_ospf&lt;br /&gt;
       exit&lt;br /&gt;
    fi&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME servico DNS voltou mas tinha morrido!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 qt_falhas=0&lt;br /&gt;
 qt_total=&amp;quot;${#dominios_testar[@]}&amp;quot;&lt;br /&gt;
 echo &amp;quot;total_dominios: $qt_total&amp;quot;&lt;br /&gt;
 for site in &amp;quot;${dominios_testar[@]}&amp;quot;&lt;br /&gt;
 do&lt;br /&gt;
   unbound-control flush $site &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   resolver=&amp;quot;127.0.0.1&amp;quot;&lt;br /&gt;
   echo -e &amp;quot; - dominio $site - $resolver - \c&amp;quot;&lt;br /&gt;
   host $site $resolver &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   if [ $? -ne 0 ]; then&lt;br /&gt;
      ((qt_falhas++))&lt;br /&gt;
      echo -e &amp;quot;[Falhou]&amp;quot;&lt;br /&gt;
   else&lt;br /&gt;
      echo -e &amp;quot;[OK]&amp;quot;&lt;br /&gt;
   fi&lt;br /&gt;
 done&lt;br /&gt;
  &lt;br /&gt;
 taxa_falha=$((qt_falhas*100/qt_total))&lt;br /&gt;
 echo &amp;quot;Falhas $qt_falhas/$qt_total ($taxa_falha%)&amp;quot;&lt;br /&gt;
  &lt;br /&gt;
 if [ &amp;quot;$taxa_falha&amp;quot; -ge &amp;quot;$corte_taxa_falha&amp;quot; ]; then&lt;br /&gt;
    remove_ospf&lt;br /&gt;
    exit&lt;br /&gt;
 fi&lt;br /&gt;
 adiciona_ospf&lt;br /&gt;
Se rodarmos o script manualmente veremos isto:&lt;br /&gt;
 # /root/scripts/checa_dns.sh&lt;br /&gt;
 total_dominios: 10&lt;br /&gt;
  - dominio www.google.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.terra.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.uol.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.globo.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.facebook.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.youtube.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.twitch.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.discord.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.debian.org - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.redhat.com - 127.0.0.1 - [OK]&lt;br /&gt;
 Falhas 0/10 (0%)&lt;br /&gt;
Se acontecer 100% de falhas o script irá remover os anúncios do OSPF. Se o daemon do unbound morrer, ele tentará reiniciá-lo. Se tudo normalizar o script irá retornar os anúncios para o OSPF. Deixei comentado no script as partes que enviariam uma notificação para o Telegram. Existem diversas documentações sobre isso na Internet, eu mesmo tenho uma. Assim que eu publicar aqui, atualizo essa documentação e sinta-se à vontade de modificar como desejar.&lt;br /&gt;
 # chmod 700 /root/scripts/checa_dns.sh&lt;br /&gt;
Adicione a linha abaixo em seu '''/etc/crontab''':&lt;br /&gt;
 */1 *   * * *   root    /root/scripts/checa_dns.sh&lt;br /&gt;
&lt;br /&gt;
== Habilitando o DoH (&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; over HTTPS) - opcional ==&lt;br /&gt;
Para habilitar o '''DoH''' no Unbound é bem simples. O recurso do '''DoH''' vem para trazer mais segurança e privacidade para o usuário. É um recurso muito pouco utilizado ainda mas que seu cliente pode vir a pedir algum dia.&lt;br /&gt;
&lt;br /&gt;
Você precisará gerar certificados SSL legítimos e para isso você poderá usar o '''Let's Encrypt''' só que de uma forma não tão convencional.&lt;br /&gt;
&lt;br /&gt;
Na sequência vamos instalar o Let's Encrypt para gerarmos nosso certificado SSL:&lt;br /&gt;
 # apt install letsencrypt&lt;br /&gt;
Escolha um '''hostname''' para ser usado no nosso '''DoH''' e aponte ele no seu DNS Autoritativo para seus IPs 10.10.10.10 e 10.10.9.9. Aqui vamos usar o seguinte como exemplo: '''doh.brasilpeeringforum.org'''. Para gerarmos nosso certificado iremos usar o tipo '''DNS-01''', ele não necessita que tenhamos um servidor web rodando no servidor e nem tão pouco levanta um serviço na porta 80 para checar o hostname. Ele utiliza o DNS como validador e vai te solicitar que crie um registro '''CNAME''' no seu '''DNS Autoritativo''' para provar que você tem o controle sobre aquele hostname. Antes disso vamos instalar um programa em Python para podermos automatizar nossa renovação de certificado no futuro. Esse programa se encontra '''[https://github.com/joohoi/acme-dns-certbot-joohoi/raw/master/acme-dns-auth.py aqui]''' mas vou deixá-lo abaixo já modificado o interpretador.&lt;br /&gt;
&lt;br /&gt;
Crie o arquivo '''/etc/letsencrypt/acme-dns-auth.py''' com o conteúdo abaixo:&lt;br /&gt;
 #!/usr/bin/env python3&lt;br /&gt;
 import json&lt;br /&gt;
 import os&lt;br /&gt;
 import requests&lt;br /&gt;
 import sys&lt;br /&gt;
 &lt;br /&gt;
 ### EDIT THESE: Configuration values ###&lt;br /&gt;
 &lt;br /&gt;
 # URL to acme-dns instance&lt;br /&gt;
 ACMEDNS_URL = &amp;quot;&amp;lt;nowiki&amp;gt;https://auth.acme-dns.io&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
 # Path for acme-dns credential storage&lt;br /&gt;
 STORAGE_PATH = &amp;quot;/etc/letsencrypt/acmedns.json&amp;quot;&lt;br /&gt;
 # Whitelist for address ranges to allow the updates from&lt;br /&gt;
 # Example: ALLOW_FROM = [&amp;quot;192.168.10.0/24&amp;quot;, &amp;quot;::1/128&amp;quot;]&lt;br /&gt;
 ALLOW_FROM = []&lt;br /&gt;
 # Force re-registration. Overwrites the already existing acme-dns accounts.&lt;br /&gt;
 FORCE_REGISTER = False&lt;br /&gt;
 &lt;br /&gt;
 ###   DO NOT EDIT BELOW THIS POINT   ###&lt;br /&gt;
 ###         HERE BE DRAGONS          ###&lt;br /&gt;
 &lt;br /&gt;
 DOMAIN = os.environ[&amp;quot;CERTBOT_DOMAIN&amp;quot;]&lt;br /&gt;
 if DOMAIN.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
     DOMAIN = DOMAIN[2:]&lt;br /&gt;
 VALIDATION_DOMAIN = &amp;quot;_acme-challenge.&amp;quot;+DOMAIN&lt;br /&gt;
 VALIDATION_TOKEN = os.environ[&amp;quot;CERTBOT_VALIDATION&amp;quot;]&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 class AcmeDnsClient(object):&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
     Handles the communication with ACME-DNS API&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
     def __init__(self, acmedns_url):&lt;br /&gt;
         self.acmedns_url = acmedns_url&lt;br /&gt;
 &lt;br /&gt;
     def register_account(self, allowfrom):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Registers a new ACME-DNS account&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
         if allowfrom:&lt;br /&gt;
             # Include whitelisted networks to the registration call&lt;br /&gt;
             reg_data = {&amp;quot;allowfrom&amp;quot;: allowfrom}&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;,&lt;br /&gt;
                                 data=json.dumps(reg_data))&lt;br /&gt;
         else:&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;)&lt;br /&gt;
         if res.status_code == 201:&lt;br /&gt;
             # The request was successful&lt;br /&gt;
             return res.json()&lt;br /&gt;
         else:&lt;br /&gt;
             # Encountered an error&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to register a new acme-dns &amp;quot;&lt;br /&gt;
                    &amp;quot;account. HTTP status {}, Response body: {}&amp;quot;)&lt;br /&gt;
             print(msg.format(res.status_code, res.text))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def update_txt_record(self, account, txt):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Updates the TXT challenge record to ACME-DNS subdomain.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         update = {&amp;quot;subdomain&amp;quot;: account['subdomain'], &amp;quot;txt&amp;quot;: txt}&lt;br /&gt;
         headers = {&amp;quot;X-Api-User&amp;quot;: account['username'],&lt;br /&gt;
                    &amp;quot;X-Api-Key&amp;quot;: account['password'],&lt;br /&gt;
                    &amp;quot;Content-Type&amp;quot;: &amp;quot;application/json&amp;quot;}&lt;br /&gt;
         res = requests.post(self.acmedns_url+&amp;quot;/update&amp;quot;,&lt;br /&gt;
                             headers=headers,&lt;br /&gt;
                             data=json.dumps(update))&lt;br /&gt;
         if res.status_code == 200:&lt;br /&gt;
             # Successful update&lt;br /&gt;
             return&lt;br /&gt;
         else:&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to update TXT record in &amp;quot;&lt;br /&gt;
                    &amp;quot;acme-dns. \n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request headers:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request body:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response HTTP status: {}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response body: {}&amp;quot;)&lt;br /&gt;
             s_headers = json.dumps(headers, indent=2, sort_keys=True)&lt;br /&gt;
             s_update = json.dumps(update, indent=2, sort_keys=True)&lt;br /&gt;
             s_body = json.dumps(res.json(), indent=2, sort_keys=True)&lt;br /&gt;
             print(msg.format(s_headers, s_update, res.status_code, s_body))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
 class Storage(object):&lt;br /&gt;
     def __init__(self, storagepath):&lt;br /&gt;
         self.storagepath = storagepath&lt;br /&gt;
         self._data = self.load()&lt;br /&gt;
 &lt;br /&gt;
     def load(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Reads the storage content from the disk to a dict structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         data = dict()&lt;br /&gt;
         filedata = &amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             with open(self.storagepath, 'r') as fh:&lt;br /&gt;
                 filedata = fh.read()&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             if os.path.isfile(self.storagepath):&lt;br /&gt;
                 # Only error out if file exists, but cannot be read&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage file exists but cannot be read&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         try:&lt;br /&gt;
             data = json.loads(filedata)&lt;br /&gt;
         except ValueError:&lt;br /&gt;
             if len(filedata) &amp;gt; 0:&lt;br /&gt;
                 # Storage file is corrupted&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage JSON is corrupted&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         return data&lt;br /&gt;
 &lt;br /&gt;
     def save(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Saves the storage content to disk&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         serialized = json.dumps(self._data)&lt;br /&gt;
         try:&lt;br /&gt;
             with os.fdopen(os.open(self.storagepath,&lt;br /&gt;
                                    os.O_WRONLY | os.O_CREAT, 0o600), 'w') as fh:&lt;br /&gt;
                 fh.truncate()&lt;br /&gt;
                 fh.write(serialized)&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             print(&amp;quot;ERROR: Could not write storage file.&amp;quot;)&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def put(self, key, value):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Puts the configuration value to storage and sanitize it&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         # If wildcard domain, remove the wildcard part as this will use the&lt;br /&gt;
         # same validation record name as the base domain&lt;br /&gt;
         if key.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
             key = key[2:]&lt;br /&gt;
         self._data[key] = value&lt;br /&gt;
 &lt;br /&gt;
     def fetch(self, key):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Gets configuration value from storage&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             return self._data[key]&lt;br /&gt;
         except KeyError:&lt;br /&gt;
             return None&lt;br /&gt;
 &lt;br /&gt;
 if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
     # Init&lt;br /&gt;
     client = AcmeDnsClient(ACMEDNS_URL)&lt;br /&gt;
     storage = Storage(STORAGE_PATH)&lt;br /&gt;
 &lt;br /&gt;
     # Check if an account already exists in storage&lt;br /&gt;
     account = storage.fetch(DOMAIN)&lt;br /&gt;
     if FORCE_REGISTER or not account:&lt;br /&gt;
         # Create and save the new account&lt;br /&gt;
         account = client.register_account(ALLOW_FROM)&lt;br /&gt;
         storage.put(DOMAIN, account)&lt;br /&gt;
         storage.save()&lt;br /&gt;
 &lt;br /&gt;
         # Display the notification for the user to update the main zone&lt;br /&gt;
         msg = &amp;quot;Please add the following CNAME record to your main DNS zone:\n{}&amp;quot;&lt;br /&gt;
         cname = &amp;quot;{} CNAME {}.&amp;quot;.format(VALIDATION_DOMAIN, account[&amp;quot;fulldomain&amp;quot;])&lt;br /&gt;
         print(msg.format(cname))&lt;br /&gt;
 &lt;br /&gt;
     # Update the TXT record in acme-dns instance&lt;br /&gt;
     client.update_txt_record(account, VALIDATION_TOKEN)&lt;br /&gt;
&lt;br /&gt;
 # chmod +x /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
Usaremos a seguinte instrução para criar nosso certificado:&lt;br /&gt;
 # certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d doh.brasilpeeringforum.org&lt;br /&gt;
 Saving debug log to /var/log/letsencrypt/letsencrypt.log&lt;br /&gt;
 Plugins selected: Authenticator manual, Installer None&lt;br /&gt;
 Cert is due for renewal, auto-renewing...&lt;br /&gt;
 Renewing an existing certificate for doh.brasilpeeringforum.org&lt;br /&gt;
 Performing the following challenges:&lt;br /&gt;
 dns-01 challenge for doh.brasilpeeringforum.org&lt;br /&gt;
 Running manual-auth-hook command: /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
 Output from manual-auth-hook command acme-dns-auth.py:&lt;br /&gt;
 Please add the following CNAME record to your main DNS zone:&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
 &lt;br /&gt;
 Waiting for verification...&lt;br /&gt;
 &lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Challenges loaded. Press continue to submit to CA. Pass &amp;quot;-v&amp;quot; for more info about&lt;br /&gt;
 challenges.&lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Press Enter to Continue&lt;br /&gt;
Nesse momento você cria o registro '''CNAME''' no seu DNS Autoritativo conforme ele solicitou: '''_acme-challenge.doh.brasilpeeringforum.org IN CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.''' e somente depois de criado e checado no DNS, você pressiona o '''Enter''' para continuar. Você pode checar dessa forma:&lt;br /&gt;
 # host -t cname _acme-challenge.doh.brasilpeeringforum.org&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org is an alias for b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
Para que nosso certificado seja automaticamente renovado colocaremos no '''/etc/crontab''' a seguinte linha abaixo:&lt;br /&gt;
 00 00   1 * *   root    /usr/bin/certbot -q renew --deploy-hook &amp;quot;/usr/sbin/unbound-control reload_keep_cache&amp;quot;&lt;br /&gt;
Acima temos a instrução para renovação automática do certificado. Repare que você vai precisar também copiar esse certificado para seus outros servidores, escolha um servidor para manter o certificado sempre atualizado e crie um script que faça a mesma cópia remotamente para os outros servidores. O '''scp''' e o '''rsync''' são seus aliados nisso.&lt;br /&gt;
&lt;br /&gt;
=== Configurando o Unbound ===&lt;br /&gt;
Em nosso '''/etc/unbound/unbound.conf.d/local.conf''', adicionaremos no bloco &amp;quot;'''server:'''&amp;quot; o seguinte:&lt;br /&gt;
 interface: 10.10.10.10@443 &lt;br /&gt;
 interface: 10.10.9.9@443&lt;br /&gt;
 interface: fd00::10:10:10:10@443&lt;br /&gt;
 interface: fd00::10:10:9:9@443&lt;br /&gt;
 tls-service-key: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/privkey.pem&amp;quot; &lt;br /&gt;
 tls-service-pem: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/fullchain.pem&amp;quot;&lt;br /&gt;
Para usar o recurso do '''DoH''' você precisará habilitar o recurso no seu navegador e informar a URL. Vou colocar o exemplo do '''Google Chrome''': Digite '''chrome://settings/security?search=dns''' no seu Chrome e ative '''Usar DNS seguro''', selecione '''Personalizado''' e adicione nossa URL:&lt;br /&gt;
[[Arquivo:Doh bpf2.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Finalizando ==&lt;br /&gt;
Aqui finalizamos nosso projeto para uma Rede de DNS(s) Recursivos Anycast com Hyperlocal. Esse projeto é escalável, seguro, resiliente e você entregará muito mais qualidade de Internet para o seu cliente. Pare de entregar o '''8.8.8.8''' para os seus clientes, você está contribuindo para uma Internet mais lenta, sem a qualidade que o seu cliente merece. Investi meu tempo, que é muito pouco, para deixar esse documento para a comunidade, para você melhorar o seu ISP, para dar um UP! nele, então vamos começar 2023 com o pé direito. O que acha?&lt;br /&gt;
&lt;br /&gt;
Como prova de conceito, uma imagem abaixo onde temos uma Rede em produção de DNS(s) Recursivos Anycast e apontando exatamente o momento em que houve alguma situação que fez com que as queries de DNS, convergissem de um node para outro, de forma transparente e automática para o cliente. Podemos notar também que ao ser resolvido o problema, o tráfego retornou para o seu node correto:&lt;br /&gt;
[[Arquivo:Convergencia.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== KINDNS (Stands for Knowledge-Sharing and Instantiating Norms for DNS and Naming Security) ==&lt;br /&gt;
Achou que havia terminado? Agora que você tem a capacidade de montar uma '''Rede de DNS Recursivo''' com todas essas features acima, com todas as ferramentas que foram comentadas, o que acha de certificar o que fez?&lt;br /&gt;
&lt;br /&gt;
Assim como o [https://www.manrs.org/ MANRS] veio para certificar nosso sistema de roteamento na Internet, agora temos o [https://kindns.org/ KINDNS] para certificar que nossos sistemas de DNS estão bem feitos e dentro dos padrões de segurança. Existem '''7 ações''' que podem ser certificadas para nossos DNS Recursivos e estão aqui em https://kindns.org/shared-private-resolvers/. Com essa nossa documentação, se bem aplicada, você pode se candidatar ao KINDNS e ter seu ASN listado aqui https://kindns.org/participants/&lt;br /&gt;
&lt;br /&gt;
Obter e manter o '''MANRS''' e '''KINDNS''' demonstra seu compromisso com as Boas Práticas, contribui para termos uma '''Internet''' mais segura e te abre portas para novos negócios que possam exigir essas conformidades.&lt;br /&gt;
&lt;br /&gt;
Autor: [[Usuário:Gondim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Infraestrutura]]&lt;br /&gt;
__FORCARTDC__&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4001</id>
		<title>Usuário:Gondim</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4001"/>
		<updated>2025-12-24T12:14:12Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Marcelo Gondim da Cunha'''&lt;br /&gt;
[[Arquivo:Gondim paisagem.jpg|esquerda|commoldura]]&lt;br /&gt;
&lt;br /&gt;
'''Contribuições e trabalhos:'''&lt;br /&gt;
&lt;br /&gt;
* Administração de Sistemas Unix-Like desde 1996.&lt;br /&gt;
* Consultor na Conectiva S/A - Unidade Rio em 2000.&lt;br /&gt;
** Autor do projeto TuxFrw - https://github.com/gondimcodes/tuxfrw e https://github.com/gondimcodes/tuxfrw-nft&lt;br /&gt;
* Administração de sistemas BSD pela FreeBSD Brasil em 2010.&lt;br /&gt;
* Direção do AS53135 - Nettel Telecomunicações entre 2003 e 2021 atingindo a marca de 41.000 assinantes. Gerando qualidade na entrega de serviços e implantando boas práticas como: &lt;br /&gt;
&lt;br /&gt;
a) IPv6.&lt;br /&gt;
&lt;br /&gt;
b) MANRS.&lt;br /&gt;
&lt;br /&gt;
c) RPKI.&lt;br /&gt;
&lt;br /&gt;
d) CPEs com firmware baseada na BCOP &amp;lt;nowiki&amp;gt;https://www.m3aawg.org/sites/default/files/lac-bcop-1-m3aawg-v1-portuguese-final.pdf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** SOC Specialist na Brasil TecPar (AS262907) de 2022 a 2025. Um milhão de clientes. Responsável pelas estratégias de mitigação anti-DDoS atendendo as Operações de RJ, SP, RS, SC, MT e MS.&lt;br /&gt;
'''Palestras ministradas:'''&lt;br /&gt;
&lt;br /&gt;
* Semana da Informática UERJ 2002 - TuxFrw.&lt;br /&gt;
* CONISLI 2003 - TuxFrw.&lt;br /&gt;
* CONISLI 2004 - Fazendo compras com Gentoo Linux - Palestra sobre a distribuição Linux e suas ferramentas fantásticas.&lt;br /&gt;
* CONISLI 2004 - OpenVPN - Palestra sobre como criar VPNs seguras com OpenVPN e diferenças entre ele e o IPSec.&lt;br /&gt;
* CONISLI 2005 - SPoP (Security Point of Presence) com OpenVPN - Como utilizar túneis encriptados do OpenVPN para acessar a Internet de forma segura, onde quer que esteja.&lt;br /&gt;
* SECOMP 2005 UNIFEI - TuxFrw.&lt;br /&gt;
&lt;br /&gt;
* Debconf19 2019 - [https://debconf19.debconf.org/talks/4-debian-na-vida-de-uma-operadora-de-telecom/ Debian na vida de uma operadora de Telecom], [https://www.youtube.com/watch?v=vQSTslUZy8k&amp;amp;list=PLYUtdmpYPTTJDtwgD8AtxzFJ9t_URhFMK&amp;amp;index=35 vídeo] e [https://salsa.debian.org/debconf-team/public/share/debconf19/raw/master/slides/4-debian-na-vida-de-uma-operadora-de-telecom.pdf?inline=false pdf].&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=5uOFtkplDts FiqueEmCasaUseDebian - CGNAT com NFTables] e [https://www.youtube.com/watch?v=Wz2IAg6MMlU SysAdmin apps].&lt;br /&gt;
&lt;br /&gt;
'''Artigos desenvolvidos para a comunidade do Brasil Peering Fórum:'''&lt;br /&gt;
&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_na_pratica CGNAT na pratica].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Acesso_via_IPv6_Link-Local Acesso via IPv6 Link-Local].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/MANRS MANRS].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_Bulk_Port_Allocation_com_DPDK CGNAT Bulk Port Allocation com DPDK].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Servidor_de_Logs Servidor de Logs].&lt;br /&gt;
* [[DNS Recursivo Anycast Hyperlocal|DNS Anycast com Hyperlocal]].&lt;br /&gt;
* [[Recomendações sobre Mitigação DDoS]]&lt;br /&gt;
* [[Portas de Amplificação DDoS e Botnets]]&lt;br /&gt;
* [[Static Loop - um erro que pode matar seu ISP/ITP]]&lt;br /&gt;
* [[Identificando e neutralizando uma Botnet]]&lt;br /&gt;
&lt;br /&gt;
'''Tutorial:'''&lt;br /&gt;
&lt;br /&gt;
* [https://bit.ly/2saumHK Segurança de roteamento: MANRS (Mutually Agreed Norms for Routing Security) - Tutoriais NIC.br em 09/12/2019].&lt;br /&gt;
&lt;br /&gt;
'''[https://www.manrs.org/about/advisory-group/members/ MANRS Advisory Group Member (2020-2021)]'''.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=oahQkGx8urY '''Live sobre MANRS com Leonardo Furtado'''].&lt;br /&gt;
&lt;br /&gt;
Criação da Wiki ISPUP! em 24/12/2022.&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 6 do NIC.br 28/04/2023''' - &amp;quot;'''CONCEITOS E IMPLEMENTAÇÃO DE CGNAT'''&amp;quot;. Material [https://semanacap.bcp.nic.br/6-online/ aqui] e vídeo aula [https://www.youtube.com/watch?v=1q7J3NkQVSc aqui].&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 10 do NIC.br 01/07/2025''' - &amp;quot;'''Teste para padrões técnicos modernos de Internet e segurança: IPv6, DNSSEC, TLS, HTTPS e HSTS'''&amp;quot;'''.''' Material [https://semanacap.bcp.nic.br/semana-de-capacitacao-online-edicao-10-2025/ aqui] e vídeo aula [https://www.youtube.com/watch?v=55RBnGQhi2o aqui].&lt;br /&gt;
&lt;br /&gt;
'''IX Fórum Regional Sudeste (Rio de Janeiro) 24/10/2025''' com a palestra &amp;quot;'''Segurança com o pé direito'''&amp;quot; pode ser baixada [https://regional.forum.ix.br/files/apresentacao/arquivo/2307/gondim.pdf aqui].&lt;br /&gt;
&lt;br /&gt;
'''Fórum BCOP-ICANN Edição Especial DNS''' com o painel &amp;quot;'''DNS em Ação: Como os provedores estão implantando as Boas Práticas&amp;quot;''' com '''apresentação''' [https://forumbcop.nic.br/files/apresentacao/arquivo/2428/DNS_KINDNS_Reduzido.pdf aqui] e vídeo [https://www.youtube.com/live/GnYK9UOLXr4?t=10257s aqui].&lt;br /&gt;
&lt;br /&gt;
'''Webinar:'''&lt;br /&gt;
&lt;br /&gt;
Proteção e Mitigação de ataques DDoS em 10/09/2024 às 20:00 UTC -3. Site da chamada [https://gdg.community.dev/events/details/google-gdg-sinop-presents-webinar-ao-vivo-protecao-e-mitigacao-de-ataques-ddos/ aqui] e o vídeo da live no Youtube [https://www.youtube.com/live/7VIaoDQaLQE aqui].&lt;br /&gt;
&lt;br /&gt;
'''Podcast:'''&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/live/x4fxtma4eyQ Segurança de Rede e Infraestrutura para 2025: Preparando os ISPs para o futuro!]&lt;br /&gt;
&lt;br /&gt;
'''Contatos:'''&lt;br /&gt;
&lt;br /&gt;
Telegram: '''@Marcelo_Gondim'''&lt;br /&gt;
&lt;br /&gt;
WhatsApp: +55 (22) 99743-9060&lt;br /&gt;
&lt;br /&gt;
E-mail: '''gondim at ispup.com.br'''&lt;br /&gt;
&lt;br /&gt;
Linkedin: https://www.linkedin.com/in/marcelo-gondim-sysadmin/&lt;br /&gt;
&lt;br /&gt;
Meu Github: https://github.com/gondimcodes&lt;br /&gt;
&lt;br /&gt;
== Mini-CV ==&lt;br /&gt;
'''Marcelo Gondim''' começou sua carreira como desenvolvedor de software em COBOL e Clipper entre 1992 e 1995. Em 1996 foi responsável por desenvolver um sistema concorrente com o RENPAC da Embratel para acesso ao SISCOMEX e implantou a Internet para fins comerciais na empresa DATABRAS. Trabalhou como consultor e instrutor de GNU/Linux na Conectiva S/A em 2000. Em 2003 se tornou consultor de diversos Provedores de Internet na Região dos Lagos - RJ e onde acabou se tornando CTO da Nettel Telecomunicações (AS53135) com 42.000 assinantes. Implantou IPv6 iniciando em 2013 e se tornou participante do MANRS com diversas contribuições com artigos e palestras. Trabalhou como Especialista em Redes e SOC (Security Operations Center) na Brasil TecPar AS262907 entre 2022 e 2025, onde implementou boas práticas, tratamentos de incidentes relacionados ao ASN, desenvolveu as estratégias de Mitigação DDoS e uma Rede de DNS Recursivo Anycast espalhada pelo RS, RJ, SP, SC MT e MS, também certificada KINDNS. Fundador da empresa ISPFocus especializada em Tecnologia da Informação e boas práticas para ISPs.&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4000</id>
		<title>Usuário:Gondim</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=4000"/>
		<updated>2025-12-22T15:09:47Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Marcelo Gondim da Cunha'''&lt;br /&gt;
[[Arquivo:Gondim paisagem.jpg|esquerda|commoldura]]&lt;br /&gt;
&lt;br /&gt;
'''Contribuições e trabalhos:'''&lt;br /&gt;
&lt;br /&gt;
* Administração de Sistemas Unix-Like desde 1996.&lt;br /&gt;
* Consultor na Conectiva S/A - Unidade Rio em 2000.&lt;br /&gt;
** Autor do projeto TuxFrw - https://github.com/gondimcodes/tuxfrw e https://github.com/gondimcodes/tuxfrw-nft&lt;br /&gt;
* Administração de sistemas BSD pela FreeBSD Brasil em 2010.&lt;br /&gt;
* Direção do AS53135 - Nettel Telecomunicações entre 2003 e 2021 atingindo a marca de 41.000 assinantes. Gerando qualidade na entrega de serviços e implantando boas práticas como: &lt;br /&gt;
&lt;br /&gt;
a) IPv6.&lt;br /&gt;
&lt;br /&gt;
b) MANRS.&lt;br /&gt;
&lt;br /&gt;
c) RPKI.&lt;br /&gt;
&lt;br /&gt;
d) CPEs com firmware baseada na BCOP &amp;lt;nowiki&amp;gt;https://www.m3aawg.org/sites/default/files/lac-bcop-1-m3aawg-v1-portuguese-final.pdf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** SOC Specialist na Brasil TecPar (AS262907) de 2022 a 2025. Um milhão de clientes. Responsável pelas estratégias de mitigação anti-DDoS atendendo as Operações de RJ, SP, RS, SC, MT e MS.&lt;br /&gt;
'''Palestras ministradas:'''&lt;br /&gt;
&lt;br /&gt;
* Semana da Informática UERJ 2002 - TuxFrw.&lt;br /&gt;
* CONISLI 2003 - TuxFrw.&lt;br /&gt;
* CONISLI 2004 - Fazendo compras com Gentoo Linux - Palestra sobre a distribuição Linux e suas ferramentas fantásticas.&lt;br /&gt;
* CONISLI 2004 - OpenVPN - Palestra sobre como criar VPNs seguras com OpenVPN e diferenças entre ele e o IPSec.&lt;br /&gt;
* CONISLI 2005 - SPoP (Security Point of Presence) com OpenVPN - Como utilizar túneis encriptados do OpenVPN para acessar a Internet de forma segura, onde quer que esteja.&lt;br /&gt;
* SECOMP 2005 UNIFEI - TuxFrw.&lt;br /&gt;
&lt;br /&gt;
* Debconf19 2019 - [https://debconf19.debconf.org/talks/4-debian-na-vida-de-uma-operadora-de-telecom/ Debian na vida de uma operadora de Telecom], [https://www.youtube.com/watch?v=vQSTslUZy8k&amp;amp;list=PLYUtdmpYPTTJDtwgD8AtxzFJ9t_URhFMK&amp;amp;index=35 vídeo] e [https://salsa.debian.org/debconf-team/public/share/debconf19/raw/master/slides/4-debian-na-vida-de-uma-operadora-de-telecom.pdf?inline=false pdf].&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=5uOFtkplDts FiqueEmCasaUseDebian - CGNAT com NFTables] e [https://www.youtube.com/watch?v=Wz2IAg6MMlU SysAdmin apps].&lt;br /&gt;
&lt;br /&gt;
'''Artigos desenvolvidos para a comunidade do Brasil Peering Fórum:'''&lt;br /&gt;
&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_na_pratica CGNAT na pratica].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Acesso_via_IPv6_Link-Local Acesso via IPv6 Link-Local].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/MANRS MANRS].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_Bulk_Port_Allocation_com_DPDK CGNAT Bulk Port Allocation com DPDK].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Servidor_de_Logs Servidor de Logs].&lt;br /&gt;
* [[DNS Recursivo Anycast Hyperlocal|DNS Anycast com Hyperlocal]].&lt;br /&gt;
* [[Recomendações sobre Mitigação DDoS]]&lt;br /&gt;
* [[Portas de Amplificação DDoS e Botnets]]&lt;br /&gt;
* [[Static Loop - um erro que pode matar seu ISP/ITP]]&lt;br /&gt;
* [[Identificando e neutralizando uma Botnet]]&lt;br /&gt;
&lt;br /&gt;
'''Tutorial:'''&lt;br /&gt;
&lt;br /&gt;
* [https://bit.ly/2saumHK Segurança de roteamento: MANRS (Mutually Agreed Norms for Routing Security) - Tutoriais NIC.br em 09/12/2019].&lt;br /&gt;
&lt;br /&gt;
'''[https://www.manrs.org/about/advisory-group/members/ MANRS Advisory Group Member (2020-2021)]'''.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=oahQkGx8urY '''Live sobre MANRS com Leonardo Furtado'''].&lt;br /&gt;
&lt;br /&gt;
Criação da Wiki ISPUP! em 24/12/2022.&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 6 do NIC.br 28/04/2023''' - &amp;quot;'''CONCEITOS E IMPLEMENTAÇÃO DE CGNAT'''&amp;quot;. Material [https://semanacap.bcp.nic.br/6-online/ aqui] e vídeo aula [https://www.youtube.com/watch?v=1q7J3NkQVSc aqui].&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 10 do NIC.br 01/07/2025''' - &amp;quot;'''Teste para padrões técnicos modernos de Internet e segurança: IPv6, DNSSEC, TLS, HTTPS e HSTS'''&amp;quot;'''.''' Material [https://semanacap.bcp.nic.br/semana-de-capacitacao-online-edicao-10-2025/ aqui] e vídeo aula [https://www.youtube.com/watch?v=55RBnGQhi2o aqui].&lt;br /&gt;
&lt;br /&gt;
'''IX Fórum Regional Sudeste (Rio de Janeiro) 24/10/2025''' com a palestra &amp;quot;'''Segurança com o pé direito'''&amp;quot; pode ser baixada [https://regional.forum.ix.br/files/apresentacao/arquivo/2307/gondim.pdf aqui].&lt;br /&gt;
&lt;br /&gt;
'''Fórum BCOP-ICANN Edição Especial DNS''' com o painel &amp;quot;'''DNS em Ação: Como os provedores estão implantando as Boas Práticas&amp;quot;''' com '''apresentação''' [https://forumbcop.nic.br/files/apresentacao/arquivo/2428/DNS_KINDNS_Reduzido.pdf aqui]&lt;br /&gt;
&lt;br /&gt;
'''Webinar:'''&lt;br /&gt;
&lt;br /&gt;
Proteção e Mitigação de ataques DDoS em 10/09/2024 às 20:00 UTC -3. Site da chamada [https://gdg.community.dev/events/details/google-gdg-sinop-presents-webinar-ao-vivo-protecao-e-mitigacao-de-ataques-ddos/ aqui] e o vídeo da live no Youtube [https://www.youtube.com/live/7VIaoDQaLQE aqui].&lt;br /&gt;
&lt;br /&gt;
'''Podcast:'''&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/live/x4fxtma4eyQ Segurança de Rede e Infraestrutura para 2025: Preparando os ISPs para o futuro!]&lt;br /&gt;
&lt;br /&gt;
'''Contatos:'''&lt;br /&gt;
&lt;br /&gt;
Telegram: '''@Marcelo_Gondim'''&lt;br /&gt;
&lt;br /&gt;
WhatsApp: +55 (22) 99743-9060&lt;br /&gt;
&lt;br /&gt;
E-mail: '''gondim at ispup.com.br'''&lt;br /&gt;
&lt;br /&gt;
Linkedin: https://www.linkedin.com/in/marcelo-gondim-sysadmin/&lt;br /&gt;
&lt;br /&gt;
Meu Github: https://github.com/gondimcodes&lt;br /&gt;
&lt;br /&gt;
== Mini-CV ==&lt;br /&gt;
'''Marcelo Gondim''' começou sua carreira como desenvolvedor de software em COBOL e Clipper entre 1992 e 1995. Em 1996 foi responsável por desenvolver um sistema concorrente com o RENPAC da Embratel para acesso ao SISCOMEX e implantou a Internet para fins comerciais na empresa DATABRAS. Trabalhou como consultor e instrutor de GNU/Linux na Conectiva S/A em 2000. Em 2003 se tornou consultor de diversos Provedores de Internet na Região dos Lagos - RJ e onde acabou se tornando CTO da Nettel Telecomunicações (AS53135) com 42.000 assinantes. Implantou IPv6 iniciando em 2013 e se tornou participante do MANRS com diversas contribuições com artigos e palestras. Trabalhou como Especialista em Redes e SOC (Security Operations Center) na Brasil TecPar AS262907 entre 2022 e 2025, onde implementou boas práticas, tratamentos de incidentes relacionados ao ASN, desenvolveu as estratégias de Mitigação DDoS e uma Rede de DNS Recursivo Anycast espalhada pelo RS, RJ, SP, SC MT e MS, também certificada KINDNS. Fundador da empresa ISPFocus especializada em Tecnologia da Informação e boas práticas para ISPs.&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3988</id>
		<title>DNS Recursivo Anycast Hyperlocal</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3988"/>
		<updated>2025-11-24T15:01:15Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
==Introdução==&lt;br /&gt;
Você sabe como funciona a Internet? Essa é uma pergunta que meu amigo '''Thiago Ayub''' sempre faz aos seus candidatos à vagas de emprego e não importa o quanto tenham de experiência em '''Engenharia de Redes''', todos sempre travam nesse momento. Todos estão sempre prontos e preparados para resolver os problemas mais cabeludos em '''BGP''', '''OSPF''', '''MPLS''', etc mas travam com essa simples pergunta. Para contextualizar e visualizarmos melhor vamos nos atentar à imagem abaixo e uma explicação simplificada de como funciona:&lt;br /&gt;
[[Arquivo:Dns hierarquia.png|esquerda|commoldura]]&lt;br /&gt;
Tudo começa com um usuário sentado confortavelmente e querendo acessar um conteúdo disponível na Internet. Ele digita em seu navegador preferido a URL: '''&amp;lt;nowiki&amp;gt;https://wiki.brasilpeeringforum.org&amp;lt;/nowiki&amp;gt;''',&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;1)&amp;lt;/big&amp;gt;''' &amp;lt;big&amp;gt;O&amp;lt;/big&amp;gt; &amp;lt;big&amp;gt;navegador irá requisitar do '''DNS Recursivo''' utilizado pelo usuário, o '''endereço IP''' que responde pelo nome '''wiki.'''&amp;lt;/big&amp;gt;'''brasilpeeringforum.org'''&amp;lt;big&amp;gt;. Isso porque todos os acessos se dão na Internet através do '''endereço''' '''IP''' e não através do '''nome'''. Imaginem se tivéssemos que decorar os endereços IPs de todos os sites e serviços que quiséssemos acessar na Internet?&amp;lt;/big&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;big&amp;gt;'''2)''' Nosso DNS Recursivo checa se a informação consta em seu cache.&amp;lt;/big&amp;gt; Se a informação existir ela é devolvida ao navegador do usuário e aí este consegue acessar o site.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Do contrário o DNS Recursivo pergunta ao '''Root Server''' quem é o '''TLD (Top Level Domain)''' responsável para atender a requisição. &lt;br /&gt;
&lt;br /&gt;
'''4)''' O '''Root Server''' informa ao DNS Recursivo o endereço do '''TLD responsável'''. No Brasil o '''TLD''' responsável pelo '''.br''' seria o '''Registro.br'''.&lt;br /&gt;
&lt;br /&gt;
'''5)''' O DNS Recursivo pergunta ao '''TLD''' sobre '''wiki.brasilpeeringforum.org''' e este responde com os endereços IP dos '''DNS Autoritativos''' responsáveis pelo domínio '''brasilpeeringforum.org.'''&lt;br /&gt;
&lt;br /&gt;
'''6)''' O DNS Recursivo pergunta aos '''DNS Autoritativos''' pelo '''wiki.brasilpeeringforum.org''' e este responde com o '''endereço IP'''.&lt;br /&gt;
&lt;br /&gt;
'''7)''' Por último o DNS Recursivo devolve a informação para o navegador do usuário.&lt;br /&gt;
&lt;br /&gt;
Como que se dá a comunicação entre os '''DNS(s) Recursivos, Root Servers, TLDs''' e '''Autoritativos'''? Como que o navegador do usuário, após receber o IP do site, consegue chegar no servidor que tem o conteúdo? Isso só é possível devido ao protocolo chamado '''BGP (Border Gateway Protocol)''', todos os caminhos que conhecemos como rotas de destino, são anunciadas por milhares de participantes na '''Internet''' conhecidos como '''AS (Autonomous System)''', esses participantes se interligam para disponibilizar conteúdos e acessos pelo mundo aos milhares de usuários. É uma imensa rede colaborativa formada por Empresas, Universidades, Governos e todos que queiram se interconectar. Percebam que sem o '''BGP''', que serve de caminho para chegarmos nos conteúdos e sem o '''DNS (Domain Name System)''' para traduzir o nome para o endereço IP, a '''Internet''' não funcionaria e por isso precisamos cuidar muito bem desses dois serviços.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Mas não acaba por aí. O '''DNS Recursivo''' tem um papel muito importante para o Provedor de Internet e que envolve segurança, qualidade de acesso à Internet e a disponibilidade do serviço entregue ao cliente. Quando bem configurado acelera as consultas dos acessos graças ao seu cache interno, mas para que isso seja percebido pelo assinante, é necessário que esteja o mais próximo possível do seu cliente.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Um erro que destrói a qualidade do nosso serviço ==&lt;br /&gt;
Um erro muito comum que muitas operadoras cometem é utilizar DNS Recursivo externo, como o '''8.8.8.8''', '''1.1.1.1''' e outros, para seus clientes. Quanto mais próximo dos seus clientes, mais qualidade de serviço estará entregando a eles. Conteúdos serão entregues mais rapidamente pois serão resolvidos e armazenados em caches locais e não consultados remotamente na Internet. Para falar mais sobre isso, te convido leitor desse documento, que assista essa palestra do '''Thiago Ayub''' no '''GTER 51/GTS 37''' (2022) '''8.888 MOTIVOS PARA NÃO USAR DNS RECURSIVO EXTERNO EM SEU AS''': https://www.youtube.com/watch?v=Rsvpu5uF2Io&lt;br /&gt;
&lt;br /&gt;
== Objetivo ==&lt;br /&gt;
O objetivo desta documentação não é te ensinar tudo sobre '''DNS''', '''BGP''', '''OSPF''' e nem tão pouco sobre GNU/Linux e sim te mostrar um exemplo de servidor DNS Recursivo implementado pensando em segurança, qualidade e resiliência. Usaremos em todas as nossas documentações o [https://www.debian.org/ Debian GNU/Linux], por ser uma distribuição que considero uma obra de arte criada por uma enorme comunidade séria, com vasta experiência de anos, qualidade no empacotamento dos programas, estável e com uma equipe de segurança excelente e ativa. Caso você leitor, utilize alguma outra distribuição GNU/Linux, todo conteúdo apresentado aqui pode ser aplicado em outras distros, desde que respeitando as particularidades de cada uma.&lt;br /&gt;
&lt;br /&gt;
Aqui construiremos um sistema do tipo '''Anycast''', ou seja, terás o serviço rodando em diversas localidades da sua Rede utilizando o mesmo endereçamento IP e que atenderá seu cliente mais próximo. Em caso de falhas, seus clientes automaticamente e de forma transparente continuarão consultando o DNS mais próximo deles. Para que ele funcione dessa forma você precisará ter uma '''Rede OSPF''' implementada no seu Provedor Internet ou algum outro protocolo como por exemplo o '''ISIS,''' mas esse documento não irá abordar o '''ISIS'''. Também utilizaremos o '''Hyperlocal''' como recurso adicional para gerar algumas proteções de segurança e velocidade na resposta relacionada aos servidores de DNS Raiz da Internet.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
Para exemplificar nosso servidor de DNS Recursivo, usaremos como base das explicações um diagrama demonstrando o uso do DNS Recursivo em uma Rede fictícia. Adotaremos IPs privados e reservados para demonstrar todo o ambiente do Provedor de Internet.&lt;br /&gt;
[[Arquivo:Recursivo99.png|esquerda|miniaturadaimagem|695x695px]]&lt;br /&gt;
Nesse diagrama podemos observar alguns detalhes técnicos como por exemplo: existem '''3 servidores de DNS Recursivo''' posicionados em locais diferentes, que poderiam estar em bairros diferentes e até em cidades diferentes. Em cada servidor teremos '''2 loopbacks''' com os IPs:&lt;br /&gt;
&lt;br /&gt;
'''10.10.10.10/32 - fd00::10:10:10:10/128'''&lt;br /&gt;
&lt;br /&gt;
'''10.10.9.9/32 - fd00::10:10:9:9/128'''&lt;br /&gt;
&lt;br /&gt;
Esses IPs serão entregues pelos concentradores '''PPPoE''' ou '''IPoE''' ('''BNG''') para seus clientes como '''DNS primário''' e '''secundário'''. Podemos usar IPs privados como DNS primário e secundário em um ambiente real? Sim podemos, desde que não sejam IPs que possam ter problemas com as redes privadas dos clientes. Ex.: rede do cliente usando '''192.168.0.0/24'''. Se entregarmos o DNS sendo '''192.168.0.10''' e '''192.168.0.20''' teremos problemas e o cliente ficará sem Internet, porque '''192.168.0.10''' e '''192.168.0.20''' fazem parte da rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
Agora entregando '''10.10.10.10,''' '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9''' não teríamos problemas com a rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
'''Motivos para usarmos IPs privados:'''&lt;br /&gt;
* O principal motivo está relacionado com a segurança, uma vez que sendo um IP privado, não pode sofrer ataques DDoS direcionados diretamente para ele, vindos da Internet.&lt;br /&gt;
* Nem mesmo o cliente da sua rede conhece os '''IPs públicos''' utilizados para recursividade na Internet.&lt;br /&gt;
* Memorizar os IPs '''10.10.10.10''' e '''10.10.9.9''' é tão fácil quanto memorizar o '''8.8.8.8''' e o '''1.1.1.1'''. Mais fácil para o seu técnico guardar essa informação e utilizar onde for necessário.&lt;br /&gt;
Cada servidor DNS Recursivo possui um '''IPv4 público''', aqui representado por '''198.18.x.x/27''' e um '''IPv6 global''' representado por um IP dentro do prefixo '''2001:db8::/32'''. Cada servidor precisa ter os seus próprios IPs e são através destes IPs que as consultas de DNS serão realizadas na Internet.&lt;br /&gt;
&lt;br /&gt;
Nessa topologia usando '''Anycast''', o cliente será sempre atendido pelo '''DNS Recursivo''' mais próximo, desde que os pesos no '''OSPF''' estejam ajustados corretamente.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
== Dados do servidor ==&lt;br /&gt;
Podemos utilizar um sistema virtualizado ou não. Sistemas virtualizados são bem vindos pois são mais simples quando precisamos fazer backups, levantar outros sistemas sem complicações e se precisarmos restaurar rapidamente algum sistema que ficou indisponível por algum motivo. A configuração abaixo tem capacidade para atender algo em torno a '''50.000 assinantes ou mais'''. O DNS Recursivo é um serviço que pode ser utilizado até mesmo em um '''Raspberry Pi''' e atender operações pequenas, nesse caso com o intuito de economizar energia e espaço. Nosso foco aqui é montar uma rede de '''DNS Recursivo Anycast com HyperLocal'''. Como comentei acima o servidor deve ficar o mais próximo dos clientes para termos a '''menor latência possível''' e '''sempre menor que 5ms''' entre o cliente e o servidor.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!CPU&lt;br /&gt;
!Memória&lt;br /&gt;
!Disco&lt;br /&gt;
!Sistema&lt;br /&gt;
|-&lt;br /&gt;
|2.4Ghz 8 cores&lt;br /&gt;
|16G DDR4&lt;br /&gt;
|30G&lt;br /&gt;
|Debian 13 amd64 (Trixie)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Softwares utilizados ==&lt;br /&gt;
* Debian 13 amd64 (Trixie) instalação mínima.&lt;br /&gt;
&lt;br /&gt;
* [https://frrouting.org/ FRRouting].&lt;br /&gt;
* Unbound.&lt;br /&gt;
* Chrony (NTP/NTS).&lt;br /&gt;
* Shell script em bash.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades que teremos ==&lt;br /&gt;
* Sistema em Anycast.&lt;br /&gt;
* Hyperlocal.&lt;br /&gt;
* Controle de acesso por &amp;lt;abbr&amp;gt;ACL&amp;lt;/abbr&amp;gt;.&lt;br /&gt;
* RPZ (Response Policy Zone).&lt;br /&gt;
* Bloqueio de consultas do tipo ANY.&lt;br /&gt;
* QNAME minimization habilitado. (habilitado por default no Unbound)&lt;br /&gt;
* Recursividade em IPv4 e IPv6.&lt;br /&gt;
* DNSSEC habilitado.&lt;br /&gt;
* &amp;lt;abbr&amp;gt;DoH (DNS&amp;lt;/abbr&amp;gt; over HTTPS) habilitado.&lt;br /&gt;
&lt;br /&gt;
== Monitoramento ==&lt;br /&gt;
O monitoramento é algo bem específico e não é o foco deste documento mas é extremamente importante que você monitore seus servidores de DNS por alguma ferramenta como o Zabbix. Aqui mostrarei apenas como enviar as informações para o Zabbix. Algumas coisas que você deveria monitorar nos servidores de DNS Recursivo:&lt;br /&gt;
* Serviço do unbound parou.&lt;br /&gt;
* Perda de pacotes.&lt;br /&gt;
* Latência alta de pacotes.&lt;br /&gt;
* Lentidão na resolução de queries.&lt;br /&gt;
* CPU alta.&lt;br /&gt;
* Load alto.&lt;br /&gt;
* Memória com uso alto.&lt;br /&gt;
* Disco com pouco espaço.&lt;br /&gt;
* Queda brusca nas queries.&lt;br /&gt;
* A recursividade parou de funcionar.&lt;br /&gt;
* A recursividade voltou a funcionar.&lt;br /&gt;
Este abaixo é um exemplo de monitoramento de um sistema de DNS Recursivo que atende 50.000 assinantes:&lt;br /&gt;
[[Arquivo:Grafana dns.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Configurando a Rede ==&lt;br /&gt;
Nossa documentação será baseada no diagrama apresentado acima e por isso configuraremos apenas um dos três servidores, porque os outros serão configurados da mesma forma, só que com dados diferentes. Para tanto assumirei que já temos um sistema Debian instalado com o mínimo de pacotes e somente com sshd, para que possamos acessar remotamente mais tarde. '''Não instale um ambiente gráfico no servidor''', você não deve querer fazer isso por diversos motivos e os principais: primeiro porque não é um Desktop e segundo porque o ambiente gráfico devoraria toda a memória com recursos que não seriam úteis aqui.&lt;br /&gt;
&lt;br /&gt;
Em '''/etc/network/interfaces''' deixaremos assim:&lt;br /&gt;
 # This file describes the network interfaces available on your system&lt;br /&gt;
 # and how to activate them. For more information, see interfaces(5).&lt;br /&gt;
  &lt;br /&gt;
 source /etc/network/interfaces.d/*&lt;br /&gt;
  &lt;br /&gt;
 # The loopback network interface&lt;br /&gt;
 auto lo&lt;br /&gt;
 iface lo inet loopback&lt;br /&gt;
  &lt;br /&gt;
 auto lo:0&lt;br /&gt;
 iface lo:0 inet static&lt;br /&gt;
       address 10.10.10.10/32&lt;br /&gt;
  &lt;br /&gt;
 auto lo:1&lt;br /&gt;
 iface lo:1 inet static&lt;br /&gt;
       address 10.10.9.9/32&lt;br /&gt;
 &lt;br /&gt;
 auto lo:2&lt;br /&gt;
 iface lo:2 inet6 static&lt;br /&gt;
       address fd00::10:10:10:10/128&lt;br /&gt;
 &lt;br /&gt;
 auto lo:3&lt;br /&gt;
 iface lo:3 inet6 static&lt;br /&gt;
       address fd00::10:10:9:9/128&lt;br /&gt;
  &lt;br /&gt;
 # The primary network interface&lt;br /&gt;
 auto ens18&lt;br /&gt;
 iface ens18 inet static&lt;br /&gt;
         address 198.18.1.10/27&lt;br /&gt;
         gateway 198.18.1.1&lt;br /&gt;
  &lt;br /&gt;
 iface ens18 inet6 static&lt;br /&gt;
         address 2001:db8::faca:198:18:1:10/64&lt;br /&gt;
         gateway 2001:db8::faca:198:18:1:1&lt;br /&gt;
  &lt;br /&gt;
 # The secondary network interface&lt;br /&gt;
 auto ens18:0&lt;br /&gt;
 iface ens18:0 inet static&lt;br /&gt;
         address 172.16.0.6/30&lt;br /&gt;
Nesse cenário temos as duas '''loopbacks''' com os IPs '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10''' e '''fd00::10:10:9:9''' que serão anunciados via OSPF para a rede e serem entregues aos clientes via BNG. Os IPs '''198.18.1.10''' e '''2001:db8::faca:198:18:1:10''' serão usados para fazerem a recursividade na Internet tanto em IPv4 quanto em IPv6. Esses IPs não devem ser divulgados para clientes; os IPs públicos são dedicados apenas para essa finalidade.&lt;br /&gt;
&lt;br /&gt;
== Configuração dos repositórios Debian ==&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://security.debian.org/debian-security/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-security&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-updates&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian-backports.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-backports&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
&lt;br /&gt;
 # rm /etc/apt/sources.list&lt;br /&gt;
Após a configuração vamos instalar alguns pacotes necessários e outros úteis:&lt;br /&gt;
 # apt update &amp;amp;&amp;amp; apt full-upgrade&lt;br /&gt;
 # apt install net-tools nftables htop iotop sipcalc tcpdump curl gnupg rsync wget host dnsutils mtr-tiny bmon sudo tmux whois ethtool dnstop&lt;br /&gt;
&lt;br /&gt;
== Fazendo algum tuning no sistema ==&lt;br /&gt;
Em '''/etc/sysctl.d/100-tuning.conf''' adicionamos essas instruções:&lt;br /&gt;
 net.core.rmem_max = 2147483647&lt;br /&gt;
 net.core.wmem_max = 2147483647&lt;br /&gt;
 net.ipv4.tcp_rmem = 4096 87380 2147483647&lt;br /&gt;
 net.ipv4.tcp_wmem = 4096 65536 2147483647&lt;br /&gt;
 net.netfilter.nf_conntrack_buckets = 512000&lt;br /&gt;
 net.netfilter.nf_conntrack_max = 4096000&lt;br /&gt;
 vm.swappiness=10&lt;br /&gt;
Estamos fazendo algumas melhorias de memória, algumas relacionadas a '''conntrack''' porque se for usar um filtro de pacotes stateful, como o '''Netfilter/IPTables''' ou '''Netfilter/NFTables''', o valor default da tabela é pequeno e dependendo da situação, se estourar essa tabela, as consultas de DNS terão problemas também. O DNS Recursivo não deve ficar aberto para qualquer um na Internet, ele deve ser liberado apenas para seus clientes. Podemos fazer através das ACLs do Unbound e pelo filtro de pacotes. O último parâmetro diz respeito ao uso de swap, por padrão o Debian permite o uso de swap após 40% do uso da memória, nesse caso estamos dizendo para o sistema usar o swap com 90% de uso da memória.&lt;br /&gt;
&lt;br /&gt;
Precisamos adicionar o módulo '''nf_conntrack''' em '''/etc/modules''' para que seja carregado em tempo de boot, senão os parâmetros de '''conntrack''' que colocamos em '''/etc/sysctl.conf''' não serão carregados.&lt;br /&gt;
 # echo nf_conntrack &amp;gt;&amp;gt; /etc/modules&lt;br /&gt;
 # modprobe nf_conntrack&lt;br /&gt;
 # sysctl -p&lt;br /&gt;
&lt;br /&gt;
== Instalando o FRRouting ==&lt;br /&gt;
O FRRouting é o programa que usaremos para fazer os anúncios das nossas loopbacks via OSPF. Nesse documento usaremos a versão 10.x:&lt;br /&gt;
 # apt install frr frr-doc frr-pythontools&lt;br /&gt;
Aconselho depois de instalar os pacotes, marcá-los para não atualizar juntamente com os demais pacotes, isso é para evitar de ocorrer alguma atualização no FRRouting, que torne o serviço instável por algum motivo. Não que isso vá ocorrer, mas é melhor fazer essa atualização quando realmente for necessário.&lt;br /&gt;
 # apt-mark hold frr frr-doc frr-pythontools&lt;br /&gt;
Após esse comando acima, o sistema manterá a instalação original do pacote intacta. Para desbloquear basta executar o comando abaixo:&lt;br /&gt;
 # apt-mark unhold frr frr-doc frr-pythontools&lt;br /&gt;
&lt;br /&gt;
== Removendo o APPARMOR ==&lt;br /&gt;
O '''APPARMOR''' às vezes causa mais problemas que solução e se não for fazer uma completa configuração nele, é melhor desabilitá-lo. Para fazer isso efetivamente, o procedimento é esse abaixo:&lt;br /&gt;
 # mkdir -p /etc/default/grub.d&lt;br /&gt;
 # echo 'GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;$GRUB_CMDLINE_LINUX_DEFAULT apparmor=0&amp;quot;' | tee /etc/default/grub.d/apparmor.cfg&lt;br /&gt;
 # update-grub&lt;br /&gt;
 # reboot&lt;br /&gt;
&lt;br /&gt;
== Instalando o Unbound ==&lt;br /&gt;
Nesse momento ainda não iremos configurar o Unbound, apenas instalar o pacote e acertar o ambiente. Vamos instalar o unbound do backports porque este já possui suporte ao DoH que veremos mais à frente.&lt;br /&gt;
 # apt install unbound dns-root-data&lt;br /&gt;
 # mkdir -p /var/log/unbound&lt;br /&gt;
 # touch /var/log/unbound/unbound.log&lt;br /&gt;
 # chown -R unbound:unbound /var/log/unbound/&lt;br /&gt;
 # systemctl restart unbound&lt;br /&gt;
Configurando o logrotate:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/logrotate.d/unbound&lt;br /&gt;
 /var/log/unbound/unbound.log {&lt;br /&gt;
     rotate 5&lt;br /&gt;
     weekly&lt;br /&gt;
     postrotate&lt;br /&gt;
         unbound-control log_reopen&lt;br /&gt;
     endscript&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
Reiniciando o serviço:&lt;br /&gt;
 # systemctl restart logrotate.service&lt;br /&gt;
&lt;br /&gt;
== Desabilitando THP (Transparente Huge Pages) em arquitetura AMD64 ==&lt;br /&gt;
No Debian o '''THP''' vem habilitado como '''always''' e o '''unbound''' por trabalhar bastante com alterações do cache em memória, isso pode acabar causando um consumo crescente de uso de RAM sem necessidade. É uma boa prática desabilitá-lo com os passos abaixo:&lt;br /&gt;
&lt;br /&gt;
https://github.com/NLnetLabs/unbound/issues/724&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/systemd/system/disable-thp.service&lt;br /&gt;
 [Unit]&lt;br /&gt;
 Description=Desabilita Transparent Huge Pages (THP)&lt;br /&gt;
 After=network.target&lt;br /&gt;
 &lt;br /&gt;
 [Service]&lt;br /&gt;
 Type=oneshot&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled&amp;quot;&lt;br /&gt;
 RemainAfterExit=yes&lt;br /&gt;
 &lt;br /&gt;
 [Install]&lt;br /&gt;
 WantedBy=multi-user.target&lt;br /&gt;
 EOF&lt;br /&gt;
Acima configuramos o serviço '''disable-thp.service''' para desabilitar o '''THP''' e abaixo habilitamos no '''systemd''' e iniciamos:&lt;br /&gt;
 # systemctl daemon-reload&lt;br /&gt;
 # systemctl enable --now disable-thp&lt;br /&gt;
&lt;br /&gt;
== Preparando o monitoramento do seu DNS Recursivo ==&lt;br /&gt;
O monitoramento do seu DNS Recursivo é muito importante e para isso vamos usar um '''template para Zabbix''', que modifiquei juntamente com o seu shell script e que enviará os dados para o seu Zabbix server via '''zabbix-sender'''. O projeto original está aqui '''https://github.com/jeftedelima/Unbound-DNS&amp;lt;nowiki/&amp;gt;.''' O xml alterado está aqui '''https://github.com/gondimcodes/template_zabbix_dns_unbound'''. Embora seja antigo é perfeitamente importável no Zabbix 6.0, por exemplo.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;nowiki/&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Teremos um shell script que você precisará colocar no seu '''/etc/crontab'''. No exemplo abaixo assumi que o shell script está em '''/root/scripts'''. De 5 em 5 minutos os dados serão enviados para o seu Zabbix server.&lt;br /&gt;
 */5 * * * *     root    /root/scripts/unboundSend.sh '''IP_zabbix_server''' '''nome_do_host''' 1&amp;gt; /dev/null&lt;br /&gt;
Na linha acima, troque o '''IP_zabbix_server''' pelo '''IP do seu servidor Zabbix''' e o '''nome_do_host''' pelo '''hostname''' '''do seu DNS Recursivo'''. Você precisará instalar o pacote '''zabbix-sender''' no seu DNS Recursivo pois ele será usado para enviar os dados para o Zabbix server.&lt;br /&gt;
&lt;br /&gt;
Abaixo o '''unboundSend.sh''' também alterado com inclusão de mais dados:&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 #       @Jefte de Lima Ferreira&lt;br /&gt;
 #       jeftedelima at gmail dot com&lt;br /&gt;
 #       CRON Example&lt;br /&gt;
 #       Contributor: Marcelo Gondim - gondim at gmail dot com&lt;br /&gt;
 #       */5   **** root sh /home/dir/unboundSend.sh 192.168.10.1 Unbound 1&amp;gt; /dev/null&lt;br /&gt;
  &lt;br /&gt;
 if [ -z ${1} ] || [ -z ${2} ] ; then&lt;br /&gt;
         echo &amp;quot;You need to specify the IP address of zabbix server and hostname of your DNS Unbound on zabbix&amp;quot;&lt;br /&gt;
         echo &amp;quot;Usage example: ./unboundSend.sh 192.168.10.1 UnboundServer&amp;quot;&lt;br /&gt;
         exit 1&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 # ZABBIX_SERVER IP&lt;br /&gt;
 IP_ZABBIX=$1&lt;br /&gt;
 # NAME Unbound on Zabbix&lt;br /&gt;
 NAME_HOST=$2&lt;br /&gt;
 DIR_TEMP=/var/tmp/&lt;br /&gt;
 FILE=&amp;quot;${DIR_TEMP}dump_unbound_control_stats.txt&amp;quot;&lt;br /&gt;
 unbound-control stats &amp;gt; ${FILE}&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_NUM_QUERIES=$(cat ${FILE} | grep -w 'total.num.queries' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEHITS=$(cat ${FILE} | grep -w 'total.num.cachehits' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEMISS=$(cat ${FILE} | grep -w 'total.num.cachemiss' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_PREFETCH=$(cat ${FILE} | grep -w 'total.num.prefetch' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_RECURSIVEREPLIES=$(cat ${FILE} | grep -w 'total.num.recursivereplies' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_REQ_MAX=$(cat ${FILE} | grep -w 'total.requestlist.max' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_AVG=$(cat ${FILE} | grep -w 'total.requestlist.avg' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_OVERWRITTEN=$(cat ${FILE} | grep -w 'total.requestlist.overwritten' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_EXCEEDED=$(cat ${FILE} | grep -w 'total.requestlist.exceeded' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_ALL=$(cat ${FILE} | grep -w 'total.requestlist.current.all' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_USER=$(cat ${FILE} | grep -w 'total.requestlist.current.user' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_TCPUSAGE=$(cat ${FILE} | grep -w 'total.tcpusage' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_QUERY_TYPE_A=$(cat ${FILE} | grep -w 'num.query.type.A' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NS=$(cat ${FILE} | grep -w 'num.query.type.NS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_MX=$(cat ${FILE} | grep -w 'num.query.type.MX' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TXT=$(cat ${FILE} | grep -w 'num.query.type.TXT' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_PTR=$(cat ${FILE} | grep -w 'num.query.type.PTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_AAAA=$(cat ${FILE} | grep -w 'num.query.type.AAAA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SRV=$(cat ${FILE} | grep -w 'num.query.type.SRV' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SOA=$(cat ${FILE} | grep -w 'num.query.type.SOA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HTTPS=$(cat ${FILE} | grep -w 'num.query.type.HTTPS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TYPE0=$(cat ${FILE} | grep -w 'num.query.type.TYPE0' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_CNAME=$(cat ${FILE} | grep -w 'num.query.type.CNAME' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_WKS=$(cat ${FILE} | grep -w 'num.query.type.WKS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HINFO=$(cat ${FILE} | grep -w 'num.query.type.HINFO' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_X25=$(cat ${FILE} | grep -w 'num.query.type.X25' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NAPTR=$(cat ${FILE} | grep -w 'num.query.type.NAPTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DS=$(cat ${FILE} | grep -w 'num.query.type.DS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DNSKEY=$(cat ${FILE} | grep -w 'num.query.type.DNSKEY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TLSA=$(cat ${FILE} | grep -w 'num.query.type.TLSA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SVCB=$(cat ${FILE} | grep -w 'num.query.type.SVCB' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SPF=$(cat ${FILE} | grep -w 'num.query.type.SPF' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_ANY=$(cat ${FILE} | grep -w 'num.query.type.ANY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_OTHER=$(cat ${FILE} | grep -w 'num.query.type.other' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_ANSWER_RCODE_NOERROR=$(cat ${FILE} | grep -w 'num.answer.rcode.NOERROR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_NXDOMAIN=$(cat ${FILE} | grep -w 'num.answer.rcode.NXDOMAIN' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_SERVFAIL=$(cat ${FILE} | grep -w 'num.answer.rcode.SERVFAIL' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_REFUSED=$(cat ${FILE} | grep -w 'num.answer.rcode.REFUSED' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_nodata=$(cat ${FILE} | grep -w 'num.answer.rcode.nodata' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_secure=$(cat ${FILE} | grep -w 'num.answer.secure' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 #       Sending info to zabbix_server.&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.queries -o $(( ${TOTAL_NUM_QUERIES:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachehits -o $(( ${TOTAL_NUM_CACHEHITS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachemiss -o $(( ${TOTAL_NUM_CACHEMISS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.prefetch -o $(( ${TOTAL_NUM_PREFETCH:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.recursivereplies -o $(( ${TOTAL_NUM_RECURSIVEREPLIES:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.max -o $(( ${TOTAL_REQ_MAX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.avg -o $(( ${TOTAL_REQ_AVG:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.overwritten -o $(( ${TOTAL_REQ_OVERWRITTEN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.exceeded -o $(( ${TOTAL_REQ_EXCEEDED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.all -o $(( ${TOTAL_REQ_CURRENT_ALL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.user -o $(( ${TOTAL_REQ_CURRENT_USER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.tcpusage -o $(( ${TOTAL_TCPUSAGE:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.a -o $(( ${NUM_QUERY_TYPE_A:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ns -o $(( ${NUM_QUERY_TYPE_NS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.mx -o $(( ${NUM_QUERY_TYPE_MX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.txt -o $(( ${NUM_QUERY_TYPE_TXT:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ptr -o $(( ${NUM_QUERY_TYPE_PTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.aaaa -o $(( ${NUM_QUERY_TYPE_AAAA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.srv -o $(( ${NUM_QUERY_TYPE_SRV:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.soa -o $(( ${NUM_QUERY_TYPE_SOA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.https -o $(( ${NUM_QUERY_TYPE_HTTPS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.type0 -o $(( ${NUM_QUERY_TYPE_TYPE0:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.cname -o $(( ${NUM_QUERY_TYPE_CNAME:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.wks -o $(( ${NUM_QUERY_TYPE_WKS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.hinfo -o $(( ${NUM_QUERY_TYPE_HINFO:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.X25 -o $(( ${NUM_QUERY_TYPE_X25:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.naptr -o $(( ${NUM_QUERY_TYPE_NAPTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ds -o $(( ${NUM_QUERY_TYPE_DS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.dnskey -o $(( ${NUM_QUERY_TYPE_DNSKEY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.tlsa -o $(( ${NUM_QUERY_TYPE_TLSA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.svcb -o $(( ${NUM_QUERY_TYPE_SVCB:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.spf -o $(( ${NUM_QUERY_TYPE_SPF:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.any -o $(( ${NUM_QUERY_TYPE_ANY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.other -o $(( ${NUM_QUERY_TYPE_OTHER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NOERROR -o $(( ${NUM_ANSWER_RCODE_NOERROR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NXDOMAIN -o $(( ${NUM_ANSWER_RCODE_NXDOMAIN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.SERVFAIL -o $(( ${NUM_ANSWER_RCODE_SERVFAIL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.REFUSED -o $(( ${NUM_ANSWER_RCODE_REFUSED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.nodata -o $(( ${NUM_ANSWER_RCODE_nodata:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.secure -o $(( ${NUM_ANSWER_secure:-0} / 300 ))&lt;br /&gt;
No Zabbix será registrado dados como esses abaixo e posteriormente pode ser montado um Grafana com eles:&lt;br /&gt;
[[Arquivo:Zabbix dns01.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns02.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns03.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns04.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Mantendo a hora certa ==&lt;br /&gt;
Vamos instalar agora o Chrony para manter a data e hora certas no sistema:&lt;br /&gt;
 # apt install chrony&lt;br /&gt;
Após a instalação do Chrony edite o arquivo /etc/chrony/chrony.conf, comente e a linha abaixo e adicione seus servidores NTP. Caso não tenha servidores NTP, estou colocando os do NIC.br aqui.&lt;br /&gt;
 #pool 2.debian.pool.ntp.org iburst&lt;br /&gt;
 server a.st1.ntp.br iburst nts&lt;br /&gt;
 server b.st1.ntp.br iburst nts&lt;br /&gt;
 server c.st1.ntp.br iburst nts&lt;br /&gt;
 server d.st1.ntp.br iburst nts&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart chronyd.service&lt;br /&gt;
Cheque com o '''chronyc''' se os servidores estão OK:&lt;br /&gt;
 # chronyc sourcestats&lt;br /&gt;
 Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev&lt;br /&gt;
 ==============================================================================&lt;br /&gt;
 a.st1.ntp.br               10   5  155m     -0.027      0.030    -71us    51us&lt;br /&gt;
 b.st1.ntp.br               11   7  344m     +0.068      0.079    +23ms   382us&lt;br /&gt;
 c.st1.ntp.br                6   3  344m     +0.026      0.037   -124us    92us&lt;br /&gt;
 200.20.186.76               9   3  138m     -0.022      0.031   +172us    42us&lt;br /&gt;
&lt;br /&gt;
 # chronyc sources&lt;br /&gt;
 MS Name/IP address         Stratum Poll Reach LastRx Last sample&lt;br /&gt;
 ===============================================================================&lt;br /&gt;
 ^* a.st1.ntp.br                  1  10   377   588   +487us[ +397us] +/-   12ms&lt;br /&gt;
 ^- b.st1.ntp.br                  2  10   377   830    +23ms[  +23ms] +/-   49ms&lt;br /&gt;
 ^+ c.st1.ntp.br                  2  10    21  1038   -147us[ -242us] +/-   17ms&lt;br /&gt;
 ^+ 200.20.186.76                 1  10   377  1032   +381us[ +285us] +/-   15ms&lt;br /&gt;
&lt;br /&gt;
== Configurando o FRRouting ==&lt;br /&gt;
Nesse ponto iremos configurar o '''FRRouting''' para enviar os IPs das '''loopbacks''' e o '''/30''' para o nosso PE do diagrama. Em '''/etc/frr/daemons''' habilite o parâmetro conforme abaixo:&lt;br /&gt;
 ospfd=yes&lt;br /&gt;
 ospf6d=yes&lt;br /&gt;
Edite o arquivo '''/etc/frr/frr.conf''' e deixe com o conteúdo abaixo, para ficar conforme nosso diagrama do projeto. Apenas troque '''&amp;lt;SENHA&amp;gt;''' por uma senha para fechar o OSPF com mais segurança. Essa senha deve ser usada dos dois lados.&lt;br /&gt;
 frr version 10.3&lt;br /&gt;
 frr defaults traditional&lt;br /&gt;
 hostname dns-recursivo-01&lt;br /&gt;
 log syslog informational&lt;br /&gt;
 no ip forwarding&lt;br /&gt;
 no ipv6 forwarding&lt;br /&gt;
 service integrated-vtysh-config&lt;br /&gt;
 !&lt;br /&gt;
 interface ens18&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf message-digest-key 5 md5 &amp;lt;SENHA&amp;gt;&lt;br /&gt;
  ip ospf network point-to-point&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 network point-to-point&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 interface lo&lt;br /&gt;
  description LOOPBACKS&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf passive&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 passive&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf&lt;br /&gt;
  ospf router-id 172.16.0.6&lt;br /&gt;
  area 0.0.0.0 authentication message-digest&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf6&lt;br /&gt;
  ospf6 router-id 172.16.0.6&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart frr.service&lt;br /&gt;
Cheque se está tudo OK com o OSPF e verifique no PE se está recebendo os prefixos anunciados.&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL&lt;br /&gt;
 172.16.0.5     1 Full/-          10m49s            35.310s 172.16.0.5   ens18:172.16.0.6                  0     0     0&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri    DeadTime    State/IfState         Duration I/F[State]&lt;br /&gt;
 172.16.0.5       1    00:00:30     Full/PointToPoint 25d22:53:47 ens18[PointToPoint]&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor detail'&lt;br /&gt;
 &lt;br /&gt;
  Neighbor 172.16.0.5, interface address 172.16.0.5&lt;br /&gt;
     In the area 0.0.0.0 via interface ens18&lt;br /&gt;
     Neighbor priority is 1, State is Full/-, 5 state changes&lt;br /&gt;
     Most recent state change statistics:&lt;br /&gt;
       Progressive change 21w3d15h ago&lt;br /&gt;
     DR is 0.0.0.0, BDR is 0.0.0.0&lt;br /&gt;
     Options 18 *|-|-|EA|-|-|E|-&lt;br /&gt;
     Dead timer due in 34.685s&lt;br /&gt;
     Database Summary List 0&lt;br /&gt;
     Link State Request List 0&lt;br /&gt;
     Link State Retransmission List 0&lt;br /&gt;
     Thread Inactivity Timer on&lt;br /&gt;
     Thread Database Description Retransmision off&lt;br /&gt;
     Thread Link State Request Retransmission on&lt;br /&gt;
     Thread Link State Update Retransmission on&lt;br /&gt;
 &lt;br /&gt;
     Graceful restart Helper info:&lt;br /&gt;
       Graceful Restart HELPER Status : None&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor detail'&lt;br /&gt;
  Neighbor 172.16.0.5%ens18&lt;br /&gt;
     Area 0.0.0.0 via interface ens18 (ifindex 4)&lt;br /&gt;
     His IfIndex: 60 Link-local address: fe80::469b:c1ff:fed6:43ee&lt;br /&gt;
     State Full for a duration of 25d22:57:14&lt;br /&gt;
     His choice of DR/BDR 0.0.0.0/0.0.0.0, Priority 1&lt;br /&gt;
     DbDesc status: Master SeqNum: 0xb94b0000&lt;br /&gt;
     Summary-List: 0 LSAs&lt;br /&gt;
     Request-List: 0 LSAs&lt;br /&gt;
     Retrans-List: 0 LSAs&lt;br /&gt;
     0 Pending LSAs for DbDesc in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSReq in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSAck in Time 00:00:00 [thread off]&lt;br /&gt;
     Authentication header not present&lt;br /&gt;
&lt;br /&gt;
== Configurando o Unbound ==&lt;br /&gt;
Abaixo a configuração que usaremos nos servidores atentando para o detalhe do '''num-threads''', esse deve ter o valor igual ao número de CPUs do servidor.&lt;br /&gt;
&lt;br /&gt;
Também os IPs utilizados em '''outgoing-interface''' que serão diferentes em cada servidor, esses serão os IPs usados para '''recursividade'''. Consulte o manual do Unbound para obter mais informações sobre cada parâmetro listado na configuração.&lt;br /&gt;
&lt;br /&gt;
O tuning no Unbound pode ser alterado conforme abaixo:&lt;br /&gt;
 num-threads = nº CPUs&lt;br /&gt;
 so-reuseport = yes&lt;br /&gt;
 *-slabs = potência de 2 próximo ao num-threads&lt;br /&gt;
 msg-cache-size = 1g (quantidade de memória pra usar de cache)&lt;br /&gt;
 rrset-cache-size = 2 * msg-cache-size&lt;br /&gt;
 outgoing-range = 8192&lt;br /&gt;
 num-queries-per-thread = 4096&lt;br /&gt;
 so-rcvbuf e so-sndbuf = 4m ou 8m para servidores com muita requisição&lt;br /&gt;
Agora vamos criar nosso arquivo de configuração base em '''/etc/unbound/unbound.conf.d/local.conf''':&lt;br /&gt;
 server:&lt;br /&gt;
         verbosity: 1&lt;br /&gt;
         statistics-interval: 0&lt;br /&gt;
         statistics-cumulative: no&lt;br /&gt;
         extended-statistics: yes&lt;br /&gt;
         num-threads: 8&lt;br /&gt;
         serve-expired: yes&lt;br /&gt;
         interface: 127.0.0.1&lt;br /&gt;
         interface: 10.10.10.10&lt;br /&gt;
         interface: 10.10.9.9&lt;br /&gt;
         interface: 172.16.0.6&lt;br /&gt;
         interface: fd00::10:10:10:10&lt;br /&gt;
         interface: fd00::10:10:9:9&lt;br /&gt;
         interface: ::1&lt;br /&gt;
         interface-automatic: no&lt;br /&gt;
         outgoing-interface: 198.18.1.10&lt;br /&gt;
         outgoing-interface: 2001:db8::faca:198:18:1:10&lt;br /&gt;
         outgoing-range: 8192&lt;br /&gt;
         outgoing-num-tcp: 1024&lt;br /&gt;
         incoming-num-tcp: 2048&lt;br /&gt;
         so-rcvbuf: 4m&lt;br /&gt;
         so-sndbuf: 4m&lt;br /&gt;
         so-reuseport: yes&lt;br /&gt;
         edns-buffer-size: 1232&lt;br /&gt;
         msg-cache-size: 512m&lt;br /&gt;
         msg-cache-slabs: 4&lt;br /&gt;
         num-queries-per-thread: 4096&lt;br /&gt;
         rrset-cache-size: 1g&lt;br /&gt;
         rrset-cache-slabs: 4&lt;br /&gt;
         infra-cache-slabs: 4&lt;br /&gt;
         do-ip4: yes&lt;br /&gt;
         do-ip6: yes&lt;br /&gt;
         do-udp: yes&lt;br /&gt;
         do-tcp: yes&lt;br /&gt;
         chroot: &amp;quot;&amp;quot;&lt;br /&gt;
         username: &amp;quot;unbound&amp;quot;&lt;br /&gt;
         directory: &amp;quot;/etc/unbound&amp;quot;&lt;br /&gt;
         logfile: &amp;quot;/var/log/unbound/unbound.log&amp;quot;&lt;br /&gt;
         use-syslog: no&lt;br /&gt;
         log-time-ascii: yes&lt;br /&gt;
         log-queries: no&lt;br /&gt;
         pidfile: &amp;quot;/var/run/unbound.pid&amp;quot;&lt;br /&gt;
         root-hints: &amp;quot;/usr/share/dns/root.hints&amp;quot;&lt;br /&gt;
         hide-identity: yes&lt;br /&gt;
         hide-version: yes&lt;br /&gt;
         unwanted-reply-threshold: 10000000&lt;br /&gt;
         prefetch: yes&lt;br /&gt;
         prefetch-key: yes&lt;br /&gt;
         rrset-roundrobin: yes&lt;br /&gt;
         minimal-responses: yes&lt;br /&gt;
         module-config: &amp;quot;respip validator iterator&amp;quot;&lt;br /&gt;
         val-clean-additional: yes&lt;br /&gt;
         val-log-level: 1&lt;br /&gt;
         key-cache-slabs: 4&lt;br /&gt;
         deny-any: yes&lt;br /&gt;
         cache-min-ttl: 60&lt;br /&gt;
         key-cache-size: 128m&lt;br /&gt;
         neg-cache-size: 64m&lt;br /&gt;
         cache-max-ttl: 86400&lt;br /&gt;
         infra-cache-numhosts: 100000&lt;br /&gt;
         access-control: 198.18.0.0/22 allow&lt;br /&gt;
         access-control: 2001:db8::/32 allow&lt;br /&gt;
  &lt;br /&gt;
 rpz:&lt;br /&gt;
   name: rpz.block.host.local.zone&lt;br /&gt;
   zonefile: /etc/unbound/rpz.block.hosts.zone&lt;br /&gt;
   rpz-action-override: nxdomain&lt;br /&gt;
  &lt;br /&gt;
 python:&lt;br /&gt;
  &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;.&amp;quot;&lt;br /&gt;
     master: &amp;quot;b.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;c.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;d.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;f.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;g.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;k.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/root.zone&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;arpa.&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/arpa.zone&amp;quot;&lt;br /&gt;
No parâmetro '''interface''' colocamos os IPs que serão usados para consulta dos clientes como o '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9'''. Ali repare que coloquei também o IP privado '''172.16.0.6''', isso porque cada servidor terá o seu IP privado e este deve ser usado pelo seu sistema de monitoramento para checar cada servidor. No '''outgoing-interface''' teremos os IPs, tanto '''IPv4''' quanto '''IPv6''', para que seja feita a recursividade na Internet utilizando eles. Não tem '''IPv6''' ainda na sua rede? Dê uma olhada nesse artigo. Outro parâmetro importante é o '''access-control''' e é através dele que liberamos os prefixos IP para consultarem no nosso DNS Recursivo. No exemplo estou liberando todo o prefixo '''198.18.0.0/22''' e o prefixo '''2001:db8::/32'''. Além da ACL no Unbound, recomendo que crie um filtro de pacotes com iptables ou nftables protegendo seu sistema e liberando as portas '''53/UDP''', '''53/TCP,'''  '''443/TCP e 853/TCP''' apenas para seus clientes. Falarei sobre a '''443/TCP e 853/TCP''' mais para frente nessa mesma documentação.&lt;br /&gt;
&lt;br /&gt;
Agora criaremos o arquivo '''RPZ''' ('''Response Policy Zones'''). Esse arquivo contém os sites que serão bloqueados via '''&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; Recursivo'''. São aqueles sites que às vezes você recebe um Ofício da Justiça solicitando o bloqueio deles. Não entrarei no mérito da efetividade desses bloqueios, porque muitos de vocês sabem que tecnicamente, existem formas de se fazer um bypass através desses bloqueios. Contudo vamos deixar nosso ambiente preparado para esses bloqueios e por isso crie o arquivo '''/etc/unbound/rpz.block.hosts.zone''' com esse conteúdo de exemplo:&lt;br /&gt;
 $TTL 2h&lt;br /&gt;
 @ IN SOA localhost. root.localhost. (2 6h 1h 1w 2h)&lt;br /&gt;
   IN NS  localhost.&lt;br /&gt;
 ; RPZ manual block hosts&lt;br /&gt;
 *.josedascoves.com CNAME .&lt;br /&gt;
 josedascoves.com CNAME .&lt;br /&gt;
No exemplo acima estamos bloqueando qualquer consulta de DNS para '''josedascoves.com''' ou qualquer coisa '''.josedascoves.com'''.&lt;br /&gt;
&lt;br /&gt;
Para testar podemos fazer assim do próprio servidor:&lt;br /&gt;
 # host josedascoves.com ::1&lt;br /&gt;
 Using domain server:&lt;br /&gt;
 Name: ::1&lt;br /&gt;
 Address: ::1#53&lt;br /&gt;
 Aliases:&lt;br /&gt;
 &lt;br /&gt;
 Host josedascoves.com not found: 3(NXDOMAIN)&lt;br /&gt;
Se a resposta for '''NXDOMAIN''' então está funcionando o bloqueio. Para incluir novos bloqueios basta adicionar os domínios, um abaixo do outro, conforme o exemplo que coloquei no arquivo RPZ.&lt;br /&gt;
&lt;br /&gt;
== Acertando o resolv.conf ==&lt;br /&gt;
Vamos modificar nosso /etc/resolv.conf para utilizar DNS externo. Sim você deve estar se perguntando em qual situação isso seria utilizado. Primeiro entenda que o Unbound não irá utilizar o DNS externo para fazer as consultas na Internet e sim, qualquer teste que você faça do servidor precisará apontar para o Unbound usando os IPs '''127.0.0.1''' ou '''::1'''. Faremos isso pela seguinte situação: imagine que o daemon unbound morreu mas você ainda continua com conectividade na Internet. Você conseguiria acessar qualquer local na Internet através do IP mas não através do hostname porque não conseguiria resolver nomes, seu unbound estaria fora do ar. Imagine ainda que você gostaria que seu servidor te avisasse do problema via Telegram ou e-mail. Por isso estamos utilizando um DNS externo no '''/etc/resolv.conf''', apenas para essas situações. Se você não quiser utilizar desse recurso, pode usar o '''127.0.0.1''' e '''::1''' no lugar.&lt;br /&gt;
 nameserver 8.8.8.8&lt;br /&gt;
 nameserver 8.8.4.4&lt;br /&gt;
 nameserver 2001:4860:4860::8888&lt;br /&gt;
&lt;br /&gt;
== Script de teste de recursividade ==&lt;br /&gt;
Estamos montando uma '''Rede de DNS Recursivo Anycast''', então é muito importante que você monitore essa rede para saber se algum node morreu e iniciar o troubleshooting, resolver o problema e levantar o sistema novamente. Tudo isso é importante mas o cliente não deve ficar esperando até você resolver o problema, seu sistema precisa ser inteligente o suficiente para se remover da Rede quando tiver um problema e se inserir novamente, quando o problema estiver sido solucionado. Se você montar uma Rede de DNS e um dos nodes apresentar algum problema, todos os clientes atendidos por aquele node migrarão automaticamente e transparentemente para outro '''DNS Recursivo Anycast''' mais próximo. Isso se chama '''disponibilidade'''.&lt;br /&gt;
&lt;br /&gt;
O script '''/root/scripts/checa_dns.sh''' abaixo tem a função de fazer os testes de recursividade e checar se o daemon do unbound continua rodando. Se algo acontecer, ele para o anúncio do '''10.10.10.10''' e '''10.10.9.9''' e retorna eles quando tudo estiver resolvido.&lt;br /&gt;
 # mkdir /root/scripts&lt;br /&gt;
&lt;br /&gt;
 #!/usr/bin/env bash&lt;br /&gt;
 #Script para teste de DNS v2.1&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 #Informe um domínio por linha:&lt;br /&gt;
 dominios_testar=(&lt;br /&gt;
 www.google.com&lt;br /&gt;
 www.terra.com.br&lt;br /&gt;
 www.uol.com.br&lt;br /&gt;
 www.globo.com&lt;br /&gt;
 www.facebook.com&lt;br /&gt;
 www.youtube.com&lt;br /&gt;
 www.twitch.com&lt;br /&gt;
 www.discord.com&lt;br /&gt;
 www.debian.org&lt;br /&gt;
 www.redhat.com&lt;br /&gt;
 )&lt;br /&gt;
 corte_taxa_falha=100 #Porcentagem de falha para executar uma ação&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 remove_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; != &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no description' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME morreu!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 adiciona_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; == &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'description LOOPBACKS' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME retornou do inferno!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
 if [ $? -ne 0 ]; then&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME morreu DNS mas tentando levantar!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    systemctl restart unbound&lt;br /&gt;
    systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
    if [ $? -ne 0 ]; then&lt;br /&gt;
       remove_ospf&lt;br /&gt;
       exit&lt;br /&gt;
    fi&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME servico DNS voltou mas tinha morrido!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 qt_falhas=0&lt;br /&gt;
 qt_total=&amp;quot;${#dominios_testar[@]}&amp;quot;&lt;br /&gt;
 echo &amp;quot;total_dominios: $qt_total&amp;quot;&lt;br /&gt;
 for site in &amp;quot;${dominios_testar[@]}&amp;quot;&lt;br /&gt;
 do&lt;br /&gt;
   unbound-control flush $site &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   resolver=&amp;quot;127.0.0.1&amp;quot;&lt;br /&gt;
   echo -e &amp;quot; - dominio $site - $resolver - \c&amp;quot;&lt;br /&gt;
   host $site $resolver &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   if [ $? -ne 0 ]; then&lt;br /&gt;
      ((qt_falhas++))&lt;br /&gt;
      echo -e &amp;quot;[Falhou]&amp;quot;&lt;br /&gt;
   else&lt;br /&gt;
      echo -e &amp;quot;[OK]&amp;quot;&lt;br /&gt;
   fi&lt;br /&gt;
 done&lt;br /&gt;
  &lt;br /&gt;
 taxa_falha=$((qt_falhas*100/qt_total))&lt;br /&gt;
 echo &amp;quot;Falhas $qt_falhas/$qt_total ($taxa_falha%)&amp;quot;&lt;br /&gt;
  &lt;br /&gt;
 if [ &amp;quot;$taxa_falha&amp;quot; -ge &amp;quot;$corte_taxa_falha&amp;quot; ]; then&lt;br /&gt;
    remove_ospf&lt;br /&gt;
    exit&lt;br /&gt;
 fi&lt;br /&gt;
 adiciona_ospf&lt;br /&gt;
Se rodarmos o script manualmente veremos isto:&lt;br /&gt;
 # /root/scripts/checa_dns.sh&lt;br /&gt;
 total_dominios: 10&lt;br /&gt;
  - dominio www.google.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.terra.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.uol.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.globo.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.facebook.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.youtube.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.twitch.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.discord.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.debian.org - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.redhat.com - 127.0.0.1 - [OK]&lt;br /&gt;
 Falhas 0/10 (0%)&lt;br /&gt;
Se acontecer 100% de falhas o script irá remover os anúncios do OSPF. Se o daemon do unbound morrer, ele tentará reiniciá-lo. Se tudo normalizar o script irá retornar os anúncios para o OSPF. Deixei comentado no script as partes que enviariam uma notificação para o Telegram. Existem diversas documentações sobre isso na Internet, eu mesmo tenho uma. Assim que eu publicar aqui, atualizo essa documentação e sinta-se à vontade de modificar como desejar.&lt;br /&gt;
 # chmod 700 /root/scripts/checa_dns.sh&lt;br /&gt;
Adicione a linha abaixo em seu '''/etc/crontab''':&lt;br /&gt;
 */1 *   * * *   root    /root/scripts/checa_dns.sh&lt;br /&gt;
&lt;br /&gt;
== Habilitando o DoH (&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; over HTTPS) - opcional ==&lt;br /&gt;
Para habilitar o '''DoH''' no Unbound é bem simples. O recurso do '''DoH''' vem para trazer mais segurança e privacidade para o usuário. É um recurso muito pouco utilizado ainda mas que seu cliente pode vir a pedir algum dia.&lt;br /&gt;
&lt;br /&gt;
Você precisará gerar certificados SSL legítimos e para isso você poderá usar o '''Let's Encrypt''' só que de uma forma não tão convencional.&lt;br /&gt;
&lt;br /&gt;
Na sequência vamos instalar o Let's Encrypt para gerarmos nosso certificado SSL:&lt;br /&gt;
 # apt install letsencrypt&lt;br /&gt;
Escolha um '''hostname''' para ser usado no nosso '''DoH''' e aponte ele no seu DNS Autoritativo para seus IPs 10.10.10.10 e 10.10.9.9. Aqui vamos usar o seguinte como exemplo: '''doh.brasilpeeringforum.org'''. Para gerarmos nosso certificado iremos usar o tipo '''DNS-01''', ele não necessita que tenhamos um servidor web rodando no servidor e nem tão pouco levanta um serviço na porta 80 para checar o hostname. Ele utiliza o DNS como validador e vai te solicitar que crie um registro '''CNAME''' no seu '''DNS Autoritativo''' para provar que você tem o controle sobre aquele hostname. Antes disso vamos instalar um programa em Python para podermos automatizar nossa renovação de certificado no futuro. Esse programa se encontra '''[https://github.com/joohoi/acme-dns-certbot-joohoi/raw/master/acme-dns-auth.py aqui]''' mas vou deixá-lo abaixo já modificado o interpretador.&lt;br /&gt;
&lt;br /&gt;
Crie o arquivo '''/etc/letsencrypt/acme-dns-auth.py''' com o conteúdo abaixo:&lt;br /&gt;
 #!/usr/bin/env python3&lt;br /&gt;
 import json&lt;br /&gt;
 import os&lt;br /&gt;
 import requests&lt;br /&gt;
 import sys&lt;br /&gt;
 &lt;br /&gt;
 ### EDIT THESE: Configuration values ###&lt;br /&gt;
 &lt;br /&gt;
 # URL to acme-dns instance&lt;br /&gt;
 ACMEDNS_URL = &amp;quot;&amp;lt;nowiki&amp;gt;https://auth.acme-dns.io&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
 # Path for acme-dns credential storage&lt;br /&gt;
 STORAGE_PATH = &amp;quot;/etc/letsencrypt/acmedns.json&amp;quot;&lt;br /&gt;
 # Whitelist for address ranges to allow the updates from&lt;br /&gt;
 # Example: ALLOW_FROM = [&amp;quot;192.168.10.0/24&amp;quot;, &amp;quot;::1/128&amp;quot;]&lt;br /&gt;
 ALLOW_FROM = []&lt;br /&gt;
 # Force re-registration. Overwrites the already existing acme-dns accounts.&lt;br /&gt;
 FORCE_REGISTER = False&lt;br /&gt;
 &lt;br /&gt;
 ###   DO NOT EDIT BELOW THIS POINT   ###&lt;br /&gt;
 ###         HERE BE DRAGONS          ###&lt;br /&gt;
 &lt;br /&gt;
 DOMAIN = os.environ[&amp;quot;CERTBOT_DOMAIN&amp;quot;]&lt;br /&gt;
 if DOMAIN.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
     DOMAIN = DOMAIN[2:]&lt;br /&gt;
 VALIDATION_DOMAIN = &amp;quot;_acme-challenge.&amp;quot;+DOMAIN&lt;br /&gt;
 VALIDATION_TOKEN = os.environ[&amp;quot;CERTBOT_VALIDATION&amp;quot;]&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 class AcmeDnsClient(object):&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
     Handles the communication with ACME-DNS API&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
     def __init__(self, acmedns_url):&lt;br /&gt;
         self.acmedns_url = acmedns_url&lt;br /&gt;
 &lt;br /&gt;
     def register_account(self, allowfrom):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Registers a new ACME-DNS account&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
         if allowfrom:&lt;br /&gt;
             # Include whitelisted networks to the registration call&lt;br /&gt;
             reg_data = {&amp;quot;allowfrom&amp;quot;: allowfrom}&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;,&lt;br /&gt;
                                 data=json.dumps(reg_data))&lt;br /&gt;
         else:&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;)&lt;br /&gt;
         if res.status_code == 201:&lt;br /&gt;
             # The request was successful&lt;br /&gt;
             return res.json()&lt;br /&gt;
         else:&lt;br /&gt;
             # Encountered an error&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to register a new acme-dns &amp;quot;&lt;br /&gt;
                    &amp;quot;account. HTTP status {}, Response body: {}&amp;quot;)&lt;br /&gt;
             print(msg.format(res.status_code, res.text))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def update_txt_record(self, account, txt):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Updates the TXT challenge record to ACME-DNS subdomain.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         update = {&amp;quot;subdomain&amp;quot;: account['subdomain'], &amp;quot;txt&amp;quot;: txt}&lt;br /&gt;
         headers = {&amp;quot;X-Api-User&amp;quot;: account['username'],&lt;br /&gt;
                    &amp;quot;X-Api-Key&amp;quot;: account['password'],&lt;br /&gt;
                    &amp;quot;Content-Type&amp;quot;: &amp;quot;application/json&amp;quot;}&lt;br /&gt;
         res = requests.post(self.acmedns_url+&amp;quot;/update&amp;quot;,&lt;br /&gt;
                             headers=headers,&lt;br /&gt;
                             data=json.dumps(update))&lt;br /&gt;
         if res.status_code == 200:&lt;br /&gt;
             # Successful update&lt;br /&gt;
             return&lt;br /&gt;
         else:&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to update TXT record in &amp;quot;&lt;br /&gt;
                    &amp;quot;acme-dns. \n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request headers:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request body:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response HTTP status: {}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response body: {}&amp;quot;)&lt;br /&gt;
             s_headers = json.dumps(headers, indent=2, sort_keys=True)&lt;br /&gt;
             s_update = json.dumps(update, indent=2, sort_keys=True)&lt;br /&gt;
             s_body = json.dumps(res.json(), indent=2, sort_keys=True)&lt;br /&gt;
             print(msg.format(s_headers, s_update, res.status_code, s_body))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
 class Storage(object):&lt;br /&gt;
     def __init__(self, storagepath):&lt;br /&gt;
         self.storagepath = storagepath&lt;br /&gt;
         self._data = self.load()&lt;br /&gt;
 &lt;br /&gt;
     def load(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Reads the storage content from the disk to a dict structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         data = dict()&lt;br /&gt;
         filedata = &amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             with open(self.storagepath, 'r') as fh:&lt;br /&gt;
                 filedata = fh.read()&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             if os.path.isfile(self.storagepath):&lt;br /&gt;
                 # Only error out if file exists, but cannot be read&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage file exists but cannot be read&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         try:&lt;br /&gt;
             data = json.loads(filedata)&lt;br /&gt;
         except ValueError:&lt;br /&gt;
             if len(filedata) &amp;gt; 0:&lt;br /&gt;
                 # Storage file is corrupted&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage JSON is corrupted&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         return data&lt;br /&gt;
 &lt;br /&gt;
     def save(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Saves the storage content to disk&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         serialized = json.dumps(self._data)&lt;br /&gt;
         try:&lt;br /&gt;
             with os.fdopen(os.open(self.storagepath,&lt;br /&gt;
                                    os.O_WRONLY | os.O_CREAT, 0o600), 'w') as fh:&lt;br /&gt;
                 fh.truncate()&lt;br /&gt;
                 fh.write(serialized)&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             print(&amp;quot;ERROR: Could not write storage file.&amp;quot;)&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def put(self, key, value):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Puts the configuration value to storage and sanitize it&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         # If wildcard domain, remove the wildcard part as this will use the&lt;br /&gt;
         # same validation record name as the base domain&lt;br /&gt;
         if key.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
             key = key[2:]&lt;br /&gt;
         self._data[key] = value&lt;br /&gt;
 &lt;br /&gt;
     def fetch(self, key):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Gets configuration value from storage&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             return self._data[key]&lt;br /&gt;
         except KeyError:&lt;br /&gt;
             return None&lt;br /&gt;
 &lt;br /&gt;
 if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
     # Init&lt;br /&gt;
     client = AcmeDnsClient(ACMEDNS_URL)&lt;br /&gt;
     storage = Storage(STORAGE_PATH)&lt;br /&gt;
 &lt;br /&gt;
     # Check if an account already exists in storage&lt;br /&gt;
     account = storage.fetch(DOMAIN)&lt;br /&gt;
     if FORCE_REGISTER or not account:&lt;br /&gt;
         # Create and save the new account&lt;br /&gt;
         account = client.register_account(ALLOW_FROM)&lt;br /&gt;
         storage.put(DOMAIN, account)&lt;br /&gt;
         storage.save()&lt;br /&gt;
 &lt;br /&gt;
         # Display the notification for the user to update the main zone&lt;br /&gt;
         msg = &amp;quot;Please add the following CNAME record to your main DNS zone:\n{}&amp;quot;&lt;br /&gt;
         cname = &amp;quot;{} CNAME {}.&amp;quot;.format(VALIDATION_DOMAIN, account[&amp;quot;fulldomain&amp;quot;])&lt;br /&gt;
         print(msg.format(cname))&lt;br /&gt;
 &lt;br /&gt;
     # Update the TXT record in acme-dns instance&lt;br /&gt;
     client.update_txt_record(account, VALIDATION_TOKEN)&lt;br /&gt;
&lt;br /&gt;
 # chmod +x /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
Usaremos a seguinte instrução para criar nosso certificado:&lt;br /&gt;
 # certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d doh.brasilpeeringforum.org&lt;br /&gt;
 Saving debug log to /var/log/letsencrypt/letsencrypt.log&lt;br /&gt;
 Plugins selected: Authenticator manual, Installer None&lt;br /&gt;
 Cert is due for renewal, auto-renewing...&lt;br /&gt;
 Renewing an existing certificate for doh.brasilpeeringforum.org&lt;br /&gt;
 Performing the following challenges:&lt;br /&gt;
 dns-01 challenge for doh.brasilpeeringforum.org&lt;br /&gt;
 Running manual-auth-hook command: /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
 Output from manual-auth-hook command acme-dns-auth.py:&lt;br /&gt;
 Please add the following CNAME record to your main DNS zone:&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
 &lt;br /&gt;
 Waiting for verification...&lt;br /&gt;
 &lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Challenges loaded. Press continue to submit to CA. Pass &amp;quot;-v&amp;quot; for more info about&lt;br /&gt;
 challenges.&lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Press Enter to Continue&lt;br /&gt;
Nesse momento você cria o registro '''CNAME''' no seu DNS Autoritativo conforme ele solicitou: '''_acme-challenge.doh.brasilpeeringforum.org IN CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.''' e somente depois de criado e checado no DNS, você pressiona o '''Enter''' para continuar. Você pode checar dessa forma:&lt;br /&gt;
 # host -t cname _acme-challenge.doh.brasilpeeringforum.org&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org is an alias for b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
Para que nosso certificado seja automaticamente renovado colocaremos no '''/etc/crontab''' a seguinte linha abaixo:&lt;br /&gt;
 00 00   1 * *   root    /usr/bin/certbot -q renew --deploy-hook &amp;quot;/usr/sbin/unbound-control reload_keep_cache&amp;quot;&lt;br /&gt;
Acima temos a instrução para renovação automática do certificado. Repare que você vai precisar também copiar esse certificado para seus outros servidores, escolha um servidor para manter o certificado sempre atualizado e crie um script que faça a mesma cópia remotamente para os outros servidores. O '''scp''' e o '''rsync''' são seus aliados nisso.&lt;br /&gt;
&lt;br /&gt;
=== Configurando o Unbound ===&lt;br /&gt;
Em nosso '''/etc/unbound/unbound.conf.d/local.conf''', adicionaremos no bloco &amp;quot;'''server:'''&amp;quot; o seguinte:&lt;br /&gt;
 interface: 10.10.10.10@443 &lt;br /&gt;
 interface: 10.10.9.9@443&lt;br /&gt;
 interface: fd00::10:10:10:10@443&lt;br /&gt;
 interface: fd00::10:10:9:9@443&lt;br /&gt;
 tls-service-key: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/privkey.pem&amp;quot; &lt;br /&gt;
 tls-service-pem: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/fullchain.pem&amp;quot;&lt;br /&gt;
Para usar o recurso do '''DoH''' você precisará habilitar o recurso no seu navegador e informar a URL. Vou colocar o exemplo do '''Google Chrome''': Digite '''chrome://settings/security?search=dns''' no seu Chrome e ative '''Usar DNS seguro''', selecione '''Personalizado''' e adicione nossa URL:&lt;br /&gt;
[[Arquivo:Doh bpf2.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Finalizando ==&lt;br /&gt;
Aqui finalizamos nosso projeto para uma Rede de DNS(s) Recursivos Anycast com Hyperlocal. Esse projeto é escalável, seguro, resiliente e você entregará muito mais qualidade de Internet para o seu cliente. Pare de entregar o '''8.8.8.8''' para os seus clientes, você está contribuindo para uma Internet mais lenta, sem a qualidade que o seu cliente merece. Investi meu tempo, que é muito pouco, para deixar esse documento para a comunidade, para você melhorar o seu ISP, para dar um UP! nele, então vamos começar 2023 com o pé direito. O que acha?&lt;br /&gt;
&lt;br /&gt;
Como prova de conceito, uma imagem abaixo onde temos uma Rede em produção de DNS(s) Recursivos Anycast e apontando exatamente o momento em que houve alguma situação que fez com que as queries de DNS, convergissem de um node para outro, de forma transparente e automática para o cliente. Podemos notar também que ao ser resolvido o problema, o tráfego retornou para o seu node correto:&lt;br /&gt;
[[Arquivo:Convergencia.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== KINDNS (Stands for Knowledge-Sharing and Instantiating Norms for DNS and Naming Security) ==&lt;br /&gt;
Achou que havia terminado? Agora que você tem a capacidade de montar uma '''Rede de DNS Recursivo''' com todas essas features acima, com todas as ferramentas que foram comentadas, o que acha de certificar o que fez?&lt;br /&gt;
&lt;br /&gt;
Assim como o [https://www.manrs.org/ MANRS] veio para certificar nosso sistema de roteamento na Internet, agora temos o [https://kindns.org/ KINDNS] para certificar que nossos sistemas de DNS estão bem feitos e dentro dos padrões de segurança. Existem '''7 ações''' que podem ser certificadas para nossos DNS Recursivos e estão aqui em https://kindns.org/shared-private-resolvers/. Com essa nossa documentação, se bem aplicada, você pode se candidatar ao KINDNS e ter seu ASN listado aqui https://kindns.org/participants/&lt;br /&gt;
&lt;br /&gt;
Obter e manter o '''MANRS''' e '''KINDNS''' demonstra seu compromisso com as Boas Práticas, contribui para termos uma '''Internet''' mais segura e te abre portas para novos negócios que possam exigir essas conformidades.&lt;br /&gt;
&lt;br /&gt;
Autor: [[Usuário:Gondim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Infraestrutura]]&lt;br /&gt;
__FORCARTDC__&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3987</id>
		<title>DNS Recursivo Anycast Hyperlocal</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3987"/>
		<updated>2025-11-24T14:59:16Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
==Introdução==&lt;br /&gt;
Você sabe como funciona a Internet? Essa é uma pergunta que meu amigo '''Thiago Ayub''' sempre faz aos seus candidatos à vagas de emprego e não importa o quanto tenham de experiência em '''Engenharia de Redes''', todos sempre travam nesse momento. Todos estão sempre prontos e preparados para resolver os problemas mais cabeludos em '''BGP''', '''OSPF''', '''MPLS''', etc mas travam com essa simples pergunta. Para contextualizar e visualizarmos melhor vamos nos atentar à imagem abaixo e uma explicação simplificada de como funciona:&lt;br /&gt;
[[Arquivo:Dns hierarquia.png|esquerda|commoldura]]&lt;br /&gt;
Tudo começa com um usuário sentado confortavelmente e querendo acessar um conteúdo disponível na Internet. Ele digita em seu navegador preferido a URL: '''&amp;lt;nowiki&amp;gt;https://wiki.brasilpeeringforum.org&amp;lt;/nowiki&amp;gt;''',&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;1)&amp;lt;/big&amp;gt;''' &amp;lt;big&amp;gt;O&amp;lt;/big&amp;gt; &amp;lt;big&amp;gt;navegador irá requisitar do '''DNS Recursivo''' utilizado pelo usuário, o '''endereço IP''' que responde pelo nome '''wiki.'''&amp;lt;/big&amp;gt;'''brasilpeeringforum.org'''&amp;lt;big&amp;gt;. Isso porque todos os acessos se dão na Internet através do '''endereço''' '''IP''' e não através do '''nome'''. Imaginem se tivéssemos que decorar os endereços IPs de todos os sites e serviços que quiséssemos acessar na Internet?&amp;lt;/big&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;big&amp;gt;'''2)''' Nosso DNS Recursivo checa se a informação consta em seu cache.&amp;lt;/big&amp;gt; Se a informação existir ela é devolvida ao navegador do usuário e aí este consegue acessar o site.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Do contrário o DNS Recursivo pergunta ao '''Root Server''' quem é o '''TLD (Top Level Domain)''' responsável para atender a requisição. &lt;br /&gt;
&lt;br /&gt;
'''4)''' O '''Root Server''' informa ao DNS Recursivo o endereço do '''TLD responsável'''. No Brasil o '''TLD''' responsável pelo '''.br''' seria o '''Registro.br'''.&lt;br /&gt;
&lt;br /&gt;
'''5)''' O DNS Recursivo pergunta ao '''TLD''' sobre '''wiki.brasilpeeringforum.org''' e este responde com os endereços IP dos '''DNS Autoritativos''' responsáveis pelo domínio '''brasilpeeringforum.org.'''&lt;br /&gt;
&lt;br /&gt;
'''6)''' O DNS Recursivo pergunta aos '''DNS Autoritativos''' pelo '''wiki.brasilpeeringforum.org''' e este responde com o '''endereço IP'''.&lt;br /&gt;
&lt;br /&gt;
'''7)''' Por último o DNS Recursivo devolve a informação para o navegador do usuário.&lt;br /&gt;
&lt;br /&gt;
Como que se dá a comunicação entre os '''DNS(s) Recursivos, Root Servers, TLDs''' e '''Autoritativos'''? Como que o navegador do usuário, após receber o IP do site, consegue chegar no servidor que tem o conteúdo? Isso só é possível devido ao protocolo chamado '''BGP (Border Gateway Protocol)''', todos os caminhos que conhecemos como rotas de destino, são anunciadas por milhares de participantes na '''Internet''' conhecidos como '''AS (Autonomous System)''', esses participantes se interligam para disponibilizar conteúdos e acessos pelo mundo aos milhares de usuários. É uma imensa rede colaborativa formada por Empresas, Universidades, Governos e todos que queiram se interconectar. Percebam que sem o '''BGP''', que serve de caminho para chegarmos nos conteúdos e sem o '''DNS (Domain Name System)''' para traduzir o nome para o endereço IP, a '''Internet''' não funcionaria e por isso precisamos cuidar muito bem desses dois serviços.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Mas não acaba por aí. O '''DNS Recursivo''' tem um papel muito importante para o Provedor de Internet e que envolve segurança, qualidade de acesso à Internet e a disponibilidade do serviço entregue ao cliente. Quando bem configurado acelera as consultas dos acessos graças ao seu cache interno, mas para que isso seja percebido pelo assinante, é necessário que esteja o mais próximo possível do seu cliente.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Um erro que destrói a qualidade do nosso serviço ==&lt;br /&gt;
Um erro muito comum que muitas operadoras cometem é utilizar DNS Recursivo externo, como o '''8.8.8.8''', '''1.1.1.1''' e outros, para seus clientes. Quanto mais próximo dos seus clientes, mais qualidade de serviço estará entregando a eles. Conteúdos serão entregues mais rapidamente pois serão resolvidos e armazenados em caches locais e não consultados remotamente na Internet. Para falar mais sobre isso, te convido leitor desse documento, que assista essa palestra do '''Thiago Ayub''' no '''GTER 51/GTS 37''' (2022) '''8.888 MOTIVOS PARA NÃO USAR DNS RECURSIVO EXTERNO EM SEU AS''': https://www.youtube.com/watch?v=Rsvpu5uF2Io&lt;br /&gt;
&lt;br /&gt;
== Objetivo ==&lt;br /&gt;
O objetivo desta documentação não é te ensinar tudo sobre '''DNS''', '''BGP''', '''OSPF''' e nem tão pouco sobre GNU/Linux e sim te mostrar um exemplo de servidor DNS Recursivo implementado pensando em segurança, qualidade e resiliência. Usaremos em todas as nossas documentações o [https://www.debian.org/ Debian GNU/Linux], por ser uma distribuição que considero uma obra de arte criada por uma enorme comunidade séria, com vasta experiência de anos, qualidade no empacotamento dos programas, estável e com uma equipe de segurança excelente e ativa. Caso você leitor, utilize alguma outra distribuição GNU/Linux, todo conteúdo apresentado aqui pode ser aplicado em outras distros, desde que respeitando as particularidades de cada uma.&lt;br /&gt;
&lt;br /&gt;
Aqui construiremos um sistema do tipo '''Anycast''', ou seja, terás o serviço rodando em diversas localidades da sua Rede utilizando o mesmo endereçamento IP e que atenderá seu cliente mais próximo. Em caso de falhas, seus clientes automaticamente e de forma transparente continuarão consultando o DNS mais próximo deles. Para que ele funcione dessa forma você precisará ter uma '''Rede OSPF''' implementada no seu Provedor Internet ou algum outro protocolo como por exemplo o '''ISIS,''' mas esse documento não irá abordar o '''ISIS'''. Também utilizaremos o '''Hyperlocal''' como recurso adicional para gerar algumas proteções de segurança e velocidade na resposta relacionada aos servidores de DNS Raiz da Internet.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
Para exemplificar nosso servidor de DNS Recursivo, usaremos como base das explicações um diagrama demonstrando o uso do DNS Recursivo em uma Rede fictícia. Adotaremos IPs privados e reservados para demonstrar todo o ambiente do Provedor de Internet.&lt;br /&gt;
[[Arquivo:Recursivo99.png|esquerda|miniaturadaimagem|695x695px]]&lt;br /&gt;
Nesse diagrama podemos observar alguns detalhes técnicos como por exemplo: existem '''3 servidores de DNS Recursivo''' posicionados em locais diferentes, que poderiam estar em bairros diferentes e até em cidades diferentes. Em cada servidor teremos '''2 loopbacks''' com os IPs:&lt;br /&gt;
&lt;br /&gt;
'''10.10.10.10/32 - fd00::10:10:10:10/128'''&lt;br /&gt;
&lt;br /&gt;
'''10.10.9.9/32 - fd00::10:10:9:9/128'''&lt;br /&gt;
&lt;br /&gt;
Esses IPs serão entregues pelos concentradores '''PPPoE''' ou '''IPoE''' ('''BNG''') para seus clientes como '''DNS primário''' e '''secundário'''. Podemos usar IPs privados como DNS primário e secundário em um ambiente real? Sim podemos, desde que não sejam IPs que possam ter problemas com as redes privadas dos clientes. Ex.: rede do cliente usando '''192.168.0.0/24'''. Se entregarmos o DNS sendo '''192.168.0.10''' e '''192.168.0.20''' teremos problemas e o cliente ficará sem Internet, porque '''192.168.0.10''' e '''192.168.0.20''' fazem parte da rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
Agora entregando '''10.10.10.10,''' '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9''' não teríamos problemas com a rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
'''Motivos para usarmos IPs privados:'''&lt;br /&gt;
* O principal motivo está relacionado com a segurança, uma vez que sendo um IP privado, não pode sofrer ataques DDoS direcionados diretamente para ele, vindos da Internet.&lt;br /&gt;
* Nem mesmo o cliente da sua rede conhece os '''IPs públicos''' utilizados para recursividade na Internet.&lt;br /&gt;
* Memorizar os IPs '''10.10.10.10''' e '''10.10.9.9''' é tão fácil quanto memorizar o '''8.8.8.8''' e o '''1.1.1.1'''. Mais fácil para o seu técnico guardar essa informação e utilizar onde for necessário.&lt;br /&gt;
Cada servidor DNS Recursivo possui um '''IPv4 público''', aqui representado por '''198.18.x.x/27''' e um '''IPv6 global''' representado por um IP dentro do prefixo '''2001:db8::/32'''. Cada servidor precisa ter os seus próprios IPs e são através destes IPs que as consultas de DNS serão realizadas na Internet.&lt;br /&gt;
&lt;br /&gt;
Nessa topologia usando '''Anycast''', o cliente será sempre atendido pelo '''DNS Recursivo''' mais próximo, desde que os pesos no '''OSPF''' estejam ajustados corretamente.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
== Dados do servidor ==&lt;br /&gt;
Podemos utilizar um sistema virtualizado ou não. Sistemas virtualizados são bem vindos pois são mais simples quando precisamos fazer backups, levantar outros sistemas sem complicações e se precisarmos restaurar rapidamente algum sistema que ficou indisponível por algum motivo. A configuração abaixo tem capacidade para atender algo em torno a '''50.000 assinantes ou mais'''. O DNS Recursivo é um serviço que pode ser utilizado até mesmo em um '''Raspberry Pi''' e atender operações pequenas, nesse caso com o intuito de economizar energia e espaço. Nosso foco aqui é montar uma rede de '''DNS Recursivo Anycast com HyperLocal'''. Como comentei acima o servidor deve ficar o mais próximo dos clientes para termos a '''menor latência possível''' e '''sempre menor que 5ms''' entre o cliente e o servidor.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!CPU&lt;br /&gt;
!Memória&lt;br /&gt;
!Disco&lt;br /&gt;
!Sistema&lt;br /&gt;
|-&lt;br /&gt;
|2.4Ghz 8 cores&lt;br /&gt;
|16G DDR4&lt;br /&gt;
|30G&lt;br /&gt;
|Debian 13 amd64 (Trixie)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Softwares utilizados ==&lt;br /&gt;
* Debian 13 amd64 (Trixie) instalação mínima.&lt;br /&gt;
&lt;br /&gt;
* [https://frrouting.org/ FRRouting].&lt;br /&gt;
* Unbound.&lt;br /&gt;
* Chrony (NTP/NTS).&lt;br /&gt;
* Shell script em bash.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades que teremos ==&lt;br /&gt;
* Sistema em Anycast.&lt;br /&gt;
* Hyperlocal.&lt;br /&gt;
* Controle de acesso por &amp;lt;abbr&amp;gt;ACL&amp;lt;/abbr&amp;gt;.&lt;br /&gt;
* RPZ (Response Policy Zone).&lt;br /&gt;
* Bloqueio de consultas do tipo ANY.&lt;br /&gt;
* QNAME minimization habilitado. (habilitado por default no Unbound)&lt;br /&gt;
* Recursividade em IPv4 e IPv6.&lt;br /&gt;
* DNSSEC habilitado.&lt;br /&gt;
* &amp;lt;abbr&amp;gt;DoH (DNS&amp;lt;/abbr&amp;gt; over HTTPS) habilitado.&lt;br /&gt;
&lt;br /&gt;
== Monitoramento ==&lt;br /&gt;
O monitoramento é algo bem específico e não é o foco deste documento mas é extremamente importante que você monitore seus servidores de DNS por alguma ferramenta como o Zabbix. Aqui mostrarei apenas como enviar as informações para o Zabbix. Algumas coisas que você deveria monitorar nos servidores de DNS Recursivo:&lt;br /&gt;
* Serviço do unbound parou.&lt;br /&gt;
* Perda de pacotes.&lt;br /&gt;
* Latência alta de pacotes.&lt;br /&gt;
* Lentidão na resolução de queries.&lt;br /&gt;
* CPU alta.&lt;br /&gt;
* Load alto.&lt;br /&gt;
* Memória com uso alto.&lt;br /&gt;
* Disco com pouco espaço.&lt;br /&gt;
* Queda brusca nas queries.&lt;br /&gt;
* A recursividade parou de funcionar.&lt;br /&gt;
* A recursividade voltou a funcionar.&lt;br /&gt;
Este abaixo é um exemplo de monitoramento de um sistema de DNS Recursivo que atende 50.000 assinantes:&lt;br /&gt;
[[Arquivo:Grafana dns.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Configurando a Rede ==&lt;br /&gt;
Nossa documentação será baseada no diagrama apresentado acima e por isso configuraremos apenas um dos três servidores, porque os outros serão configurados da mesma forma, só que com dados diferentes. Para tanto assumirei que já temos um sistema Debian instalado com o mínimo de pacotes e somente com sshd, para que possamos acessar remotamente mais tarde. '''Não instale um ambiente gráfico no servidor''', você não deve querer fazer isso por diversos motivos e os principais: primeiro porque não é um Desktop e segundo porque o ambiente gráfico devoraria toda a memória com recursos que não seriam úteis aqui.&lt;br /&gt;
&lt;br /&gt;
Em '''/etc/network/interfaces''' deixaremos assim:&lt;br /&gt;
 # This file describes the network interfaces available on your system&lt;br /&gt;
 # and how to activate them. For more information, see interfaces(5).&lt;br /&gt;
  &lt;br /&gt;
 source /etc/network/interfaces.d/*&lt;br /&gt;
  &lt;br /&gt;
 # The loopback network interface&lt;br /&gt;
 auto lo&lt;br /&gt;
 iface lo inet loopback&lt;br /&gt;
  &lt;br /&gt;
 auto lo:0&lt;br /&gt;
 iface lo:0 inet static&lt;br /&gt;
       address 10.10.10.10/32&lt;br /&gt;
  &lt;br /&gt;
 auto lo:1&lt;br /&gt;
 iface lo:1 inet static&lt;br /&gt;
       address 10.10.9.9/32&lt;br /&gt;
 &lt;br /&gt;
 auto lo:2&lt;br /&gt;
 iface lo:2 inet6 static&lt;br /&gt;
       address fd00::10:10:10:10/128&lt;br /&gt;
 &lt;br /&gt;
 auto lo:3&lt;br /&gt;
 iface lo:3 inet6 static&lt;br /&gt;
       address fd00::10:10:9:9/128&lt;br /&gt;
  &lt;br /&gt;
 # The primary network interface&lt;br /&gt;
 auto ens18&lt;br /&gt;
 iface ens18 inet static&lt;br /&gt;
         address 198.18.1.10/27&lt;br /&gt;
         gateway 198.18.1.1&lt;br /&gt;
  &lt;br /&gt;
 iface ens18 inet6 static&lt;br /&gt;
         address 2001:db8::faca:198:18:1:10/64&lt;br /&gt;
         gateway 2001:db8::faca:198:18:1:1&lt;br /&gt;
  &lt;br /&gt;
 # The secondary network interface&lt;br /&gt;
 auto ens18:0&lt;br /&gt;
 iface ens18:0 inet static&lt;br /&gt;
         address 172.16.0.6/30&lt;br /&gt;
Nesse cenário temos as duas '''loopbacks''' com os IPs '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10''' e '''fd00::10:10:9:9''' que serão anunciados via OSPF para a rede e serem entregues aos clientes via BNG. Os IPs '''198.18.1.10''' e '''2001:db8::faca:198:18:1:10''' serão usados para fazerem a recursividade na Internet tanto em IPv4 quanto em IPv6. Esses IPs não devem ser divulgados para clientes; os IPs públicos são dedicados apenas para essa finalidade.&lt;br /&gt;
&lt;br /&gt;
== Configuração dos repositórios Debian ==&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://security.debian.org/debian-security/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-security&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-updates&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian-backports.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-backports&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
&lt;br /&gt;
 # rm /etc/apt/sources.list&lt;br /&gt;
Após a configuração vamos instalar alguns pacotes necessários e outros úteis:&lt;br /&gt;
 # apt update &amp;amp;&amp;amp; apt full-upgrade&lt;br /&gt;
 # apt install net-tools nftables htop iotop sipcalc tcpdump curl gnupg rsync wget host dnsutils mtr-tiny bmon sudo tmux whois ethtool dnstop&lt;br /&gt;
&lt;br /&gt;
== Fazendo algum tuning no sistema ==&lt;br /&gt;
Em '''/etc/sysctl.d/100-tuning.conf''' adicionamos essas instruções:&lt;br /&gt;
 net.core.rmem_max = 2147483647&lt;br /&gt;
 net.core.wmem_max = 2147483647&lt;br /&gt;
 net.ipv4.tcp_rmem = 4096 87380 2147483647&lt;br /&gt;
 net.ipv4.tcp_wmem = 4096 65536 2147483647&lt;br /&gt;
 net.netfilter.nf_conntrack_buckets = 512000&lt;br /&gt;
 net.netfilter.nf_conntrack_max = 4096000&lt;br /&gt;
 vm.swappiness=10&lt;br /&gt;
Estamos fazendo algumas melhorias de memória, algumas relacionadas a '''conntrack''' porque se for usar um filtro de pacotes stateful, como o '''Netfilter/IPTables''' ou '''Netfilter/NFTables''', o valor default da tabela é pequeno e dependendo da situação, se estourar essa tabela, as consultas de DNS terão problemas também. O DNS Recursivo não deve ficar aberto para qualquer um na Internet, ele deve ser liberado apenas para seus clientes. Podemos fazer através das ACLs do Unbound e pelo filtro de pacotes. O último parâmetro diz respeito ao uso de swap, por padrão o Debian permite o uso de swap após 40% do uso da memória, nesse caso estamos dizendo para o sistema usar o swap com 90% de uso da memória.&lt;br /&gt;
&lt;br /&gt;
Precisamos adicionar o módulo '''nf_conntrack''' em '''/etc/modules''' para que seja carregado em tempo de boot, senão os parâmetros de '''conntrack''' que colocamos em '''/etc/sysctl.conf''' não serão carregados.&lt;br /&gt;
 # echo nf_conntrack &amp;gt;&amp;gt; /etc/modules&lt;br /&gt;
 # modprobe nf_conntrack&lt;br /&gt;
 # sysctl -p&lt;br /&gt;
&lt;br /&gt;
== Instalando o FRRouting ==&lt;br /&gt;
O FRRouting é o programa que usaremos para fazer os anúncios das nossas loopbacks via OSPF. Nesse documento usaremos a versão 10.x:&lt;br /&gt;
 # apt install frr frr-doc frr-pythontools&lt;br /&gt;
Aconselho depois de instalar os pacotes, marcá-los para não atualizar juntamente com os demais pacotes, isso é para evitar de ocorrer alguma atualização no FRRouting, que torne o serviço instável por algum motivo. Não que isso vá ocorrer, mas é melhor fazer essa atualização quando realmente for necessário.&lt;br /&gt;
 # apt-mark hold frr frr-doc frr-pythontools&lt;br /&gt;
Após esse comando acima, o sistema manterá a instalação original do pacote intacta. Para desbloquear basta executar o comando abaixo:&lt;br /&gt;
 # apt-mark unhold frr frr-doc frr-pythontools&lt;br /&gt;
&lt;br /&gt;
== Removendo o APPARMOR ==&lt;br /&gt;
O '''APPARMOR''' às vezes causa mais problemas que solução e se não for fazer uma completa configuração nele, é melhor desabilitá-lo. Para fazer isso efetivamente, o procedimento é esse abaixo:&lt;br /&gt;
 # mkdir -p /etc/default/grub.d&lt;br /&gt;
 # echo 'GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;$GRUB_CMDLINE_LINUX_DEFAULT apparmor=0&amp;quot;' | tee /etc/default/grub.d/apparmor.cfg&lt;br /&gt;
 # update-grub&lt;br /&gt;
 # reboot&lt;br /&gt;
&lt;br /&gt;
== Instalando o Unbound ==&lt;br /&gt;
Nesse momento ainda não iremos configurar o Unbound, apenas instalar o pacote e acertar o ambiente. Vamos instalar o unbound do backports porque este já possui suporte ao DoH que veremos mais à frente.&lt;br /&gt;
 # apt install unbound dns-root-data&lt;br /&gt;
 # mkdir -p /var/log/unbound&lt;br /&gt;
 # touch /var/log/unbound/unbound.log&lt;br /&gt;
 # chown -R unbound:unbound /var/log/unbound/&lt;br /&gt;
 # systemctl restart unbound&lt;br /&gt;
Configurando o logrotate:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/logrotate.d/unbound&lt;br /&gt;
 /var/log/unbound/unbound.log {&lt;br /&gt;
     rotate 5&lt;br /&gt;
     weekly&lt;br /&gt;
     postrotate&lt;br /&gt;
         unbound-control log_reopen&lt;br /&gt;
     endscript&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
Reiniciando o serviço:&lt;br /&gt;
 # systemctl restart logrotate.service&lt;br /&gt;
&lt;br /&gt;
== Desabilitando THP (Transparente Huge Pages) em arquitetura AMD64 ==&lt;br /&gt;
No Debian o '''THP''' vem habilitado como '''always''' e o '''unbound''' por trabalhar bastante com alterações do cache em memória, isso pode acabar causando um consumo crescente de uso de RAM sem necessidade. É uma boa prática desabilitá-lo com os passos abaixo:&lt;br /&gt;
&lt;br /&gt;
https://github.com/NLnetLabs/unbound/issues/724&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/systemd/system/disable-thp.service&lt;br /&gt;
 [Unit]&lt;br /&gt;
 Description=Ajusta Transparent Huge Pages (THP)&lt;br /&gt;
 After=network.target&lt;br /&gt;
 &lt;br /&gt;
 [Service]&lt;br /&gt;
 Type=oneshot&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled&amp;quot;&lt;br /&gt;
 RemainAfterExit=yes&lt;br /&gt;
 &lt;br /&gt;
 [Install]&lt;br /&gt;
 WantedBy=multi-user.target&lt;br /&gt;
 EOF&lt;br /&gt;
Acima configuramos o serviço '''disable-thp.service''' para desabilitar o '''THP''' e abaixo habilitamos no '''systemd''' e iniciamos:&lt;br /&gt;
 # systemctl daemon-reload&lt;br /&gt;
 # systemctl enable --now disable-thp&lt;br /&gt;
&lt;br /&gt;
== Preparando o monitoramento do seu DNS Recursivo ==&lt;br /&gt;
O monitoramento do seu DNS Recursivo é muito importante e para isso vamos usar um '''template para Zabbix''', que modifiquei juntamente com o seu shell script e que enviará os dados para o seu Zabbix server via '''zabbix-sender'''. O projeto original está aqui '''https://github.com/jeftedelima/Unbound-DNS&amp;lt;nowiki/&amp;gt;.''' O xml alterado está aqui '''https://github.com/gondimcodes/template_zabbix_dns_unbound'''. Embora seja antigo é perfeitamente importável no Zabbix 6.0, por exemplo.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;nowiki/&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Teremos um shell script que você precisará colocar no seu '''/etc/crontab'''. No exemplo abaixo assumi que o shell script está em '''/root/scripts'''. De 5 em 5 minutos os dados serão enviados para o seu Zabbix server.&lt;br /&gt;
 */5 * * * *     root    /root/scripts/unboundSend.sh '''IP_zabbix_server''' '''nome_do_host''' 1&amp;gt; /dev/null&lt;br /&gt;
Na linha acima, troque o '''IP_zabbix_server''' pelo '''IP do seu servidor Zabbix''' e o '''nome_do_host''' pelo '''hostname''' '''do seu DNS Recursivo'''. Você precisará instalar o pacote '''zabbix-sender''' no seu DNS Recursivo pois ele será usado para enviar os dados para o Zabbix server.&lt;br /&gt;
&lt;br /&gt;
Abaixo o '''unboundSend.sh''' também alterado com inclusão de mais dados:&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 #       @Jefte de Lima Ferreira&lt;br /&gt;
 #       jeftedelima at gmail dot com&lt;br /&gt;
 #       CRON Example&lt;br /&gt;
 #       Contributor: Marcelo Gondim - gondim at gmail dot com&lt;br /&gt;
 #       */5   **** root sh /home/dir/unboundSend.sh 192.168.10.1 Unbound 1&amp;gt; /dev/null&lt;br /&gt;
  &lt;br /&gt;
 if [ -z ${1} ] || [ -z ${2} ] ; then&lt;br /&gt;
         echo &amp;quot;You need to specify the IP address of zabbix server and hostname of your DNS Unbound on zabbix&amp;quot;&lt;br /&gt;
         echo &amp;quot;Usage example: ./unboundSend.sh 192.168.10.1 UnboundServer&amp;quot;&lt;br /&gt;
         exit 1&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 # ZABBIX_SERVER IP&lt;br /&gt;
 IP_ZABBIX=$1&lt;br /&gt;
 # NAME Unbound on Zabbix&lt;br /&gt;
 NAME_HOST=$2&lt;br /&gt;
 DIR_TEMP=/var/tmp/&lt;br /&gt;
 FILE=&amp;quot;${DIR_TEMP}dump_unbound_control_stats.txt&amp;quot;&lt;br /&gt;
 unbound-control stats &amp;gt; ${FILE}&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_NUM_QUERIES=$(cat ${FILE} | grep -w 'total.num.queries' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEHITS=$(cat ${FILE} | grep -w 'total.num.cachehits' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEMISS=$(cat ${FILE} | grep -w 'total.num.cachemiss' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_PREFETCH=$(cat ${FILE} | grep -w 'total.num.prefetch' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_RECURSIVEREPLIES=$(cat ${FILE} | grep -w 'total.num.recursivereplies' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_REQ_MAX=$(cat ${FILE} | grep -w 'total.requestlist.max' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_AVG=$(cat ${FILE} | grep -w 'total.requestlist.avg' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_OVERWRITTEN=$(cat ${FILE} | grep -w 'total.requestlist.overwritten' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_EXCEEDED=$(cat ${FILE} | grep -w 'total.requestlist.exceeded' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_ALL=$(cat ${FILE} | grep -w 'total.requestlist.current.all' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_USER=$(cat ${FILE} | grep -w 'total.requestlist.current.user' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_TCPUSAGE=$(cat ${FILE} | grep -w 'total.tcpusage' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_QUERY_TYPE_A=$(cat ${FILE} | grep -w 'num.query.type.A' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NS=$(cat ${FILE} | grep -w 'num.query.type.NS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_MX=$(cat ${FILE} | grep -w 'num.query.type.MX' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TXT=$(cat ${FILE} | grep -w 'num.query.type.TXT' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_PTR=$(cat ${FILE} | grep -w 'num.query.type.PTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_AAAA=$(cat ${FILE} | grep -w 'num.query.type.AAAA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SRV=$(cat ${FILE} | grep -w 'num.query.type.SRV' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SOA=$(cat ${FILE} | grep -w 'num.query.type.SOA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HTTPS=$(cat ${FILE} | grep -w 'num.query.type.HTTPS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TYPE0=$(cat ${FILE} | grep -w 'num.query.type.TYPE0' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_CNAME=$(cat ${FILE} | grep -w 'num.query.type.CNAME' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_WKS=$(cat ${FILE} | grep -w 'num.query.type.WKS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HINFO=$(cat ${FILE} | grep -w 'num.query.type.HINFO' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_X25=$(cat ${FILE} | grep -w 'num.query.type.X25' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NAPTR=$(cat ${FILE} | grep -w 'num.query.type.NAPTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DS=$(cat ${FILE} | grep -w 'num.query.type.DS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DNSKEY=$(cat ${FILE} | grep -w 'num.query.type.DNSKEY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TLSA=$(cat ${FILE} | grep -w 'num.query.type.TLSA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SVCB=$(cat ${FILE} | grep -w 'num.query.type.SVCB' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SPF=$(cat ${FILE} | grep -w 'num.query.type.SPF' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_ANY=$(cat ${FILE} | grep -w 'num.query.type.ANY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_OTHER=$(cat ${FILE} | grep -w 'num.query.type.other' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_ANSWER_RCODE_NOERROR=$(cat ${FILE} | grep -w 'num.answer.rcode.NOERROR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_NXDOMAIN=$(cat ${FILE} | grep -w 'num.answer.rcode.NXDOMAIN' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_SERVFAIL=$(cat ${FILE} | grep -w 'num.answer.rcode.SERVFAIL' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_REFUSED=$(cat ${FILE} | grep -w 'num.answer.rcode.REFUSED' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_nodata=$(cat ${FILE} | grep -w 'num.answer.rcode.nodata' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_secure=$(cat ${FILE} | grep -w 'num.answer.secure' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 #       Sending info to zabbix_server.&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.queries -o $(( ${TOTAL_NUM_QUERIES:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachehits -o $(( ${TOTAL_NUM_CACHEHITS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachemiss -o $(( ${TOTAL_NUM_CACHEMISS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.prefetch -o $(( ${TOTAL_NUM_PREFETCH:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.recursivereplies -o $(( ${TOTAL_NUM_RECURSIVEREPLIES:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.max -o $(( ${TOTAL_REQ_MAX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.avg -o $(( ${TOTAL_REQ_AVG:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.overwritten -o $(( ${TOTAL_REQ_OVERWRITTEN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.exceeded -o $(( ${TOTAL_REQ_EXCEEDED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.all -o $(( ${TOTAL_REQ_CURRENT_ALL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.user -o $(( ${TOTAL_REQ_CURRENT_USER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.tcpusage -o $(( ${TOTAL_TCPUSAGE:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.a -o $(( ${NUM_QUERY_TYPE_A:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ns -o $(( ${NUM_QUERY_TYPE_NS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.mx -o $(( ${NUM_QUERY_TYPE_MX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.txt -o $(( ${NUM_QUERY_TYPE_TXT:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ptr -o $(( ${NUM_QUERY_TYPE_PTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.aaaa -o $(( ${NUM_QUERY_TYPE_AAAA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.srv -o $(( ${NUM_QUERY_TYPE_SRV:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.soa -o $(( ${NUM_QUERY_TYPE_SOA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.https -o $(( ${NUM_QUERY_TYPE_HTTPS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.type0 -o $(( ${NUM_QUERY_TYPE_TYPE0:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.cname -o $(( ${NUM_QUERY_TYPE_CNAME:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.wks -o $(( ${NUM_QUERY_TYPE_WKS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.hinfo -o $(( ${NUM_QUERY_TYPE_HINFO:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.X25 -o $(( ${NUM_QUERY_TYPE_X25:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.naptr -o $(( ${NUM_QUERY_TYPE_NAPTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ds -o $(( ${NUM_QUERY_TYPE_DS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.dnskey -o $(( ${NUM_QUERY_TYPE_DNSKEY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.tlsa -o $(( ${NUM_QUERY_TYPE_TLSA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.svcb -o $(( ${NUM_QUERY_TYPE_SVCB:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.spf -o $(( ${NUM_QUERY_TYPE_SPF:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.any -o $(( ${NUM_QUERY_TYPE_ANY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.other -o $(( ${NUM_QUERY_TYPE_OTHER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NOERROR -o $(( ${NUM_ANSWER_RCODE_NOERROR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NXDOMAIN -o $(( ${NUM_ANSWER_RCODE_NXDOMAIN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.SERVFAIL -o $(( ${NUM_ANSWER_RCODE_SERVFAIL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.REFUSED -o $(( ${NUM_ANSWER_RCODE_REFUSED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.nodata -o $(( ${NUM_ANSWER_RCODE_nodata:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.secure -o $(( ${NUM_ANSWER_secure:-0} / 300 ))&lt;br /&gt;
No Zabbix será registrado dados como esses abaixo e posteriormente pode ser montado um Grafana com eles:&lt;br /&gt;
[[Arquivo:Zabbix dns01.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns02.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns03.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns04.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Mantendo a hora certa ==&lt;br /&gt;
Vamos instalar agora o Chrony para manter a data e hora certas no sistema:&lt;br /&gt;
 # apt install chrony&lt;br /&gt;
Após a instalação do Chrony edite o arquivo /etc/chrony/chrony.conf, comente e a linha abaixo e adicione seus servidores NTP. Caso não tenha servidores NTP, estou colocando os do NIC.br aqui.&lt;br /&gt;
 #pool 2.debian.pool.ntp.org iburst&lt;br /&gt;
 server a.st1.ntp.br iburst nts&lt;br /&gt;
 server b.st1.ntp.br iburst nts&lt;br /&gt;
 server c.st1.ntp.br iburst nts&lt;br /&gt;
 server d.st1.ntp.br iburst nts&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart chronyd.service&lt;br /&gt;
Cheque com o '''chronyc''' se os servidores estão OK:&lt;br /&gt;
 # chronyc sourcestats&lt;br /&gt;
 Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev&lt;br /&gt;
 ==============================================================================&lt;br /&gt;
 a.st1.ntp.br               10   5  155m     -0.027      0.030    -71us    51us&lt;br /&gt;
 b.st1.ntp.br               11   7  344m     +0.068      0.079    +23ms   382us&lt;br /&gt;
 c.st1.ntp.br                6   3  344m     +0.026      0.037   -124us    92us&lt;br /&gt;
 200.20.186.76               9   3  138m     -0.022      0.031   +172us    42us&lt;br /&gt;
&lt;br /&gt;
 # chronyc sources&lt;br /&gt;
 MS Name/IP address         Stratum Poll Reach LastRx Last sample&lt;br /&gt;
 ===============================================================================&lt;br /&gt;
 ^* a.st1.ntp.br                  1  10   377   588   +487us[ +397us] +/-   12ms&lt;br /&gt;
 ^- b.st1.ntp.br                  2  10   377   830    +23ms[  +23ms] +/-   49ms&lt;br /&gt;
 ^+ c.st1.ntp.br                  2  10    21  1038   -147us[ -242us] +/-   17ms&lt;br /&gt;
 ^+ 200.20.186.76                 1  10   377  1032   +381us[ +285us] +/-   15ms&lt;br /&gt;
&lt;br /&gt;
== Configurando o FRRouting ==&lt;br /&gt;
Nesse ponto iremos configurar o '''FRRouting''' para enviar os IPs das '''loopbacks''' e o '''/30''' para o nosso PE do diagrama. Em '''/etc/frr/daemons''' habilite o parâmetro conforme abaixo:&lt;br /&gt;
 ospfd=yes&lt;br /&gt;
 ospf6d=yes&lt;br /&gt;
Edite o arquivo '''/etc/frr/frr.conf''' e deixe com o conteúdo abaixo, para ficar conforme nosso diagrama do projeto. Apenas troque '''&amp;lt;SENHA&amp;gt;''' por uma senha para fechar o OSPF com mais segurança. Essa senha deve ser usada dos dois lados.&lt;br /&gt;
 frr version 10.3&lt;br /&gt;
 frr defaults traditional&lt;br /&gt;
 hostname dns-recursivo-01&lt;br /&gt;
 log syslog informational&lt;br /&gt;
 no ip forwarding&lt;br /&gt;
 no ipv6 forwarding&lt;br /&gt;
 service integrated-vtysh-config&lt;br /&gt;
 !&lt;br /&gt;
 interface ens18&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf message-digest-key 5 md5 &amp;lt;SENHA&amp;gt;&lt;br /&gt;
  ip ospf network point-to-point&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 network point-to-point&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 interface lo&lt;br /&gt;
  description LOOPBACKS&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf passive&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 passive&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf&lt;br /&gt;
  ospf router-id 172.16.0.6&lt;br /&gt;
  area 0.0.0.0 authentication message-digest&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf6&lt;br /&gt;
  ospf6 router-id 172.16.0.6&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart frr.service&lt;br /&gt;
Cheque se está tudo OK com o OSPF e verifique no PE se está recebendo os prefixos anunciados.&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL&lt;br /&gt;
 172.16.0.5     1 Full/-          10m49s            35.310s 172.16.0.5   ens18:172.16.0.6                  0     0     0&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri    DeadTime    State/IfState         Duration I/F[State]&lt;br /&gt;
 172.16.0.5       1    00:00:30     Full/PointToPoint 25d22:53:47 ens18[PointToPoint]&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor detail'&lt;br /&gt;
 &lt;br /&gt;
  Neighbor 172.16.0.5, interface address 172.16.0.5&lt;br /&gt;
     In the area 0.0.0.0 via interface ens18&lt;br /&gt;
     Neighbor priority is 1, State is Full/-, 5 state changes&lt;br /&gt;
     Most recent state change statistics:&lt;br /&gt;
       Progressive change 21w3d15h ago&lt;br /&gt;
     DR is 0.0.0.0, BDR is 0.0.0.0&lt;br /&gt;
     Options 18 *|-|-|EA|-|-|E|-&lt;br /&gt;
     Dead timer due in 34.685s&lt;br /&gt;
     Database Summary List 0&lt;br /&gt;
     Link State Request List 0&lt;br /&gt;
     Link State Retransmission List 0&lt;br /&gt;
     Thread Inactivity Timer on&lt;br /&gt;
     Thread Database Description Retransmision off&lt;br /&gt;
     Thread Link State Request Retransmission on&lt;br /&gt;
     Thread Link State Update Retransmission on&lt;br /&gt;
 &lt;br /&gt;
     Graceful restart Helper info:&lt;br /&gt;
       Graceful Restart HELPER Status : None&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor detail'&lt;br /&gt;
  Neighbor 172.16.0.5%ens18&lt;br /&gt;
     Area 0.0.0.0 via interface ens18 (ifindex 4)&lt;br /&gt;
     His IfIndex: 60 Link-local address: fe80::469b:c1ff:fed6:43ee&lt;br /&gt;
     State Full for a duration of 25d22:57:14&lt;br /&gt;
     His choice of DR/BDR 0.0.0.0/0.0.0.0, Priority 1&lt;br /&gt;
     DbDesc status: Master SeqNum: 0xb94b0000&lt;br /&gt;
     Summary-List: 0 LSAs&lt;br /&gt;
     Request-List: 0 LSAs&lt;br /&gt;
     Retrans-List: 0 LSAs&lt;br /&gt;
     0 Pending LSAs for DbDesc in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSReq in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSAck in Time 00:00:00 [thread off]&lt;br /&gt;
     Authentication header not present&lt;br /&gt;
&lt;br /&gt;
== Configurando o Unbound ==&lt;br /&gt;
Abaixo a configuração que usaremos nos servidores atentando para o detalhe do '''num-threads''', esse deve ter o valor igual ao número de CPUs do servidor.&lt;br /&gt;
&lt;br /&gt;
Também os IPs utilizados em '''outgoing-interface''' que serão diferentes em cada servidor, esses serão os IPs usados para '''recursividade'''. Consulte o manual do Unbound para obter mais informações sobre cada parâmetro listado na configuração.&lt;br /&gt;
&lt;br /&gt;
O tuning no Unbound pode ser alterado conforme abaixo:&lt;br /&gt;
 num-threads = nº CPUs&lt;br /&gt;
 so-reuseport = yes&lt;br /&gt;
 *-slabs = potência de 2 próximo ao num-threads&lt;br /&gt;
 msg-cache-size = 1g (quantidade de memória pra usar de cache)&lt;br /&gt;
 rrset-cache-size = 2 * msg-cache-size&lt;br /&gt;
 outgoing-range = 8192&lt;br /&gt;
 num-queries-per-thread = 4096&lt;br /&gt;
 so-rcvbuf e so-sndbuf = 4m ou 8m para servidores com muita requisição&lt;br /&gt;
Agora vamos criar nosso arquivo de configuração base em '''/etc/unbound/unbound.conf.d/local.conf''':&lt;br /&gt;
 server:&lt;br /&gt;
         verbosity: 1&lt;br /&gt;
         statistics-interval: 0&lt;br /&gt;
         statistics-cumulative: no&lt;br /&gt;
         extended-statistics: yes&lt;br /&gt;
         num-threads: 8&lt;br /&gt;
         serve-expired: yes&lt;br /&gt;
         interface: 127.0.0.1&lt;br /&gt;
         interface: 10.10.10.10&lt;br /&gt;
         interface: 10.10.9.9&lt;br /&gt;
         interface: 172.16.0.6&lt;br /&gt;
         interface: fd00::10:10:10:10&lt;br /&gt;
         interface: fd00::10:10:9:9&lt;br /&gt;
         interface: ::1&lt;br /&gt;
         interface-automatic: no&lt;br /&gt;
         outgoing-interface: 198.18.1.10&lt;br /&gt;
         outgoing-interface: 2001:db8::faca:198:18:1:10&lt;br /&gt;
         outgoing-range: 8192&lt;br /&gt;
         outgoing-num-tcp: 1024&lt;br /&gt;
         incoming-num-tcp: 2048&lt;br /&gt;
         so-rcvbuf: 4m&lt;br /&gt;
         so-sndbuf: 4m&lt;br /&gt;
         so-reuseport: yes&lt;br /&gt;
         edns-buffer-size: 1232&lt;br /&gt;
         msg-cache-size: 512m&lt;br /&gt;
         msg-cache-slabs: 4&lt;br /&gt;
         num-queries-per-thread: 4096&lt;br /&gt;
         rrset-cache-size: 1g&lt;br /&gt;
         rrset-cache-slabs: 4&lt;br /&gt;
         infra-cache-slabs: 4&lt;br /&gt;
         do-ip4: yes&lt;br /&gt;
         do-ip6: yes&lt;br /&gt;
         do-udp: yes&lt;br /&gt;
         do-tcp: yes&lt;br /&gt;
         chroot: &amp;quot;&amp;quot;&lt;br /&gt;
         username: &amp;quot;unbound&amp;quot;&lt;br /&gt;
         directory: &amp;quot;/etc/unbound&amp;quot;&lt;br /&gt;
         logfile: &amp;quot;/var/log/unbound/unbound.log&amp;quot;&lt;br /&gt;
         use-syslog: no&lt;br /&gt;
         log-time-ascii: yes&lt;br /&gt;
         log-queries: no&lt;br /&gt;
         pidfile: &amp;quot;/var/run/unbound.pid&amp;quot;&lt;br /&gt;
         root-hints: &amp;quot;/usr/share/dns/root.hints&amp;quot;&lt;br /&gt;
         hide-identity: yes&lt;br /&gt;
         hide-version: yes&lt;br /&gt;
         unwanted-reply-threshold: 10000000&lt;br /&gt;
         prefetch: yes&lt;br /&gt;
         prefetch-key: yes&lt;br /&gt;
         rrset-roundrobin: yes&lt;br /&gt;
         minimal-responses: yes&lt;br /&gt;
         module-config: &amp;quot;respip validator iterator&amp;quot;&lt;br /&gt;
         val-clean-additional: yes&lt;br /&gt;
         val-log-level: 1&lt;br /&gt;
         key-cache-slabs: 4&lt;br /&gt;
         deny-any: yes&lt;br /&gt;
         cache-min-ttl: 60&lt;br /&gt;
         key-cache-size: 128m&lt;br /&gt;
         neg-cache-size: 64m&lt;br /&gt;
         cache-max-ttl: 86400&lt;br /&gt;
         infra-cache-numhosts: 100000&lt;br /&gt;
         access-control: 198.18.0.0/22 allow&lt;br /&gt;
         access-control: 2001:db8::/32 allow&lt;br /&gt;
  &lt;br /&gt;
 rpz:&lt;br /&gt;
   name: rpz.block.host.local.zone&lt;br /&gt;
   zonefile: /etc/unbound/rpz.block.hosts.zone&lt;br /&gt;
   rpz-action-override: nxdomain&lt;br /&gt;
  &lt;br /&gt;
 python:&lt;br /&gt;
  &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;.&amp;quot;&lt;br /&gt;
     master: &amp;quot;b.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;c.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;d.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;f.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;g.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;k.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/root.zone&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;arpa.&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/arpa.zone&amp;quot;&lt;br /&gt;
No parâmetro '''interface''' colocamos os IPs que serão usados para consulta dos clientes como o '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9'''. Ali repare que coloquei também o IP privado '''172.16.0.6''', isso porque cada servidor terá o seu IP privado e este deve ser usado pelo seu sistema de monitoramento para checar cada servidor. No '''outgoing-interface''' teremos os IPs, tanto '''IPv4''' quanto '''IPv6''', para que seja feita a recursividade na Internet utilizando eles. Não tem '''IPv6''' ainda na sua rede? Dê uma olhada nesse artigo. Outro parâmetro importante é o '''access-control''' e é através dele que liberamos os prefixos IP para consultarem no nosso DNS Recursivo. No exemplo estou liberando todo o prefixo '''198.18.0.0/22''' e o prefixo '''2001:db8::/32'''. Além da ACL no Unbound, recomendo que crie um filtro de pacotes com iptables ou nftables protegendo seu sistema e liberando as portas '''53/UDP''', '''53/TCP,'''  '''443/TCP e 853/TCP''' apenas para seus clientes. Falarei sobre a '''443/TCP e 853/TCP''' mais para frente nessa mesma documentação.&lt;br /&gt;
&lt;br /&gt;
Agora criaremos o arquivo '''RPZ''' ('''Response Policy Zones'''). Esse arquivo contém os sites que serão bloqueados via '''&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; Recursivo'''. São aqueles sites que às vezes você recebe um Ofício da Justiça solicitando o bloqueio deles. Não entrarei no mérito da efetividade desses bloqueios, porque muitos de vocês sabem que tecnicamente, existem formas de se fazer um bypass através desses bloqueios. Contudo vamos deixar nosso ambiente preparado para esses bloqueios e por isso crie o arquivo '''/etc/unbound/rpz.block.hosts.zone''' com esse conteúdo de exemplo:&lt;br /&gt;
 $TTL 2h&lt;br /&gt;
 @ IN SOA localhost. root.localhost. (2 6h 1h 1w 2h)&lt;br /&gt;
   IN NS  localhost.&lt;br /&gt;
 ; RPZ manual block hosts&lt;br /&gt;
 *.josedascoves.com CNAME .&lt;br /&gt;
 josedascoves.com CNAME .&lt;br /&gt;
No exemplo acima estamos bloqueando qualquer consulta de DNS para '''josedascoves.com''' ou qualquer coisa '''.josedascoves.com'''.&lt;br /&gt;
&lt;br /&gt;
Para testar podemos fazer assim do próprio servidor:&lt;br /&gt;
 # host josedascoves.com ::1&lt;br /&gt;
 Using domain server:&lt;br /&gt;
 Name: ::1&lt;br /&gt;
 Address: ::1#53&lt;br /&gt;
 Aliases:&lt;br /&gt;
 &lt;br /&gt;
 Host josedascoves.com not found: 3(NXDOMAIN)&lt;br /&gt;
Se a resposta for '''NXDOMAIN''' então está funcionando o bloqueio. Para incluir novos bloqueios basta adicionar os domínios, um abaixo do outro, conforme o exemplo que coloquei no arquivo RPZ.&lt;br /&gt;
&lt;br /&gt;
== Acertando o resolv.conf ==&lt;br /&gt;
Vamos modificar nosso /etc/resolv.conf para utilizar DNS externo. Sim você deve estar se perguntando em qual situação isso seria utilizado. Primeiro entenda que o Unbound não irá utilizar o DNS externo para fazer as consultas na Internet e sim, qualquer teste que você faça do servidor precisará apontar para o Unbound usando os IPs '''127.0.0.1''' ou '''::1'''. Faremos isso pela seguinte situação: imagine que o daemon unbound morreu mas você ainda continua com conectividade na Internet. Você conseguiria acessar qualquer local na Internet através do IP mas não através do hostname porque não conseguiria resolver nomes, seu unbound estaria fora do ar. Imagine ainda que você gostaria que seu servidor te avisasse do problema via Telegram ou e-mail. Por isso estamos utilizando um DNS externo no '''/etc/resolv.conf''', apenas para essas situações. Se você não quiser utilizar desse recurso, pode usar o '''127.0.0.1''' e '''::1''' no lugar.&lt;br /&gt;
 nameserver 8.8.8.8&lt;br /&gt;
 nameserver 8.8.4.4&lt;br /&gt;
 nameserver 2001:4860:4860::8888&lt;br /&gt;
&lt;br /&gt;
== Script de teste de recursividade ==&lt;br /&gt;
Estamos montando uma '''Rede de DNS Recursivo Anycast''', então é muito importante que você monitore essa rede para saber se algum node morreu e iniciar o troubleshooting, resolver o problema e levantar o sistema novamente. Tudo isso é importante mas o cliente não deve ficar esperando até você resolver o problema, seu sistema precisa ser inteligente o suficiente para se remover da Rede quando tiver um problema e se inserir novamente, quando o problema estiver sido solucionado. Se você montar uma Rede de DNS e um dos nodes apresentar algum problema, todos os clientes atendidos por aquele node migrarão automaticamente e transparentemente para outro '''DNS Recursivo Anycast''' mais próximo. Isso se chama '''disponibilidade'''.&lt;br /&gt;
&lt;br /&gt;
O script '''/root/scripts/checa_dns.sh''' abaixo tem a função de fazer os testes de recursividade e checar se o daemon do unbound continua rodando. Se algo acontecer, ele para o anúncio do '''10.10.10.10''' e '''10.10.9.9''' e retorna eles quando tudo estiver resolvido.&lt;br /&gt;
 # mkdir /root/scripts&lt;br /&gt;
&lt;br /&gt;
 #!/usr/bin/env bash&lt;br /&gt;
 #Script para teste de DNS v2.1&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 #Informe um domínio por linha:&lt;br /&gt;
 dominios_testar=(&lt;br /&gt;
 www.google.com&lt;br /&gt;
 www.terra.com.br&lt;br /&gt;
 www.uol.com.br&lt;br /&gt;
 www.globo.com&lt;br /&gt;
 www.facebook.com&lt;br /&gt;
 www.youtube.com&lt;br /&gt;
 www.twitch.com&lt;br /&gt;
 www.discord.com&lt;br /&gt;
 www.debian.org&lt;br /&gt;
 www.redhat.com&lt;br /&gt;
 )&lt;br /&gt;
 corte_taxa_falha=100 #Porcentagem de falha para executar uma ação&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 remove_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; != &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no description' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME morreu!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 adiciona_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; == &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'description LOOPBACKS' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME retornou do inferno!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
 if [ $? -ne 0 ]; then&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME morreu DNS mas tentando levantar!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    systemctl restart unbound&lt;br /&gt;
    systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
    if [ $? -ne 0 ]; then&lt;br /&gt;
       remove_ospf&lt;br /&gt;
       exit&lt;br /&gt;
    fi&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME servico DNS voltou mas tinha morrido!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 qt_falhas=0&lt;br /&gt;
 qt_total=&amp;quot;${#dominios_testar[@]}&amp;quot;&lt;br /&gt;
 echo &amp;quot;total_dominios: $qt_total&amp;quot;&lt;br /&gt;
 for site in &amp;quot;${dominios_testar[@]}&amp;quot;&lt;br /&gt;
 do&lt;br /&gt;
   unbound-control flush $site &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   resolver=&amp;quot;127.0.0.1&amp;quot;&lt;br /&gt;
   echo -e &amp;quot; - dominio $site - $resolver - \c&amp;quot;&lt;br /&gt;
   host $site $resolver &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   if [ $? -ne 0 ]; then&lt;br /&gt;
      ((qt_falhas++))&lt;br /&gt;
      echo -e &amp;quot;[Falhou]&amp;quot;&lt;br /&gt;
   else&lt;br /&gt;
      echo -e &amp;quot;[OK]&amp;quot;&lt;br /&gt;
   fi&lt;br /&gt;
 done&lt;br /&gt;
  &lt;br /&gt;
 taxa_falha=$((qt_falhas*100/qt_total))&lt;br /&gt;
 echo &amp;quot;Falhas $qt_falhas/$qt_total ($taxa_falha%)&amp;quot;&lt;br /&gt;
  &lt;br /&gt;
 if [ &amp;quot;$taxa_falha&amp;quot; -ge &amp;quot;$corte_taxa_falha&amp;quot; ]; then&lt;br /&gt;
    remove_ospf&lt;br /&gt;
    exit&lt;br /&gt;
 fi&lt;br /&gt;
 adiciona_ospf&lt;br /&gt;
Se rodarmos o script manualmente veremos isto:&lt;br /&gt;
 # /root/scripts/checa_dns.sh&lt;br /&gt;
 total_dominios: 10&lt;br /&gt;
  - dominio www.google.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.terra.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.uol.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.globo.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.facebook.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.youtube.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.twitch.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.discord.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.debian.org - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.redhat.com - 127.0.0.1 - [OK]&lt;br /&gt;
 Falhas 0/10 (0%)&lt;br /&gt;
Se acontecer 100% de falhas o script irá remover os anúncios do OSPF. Se o daemon do unbound morrer, ele tentará reiniciá-lo. Se tudo normalizar o script irá retornar os anúncios para o OSPF. Deixei comentado no script as partes que enviariam uma notificação para o Telegram. Existem diversas documentações sobre isso na Internet, eu mesmo tenho uma. Assim que eu publicar aqui, atualizo essa documentação e sinta-se à vontade de modificar como desejar.&lt;br /&gt;
 # chmod 700 /root/scripts/checa_dns.sh&lt;br /&gt;
Adicione a linha abaixo em seu '''/etc/crontab''':&lt;br /&gt;
 */1 *   * * *   root    /root/scripts/checa_dns.sh&lt;br /&gt;
&lt;br /&gt;
== Habilitando o DoH (&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; over HTTPS) - opcional ==&lt;br /&gt;
Para habilitar o '''DoH''' no Unbound é bem simples. O recurso do '''DoH''' vem para trazer mais segurança e privacidade para o usuário. É um recurso muito pouco utilizado ainda mas que seu cliente pode vir a pedir algum dia.&lt;br /&gt;
&lt;br /&gt;
Você precisará gerar certificados SSL legítimos e para isso você poderá usar o '''Let's Encrypt''' só que de uma forma não tão convencional.&lt;br /&gt;
&lt;br /&gt;
Na sequência vamos instalar o Let's Encrypt para gerarmos nosso certificado SSL:&lt;br /&gt;
 # apt install letsencrypt&lt;br /&gt;
Escolha um '''hostname''' para ser usado no nosso '''DoH''' e aponte ele no seu DNS Autoritativo para seus IPs 10.10.10.10 e 10.10.9.9. Aqui vamos usar o seguinte como exemplo: '''doh.brasilpeeringforum.org'''. Para gerarmos nosso certificado iremos usar o tipo '''DNS-01''', ele não necessita que tenhamos um servidor web rodando no servidor e nem tão pouco levanta um serviço na porta 80 para checar o hostname. Ele utiliza o DNS como validador e vai te solicitar que crie um registro '''CNAME''' no seu '''DNS Autoritativo''' para provar que você tem o controle sobre aquele hostname. Antes disso vamos instalar um programa em Python para podermos automatizar nossa renovação de certificado no futuro. Esse programa se encontra '''[https://github.com/joohoi/acme-dns-certbot-joohoi/raw/master/acme-dns-auth.py aqui]''' mas vou deixá-lo abaixo já modificado o interpretador.&lt;br /&gt;
&lt;br /&gt;
Crie o arquivo '''/etc/letsencrypt/acme-dns-auth.py''' com o conteúdo abaixo:&lt;br /&gt;
 #!/usr/bin/env python3&lt;br /&gt;
 import json&lt;br /&gt;
 import os&lt;br /&gt;
 import requests&lt;br /&gt;
 import sys&lt;br /&gt;
 &lt;br /&gt;
 ### EDIT THESE: Configuration values ###&lt;br /&gt;
 &lt;br /&gt;
 # URL to acme-dns instance&lt;br /&gt;
 ACMEDNS_URL = &amp;quot;&amp;lt;nowiki&amp;gt;https://auth.acme-dns.io&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
 # Path for acme-dns credential storage&lt;br /&gt;
 STORAGE_PATH = &amp;quot;/etc/letsencrypt/acmedns.json&amp;quot;&lt;br /&gt;
 # Whitelist for address ranges to allow the updates from&lt;br /&gt;
 # Example: ALLOW_FROM = [&amp;quot;192.168.10.0/24&amp;quot;, &amp;quot;::1/128&amp;quot;]&lt;br /&gt;
 ALLOW_FROM = []&lt;br /&gt;
 # Force re-registration. Overwrites the already existing acme-dns accounts.&lt;br /&gt;
 FORCE_REGISTER = False&lt;br /&gt;
 &lt;br /&gt;
 ###   DO NOT EDIT BELOW THIS POINT   ###&lt;br /&gt;
 ###         HERE BE DRAGONS          ###&lt;br /&gt;
 &lt;br /&gt;
 DOMAIN = os.environ[&amp;quot;CERTBOT_DOMAIN&amp;quot;]&lt;br /&gt;
 if DOMAIN.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
     DOMAIN = DOMAIN[2:]&lt;br /&gt;
 VALIDATION_DOMAIN = &amp;quot;_acme-challenge.&amp;quot;+DOMAIN&lt;br /&gt;
 VALIDATION_TOKEN = os.environ[&amp;quot;CERTBOT_VALIDATION&amp;quot;]&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 class AcmeDnsClient(object):&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
     Handles the communication with ACME-DNS API&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
     def __init__(self, acmedns_url):&lt;br /&gt;
         self.acmedns_url = acmedns_url&lt;br /&gt;
 &lt;br /&gt;
     def register_account(self, allowfrom):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Registers a new ACME-DNS account&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
         if allowfrom:&lt;br /&gt;
             # Include whitelisted networks to the registration call&lt;br /&gt;
             reg_data = {&amp;quot;allowfrom&amp;quot;: allowfrom}&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;,&lt;br /&gt;
                                 data=json.dumps(reg_data))&lt;br /&gt;
         else:&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;)&lt;br /&gt;
         if res.status_code == 201:&lt;br /&gt;
             # The request was successful&lt;br /&gt;
             return res.json()&lt;br /&gt;
         else:&lt;br /&gt;
             # Encountered an error&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to register a new acme-dns &amp;quot;&lt;br /&gt;
                    &amp;quot;account. HTTP status {}, Response body: {}&amp;quot;)&lt;br /&gt;
             print(msg.format(res.status_code, res.text))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def update_txt_record(self, account, txt):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Updates the TXT challenge record to ACME-DNS subdomain.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         update = {&amp;quot;subdomain&amp;quot;: account['subdomain'], &amp;quot;txt&amp;quot;: txt}&lt;br /&gt;
         headers = {&amp;quot;X-Api-User&amp;quot;: account['username'],&lt;br /&gt;
                    &amp;quot;X-Api-Key&amp;quot;: account['password'],&lt;br /&gt;
                    &amp;quot;Content-Type&amp;quot;: &amp;quot;application/json&amp;quot;}&lt;br /&gt;
         res = requests.post(self.acmedns_url+&amp;quot;/update&amp;quot;,&lt;br /&gt;
                             headers=headers,&lt;br /&gt;
                             data=json.dumps(update))&lt;br /&gt;
         if res.status_code == 200:&lt;br /&gt;
             # Successful update&lt;br /&gt;
             return&lt;br /&gt;
         else:&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to update TXT record in &amp;quot;&lt;br /&gt;
                    &amp;quot;acme-dns. \n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request headers:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request body:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response HTTP status: {}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response body: {}&amp;quot;)&lt;br /&gt;
             s_headers = json.dumps(headers, indent=2, sort_keys=True)&lt;br /&gt;
             s_update = json.dumps(update, indent=2, sort_keys=True)&lt;br /&gt;
             s_body = json.dumps(res.json(), indent=2, sort_keys=True)&lt;br /&gt;
             print(msg.format(s_headers, s_update, res.status_code, s_body))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
 class Storage(object):&lt;br /&gt;
     def __init__(self, storagepath):&lt;br /&gt;
         self.storagepath = storagepath&lt;br /&gt;
         self._data = self.load()&lt;br /&gt;
 &lt;br /&gt;
     def load(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Reads the storage content from the disk to a dict structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         data = dict()&lt;br /&gt;
         filedata = &amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             with open(self.storagepath, 'r') as fh:&lt;br /&gt;
                 filedata = fh.read()&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             if os.path.isfile(self.storagepath):&lt;br /&gt;
                 # Only error out if file exists, but cannot be read&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage file exists but cannot be read&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         try:&lt;br /&gt;
             data = json.loads(filedata)&lt;br /&gt;
         except ValueError:&lt;br /&gt;
             if len(filedata) &amp;gt; 0:&lt;br /&gt;
                 # Storage file is corrupted&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage JSON is corrupted&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         return data&lt;br /&gt;
 &lt;br /&gt;
     def save(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Saves the storage content to disk&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         serialized = json.dumps(self._data)&lt;br /&gt;
         try:&lt;br /&gt;
             with os.fdopen(os.open(self.storagepath,&lt;br /&gt;
                                    os.O_WRONLY | os.O_CREAT, 0o600), 'w') as fh:&lt;br /&gt;
                 fh.truncate()&lt;br /&gt;
                 fh.write(serialized)&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             print(&amp;quot;ERROR: Could not write storage file.&amp;quot;)&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def put(self, key, value):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Puts the configuration value to storage and sanitize it&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         # If wildcard domain, remove the wildcard part as this will use the&lt;br /&gt;
         # same validation record name as the base domain&lt;br /&gt;
         if key.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
             key = key[2:]&lt;br /&gt;
         self._data[key] = value&lt;br /&gt;
 &lt;br /&gt;
     def fetch(self, key):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Gets configuration value from storage&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             return self._data[key]&lt;br /&gt;
         except KeyError:&lt;br /&gt;
             return None&lt;br /&gt;
 &lt;br /&gt;
 if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
     # Init&lt;br /&gt;
     client = AcmeDnsClient(ACMEDNS_URL)&lt;br /&gt;
     storage = Storage(STORAGE_PATH)&lt;br /&gt;
 &lt;br /&gt;
     # Check if an account already exists in storage&lt;br /&gt;
     account = storage.fetch(DOMAIN)&lt;br /&gt;
     if FORCE_REGISTER or not account:&lt;br /&gt;
         # Create and save the new account&lt;br /&gt;
         account = client.register_account(ALLOW_FROM)&lt;br /&gt;
         storage.put(DOMAIN, account)&lt;br /&gt;
         storage.save()&lt;br /&gt;
 &lt;br /&gt;
         # Display the notification for the user to update the main zone&lt;br /&gt;
         msg = &amp;quot;Please add the following CNAME record to your main DNS zone:\n{}&amp;quot;&lt;br /&gt;
         cname = &amp;quot;{} CNAME {}.&amp;quot;.format(VALIDATION_DOMAIN, account[&amp;quot;fulldomain&amp;quot;])&lt;br /&gt;
         print(msg.format(cname))&lt;br /&gt;
 &lt;br /&gt;
     # Update the TXT record in acme-dns instance&lt;br /&gt;
     client.update_txt_record(account, VALIDATION_TOKEN)&lt;br /&gt;
&lt;br /&gt;
 # chmod +x /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
Usaremos a seguinte instrução para criar nosso certificado:&lt;br /&gt;
 # certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d doh.brasilpeeringforum.org&lt;br /&gt;
 Saving debug log to /var/log/letsencrypt/letsencrypt.log&lt;br /&gt;
 Plugins selected: Authenticator manual, Installer None&lt;br /&gt;
 Cert is due for renewal, auto-renewing...&lt;br /&gt;
 Renewing an existing certificate for doh.brasilpeeringforum.org&lt;br /&gt;
 Performing the following challenges:&lt;br /&gt;
 dns-01 challenge for doh.brasilpeeringforum.org&lt;br /&gt;
 Running manual-auth-hook command: /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
 Output from manual-auth-hook command acme-dns-auth.py:&lt;br /&gt;
 Please add the following CNAME record to your main DNS zone:&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
 &lt;br /&gt;
 Waiting for verification...&lt;br /&gt;
 &lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Challenges loaded. Press continue to submit to CA. Pass &amp;quot;-v&amp;quot; for more info about&lt;br /&gt;
 challenges.&lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Press Enter to Continue&lt;br /&gt;
Nesse momento você cria o registro '''CNAME''' no seu DNS Autoritativo conforme ele solicitou: '''_acme-challenge.doh.brasilpeeringforum.org IN CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.''' e somente depois de criado e checado no DNS, você pressiona o '''Enter''' para continuar. Você pode checar dessa forma:&lt;br /&gt;
 # host -t cname _acme-challenge.doh.brasilpeeringforum.org&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org is an alias for b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
Para que nosso certificado seja automaticamente renovado colocaremos no '''/etc/crontab''' a seguinte linha abaixo:&lt;br /&gt;
 00 00   1 * *   root    /usr/bin/certbot -q renew --deploy-hook &amp;quot;/usr/sbin/unbound-control reload_keep_cache&amp;quot;&lt;br /&gt;
Acima temos a instrução para renovação automática do certificado. Repare que você vai precisar também copiar esse certificado para seus outros servidores, escolha um servidor para manter o certificado sempre atualizado e crie um script que faça a mesma cópia remotamente para os outros servidores. O '''scp''' e o '''rsync''' são seus aliados nisso.&lt;br /&gt;
&lt;br /&gt;
=== Configurando o Unbound ===&lt;br /&gt;
Em nosso '''/etc/unbound/unbound.conf.d/local.conf''', adicionaremos no bloco &amp;quot;'''server:'''&amp;quot; o seguinte:&lt;br /&gt;
 interface: 10.10.10.10@443 &lt;br /&gt;
 interface: 10.10.9.9@443&lt;br /&gt;
 interface: fd00::10:10:10:10@443&lt;br /&gt;
 interface: fd00::10:10:9:9@443&lt;br /&gt;
 tls-service-key: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/privkey.pem&amp;quot; &lt;br /&gt;
 tls-service-pem: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/fullchain.pem&amp;quot;&lt;br /&gt;
Para usar o recurso do '''DoH''' você precisará habilitar o recurso no seu navegador e informar a URL. Vou colocar o exemplo do '''Google Chrome''': Digite '''chrome://settings/security?search=dns''' no seu Chrome e ative '''Usar DNS seguro''', selecione '''Personalizado''' e adicione nossa URL:&lt;br /&gt;
[[Arquivo:Doh bpf2.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Finalizando ==&lt;br /&gt;
Aqui finalizamos nosso projeto para uma Rede de DNS(s) Recursivos Anycast com Hyperlocal. Esse projeto é escalável, seguro, resiliente e você entregará muito mais qualidade de Internet para o seu cliente. Pare de entregar o '''8.8.8.8''' para os seus clientes, você está contribuindo para uma Internet mais lenta, sem a qualidade que o seu cliente merece. Investi meu tempo, que é muito pouco, para deixar esse documento para a comunidade, para você melhorar o seu ISP, para dar um UP! nele, então vamos começar 2023 com o pé direito. O que acha?&lt;br /&gt;
&lt;br /&gt;
Como prova de conceito, uma imagem abaixo onde temos uma Rede em produção de DNS(s) Recursivos Anycast e apontando exatamente o momento em que houve alguma situação que fez com que as queries de DNS, convergissem de um node para outro, de forma transparente e automática para o cliente. Podemos notar também que ao ser resolvido o problema, o tráfego retornou para o seu node correto:&lt;br /&gt;
[[Arquivo:Convergencia.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== KINDNS (Stands for Knowledge-Sharing and Instantiating Norms for DNS and Naming Security) ==&lt;br /&gt;
Achou que havia terminado? Agora que você tem a capacidade de montar uma '''Rede de DNS Recursivo''' com todas essas features acima, com todas as ferramentas que foram comentadas, o que acha de certificar o que fez?&lt;br /&gt;
&lt;br /&gt;
Assim como o [https://www.manrs.org/ MANRS] veio para certificar nosso sistema de roteamento na Internet, agora temos o [https://kindns.org/ KINDNS] para certificar que nossos sistemas de DNS estão bem feitos e dentro dos padrões de segurança. Existem '''7 ações''' que podem ser certificadas para nossos DNS Recursivos e estão aqui em https://kindns.org/shared-private-resolvers/. Com essa nossa documentação, se bem aplicada, você pode se candidatar ao KINDNS e ter seu ASN listado aqui https://kindns.org/participants/&lt;br /&gt;
&lt;br /&gt;
Obter e manter o '''MANRS''' e '''KINDNS''' demonstra seu compromisso com as Boas Práticas, contribui para termos uma '''Internet''' mais segura e te abre portas para novos negócios que possam exigir essas conformidades.&lt;br /&gt;
&lt;br /&gt;
Autor: [[Usuário:Gondim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Infraestrutura]]&lt;br /&gt;
__FORCARTDC__&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3986</id>
		<title>DNS Recursivo Anycast Hyperlocal</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3986"/>
		<updated>2025-11-24T14:57:45Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
==Introdução==&lt;br /&gt;
Você sabe como funciona a Internet? Essa é uma pergunta que meu amigo '''Thiago Ayub''' sempre faz aos seus candidatos à vagas de emprego e não importa o quanto tenham de experiência em '''Engenharia de Redes''', todos sempre travam nesse momento. Todos estão sempre prontos e preparados para resolver os problemas mais cabeludos em '''BGP''', '''OSPF''', '''MPLS''', etc mas travam com essa simples pergunta. Para contextualizar e visualizarmos melhor vamos nos atentar à imagem abaixo e uma explicação simplificada de como funciona:&lt;br /&gt;
[[Arquivo:Dns hierarquia.png|esquerda|commoldura]]&lt;br /&gt;
Tudo começa com um usuário sentado confortavelmente e querendo acessar um conteúdo disponível na Internet. Ele digita em seu navegador preferido a URL: '''&amp;lt;nowiki&amp;gt;https://wiki.brasilpeeringforum.org&amp;lt;/nowiki&amp;gt;''',&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;1)&amp;lt;/big&amp;gt;''' &amp;lt;big&amp;gt;O&amp;lt;/big&amp;gt; &amp;lt;big&amp;gt;navegador irá requisitar do '''DNS Recursivo''' utilizado pelo usuário, o '''endereço IP''' que responde pelo nome '''wiki.'''&amp;lt;/big&amp;gt;'''brasilpeeringforum.org'''&amp;lt;big&amp;gt;. Isso porque todos os acessos se dão na Internet através do '''endereço''' '''IP''' e não através do '''nome'''. Imaginem se tivéssemos que decorar os endereços IPs de todos os sites e serviços que quiséssemos acessar na Internet?&amp;lt;/big&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;big&amp;gt;'''2)''' Nosso DNS Recursivo checa se a informação consta em seu cache.&amp;lt;/big&amp;gt; Se a informação existir ela é devolvida ao navegador do usuário e aí este consegue acessar o site.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Do contrário o DNS Recursivo pergunta ao '''Root Server''' quem é o '''TLD (Top Level Domain)''' responsável para atender a requisição. &lt;br /&gt;
&lt;br /&gt;
'''4)''' O '''Root Server''' informa ao DNS Recursivo o endereço do '''TLD responsável'''. No Brasil o '''TLD''' responsável pelo '''.br''' seria o '''Registro.br'''.&lt;br /&gt;
&lt;br /&gt;
'''5)''' O DNS Recursivo pergunta ao '''TLD''' sobre '''wiki.brasilpeeringforum.org''' e este responde com os endereços IP dos '''DNS Autoritativos''' responsáveis pelo domínio '''brasilpeeringforum.org.'''&lt;br /&gt;
&lt;br /&gt;
'''6)''' O DNS Recursivo pergunta aos '''DNS Autoritativos''' pelo '''wiki.brasilpeeringforum.org''' e este responde com o '''endereço IP'''.&lt;br /&gt;
&lt;br /&gt;
'''7)''' Por último o DNS Recursivo devolve a informação para o navegador do usuário.&lt;br /&gt;
&lt;br /&gt;
Como que se dá a comunicação entre os '''DNS(s) Recursivos, Root Servers, TLDs''' e '''Autoritativos'''? Como que o navegador do usuário, após receber o IP do site, consegue chegar no servidor que tem o conteúdo? Isso só é possível devido ao protocolo chamado '''BGP (Border Gateway Protocol)''', todos os caminhos que conhecemos como rotas de destino, são anunciadas por milhares de participantes na '''Internet''' conhecidos como '''AS (Autonomous System)''', esses participantes se interligam para disponibilizar conteúdos e acessos pelo mundo aos milhares de usuários. É uma imensa rede colaborativa formada por Empresas, Universidades, Governos e todos que queiram se interconectar. Percebam que sem o '''BGP''', que serve de caminho para chegarmos nos conteúdos e sem o '''DNS (Domain Name System)''' para traduzir o nome para o endereço IP, a '''Internet''' não funcionaria e por isso precisamos cuidar muito bem desses dois serviços.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Mas não acaba por aí. O '''DNS Recursivo''' tem um papel muito importante para o Provedor de Internet e que envolve segurança, qualidade de acesso à Internet e a disponibilidade do serviço entregue ao cliente. Quando bem configurado acelera as consultas dos acessos graças ao seu cache interno, mas para que isso seja percebido pelo assinante, é necessário que esteja o mais próximo possível do seu cliente.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Um erro que destrói a qualidade do nosso serviço ==&lt;br /&gt;
Um erro muito comum que muitas operadoras cometem é utilizar DNS Recursivo externo, como o '''8.8.8.8''', '''1.1.1.1''' e outros, para seus clientes. Quanto mais próximo dos seus clientes, mais qualidade de serviço estará entregando a eles. Conteúdos serão entregues mais rapidamente pois serão resolvidos e armazenados em caches locais e não consultados remotamente na Internet. Para falar mais sobre isso, te convido leitor desse documento, que assista essa palestra do '''Thiago Ayub''' no '''GTER 51/GTS 37''' (2022) '''8.888 MOTIVOS PARA NÃO USAR DNS RECURSIVO EXTERNO EM SEU AS''': https://www.youtube.com/watch?v=Rsvpu5uF2Io&lt;br /&gt;
&lt;br /&gt;
== Objetivo ==&lt;br /&gt;
O objetivo desta documentação não é te ensinar tudo sobre '''DNS''', '''BGP''', '''OSPF''' e nem tão pouco sobre GNU/Linux e sim te mostrar um exemplo de servidor DNS Recursivo implementado pensando em segurança, qualidade e resiliência. Usaremos em todas as nossas documentações o [https://www.debian.org/ Debian GNU/Linux], por ser uma distribuição que considero uma obra de arte criada por uma enorme comunidade séria, com vasta experiência de anos, qualidade no empacotamento dos programas, estável e com uma equipe de segurança excelente e ativa. Caso você leitor, utilize alguma outra distribuição GNU/Linux, todo conteúdo apresentado aqui pode ser aplicado em outras distros, desde que respeitando as particularidades de cada uma.&lt;br /&gt;
&lt;br /&gt;
Aqui construiremos um sistema do tipo '''Anycast''', ou seja, terás o serviço rodando em diversas localidades da sua Rede utilizando o mesmo endereçamento IP e que atenderá seu cliente mais próximo. Em caso de falhas, seus clientes automaticamente e de forma transparente continuarão consultando o DNS mais próximo deles. Para que ele funcione dessa forma você precisará ter uma '''Rede OSPF''' implementada no seu Provedor Internet ou algum outro protocolo como por exemplo o '''ISIS,''' mas esse documento não irá abordar o '''ISIS'''. Também utilizaremos o '''Hyperlocal''' como recurso adicional para gerar algumas proteções de segurança e velocidade na resposta relacionada aos servidores de DNS Raiz da Internet.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
Para exemplificar nosso servidor de DNS Recursivo, usaremos como base das explicações um diagrama demonstrando o uso do DNS Recursivo em uma Rede fictícia. Adotaremos IPs privados e reservados para demonstrar todo o ambiente do Provedor de Internet.&lt;br /&gt;
[[Arquivo:Recursivo99.png|esquerda|miniaturadaimagem|695x695px]]&lt;br /&gt;
Nesse diagrama podemos observar alguns detalhes técnicos como por exemplo: existem '''3 servidores de DNS Recursivo''' posicionados em locais diferentes, que poderiam estar em bairros diferentes e até em cidades diferentes. Em cada servidor teremos '''2 loopbacks''' com os IPs:&lt;br /&gt;
&lt;br /&gt;
'''10.10.10.10/32 - fd00::10:10:10:10/128'''&lt;br /&gt;
&lt;br /&gt;
'''10.10.9.9/32 - fd00::10:10:9:9/128'''&lt;br /&gt;
&lt;br /&gt;
Esses IPs serão entregues pelos concentradores '''PPPoE''' ou '''IPoE''' ('''BNG''') para seus clientes como '''DNS primário''' e '''secundário'''. Podemos usar IPs privados como DNS primário e secundário em um ambiente real? Sim podemos, desde que não sejam IPs que possam ter problemas com as redes privadas dos clientes. Ex.: rede do cliente usando '''192.168.0.0/24'''. Se entregarmos o DNS sendo '''192.168.0.10''' e '''192.168.0.20''' teremos problemas e o cliente ficará sem Internet, porque '''192.168.0.10''' e '''192.168.0.20''' fazem parte da rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
Agora entregando '''10.10.10.10,''' '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9''' não teríamos problemas com a rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
'''Motivos para usarmos IPs privados:'''&lt;br /&gt;
* O principal motivo está relacionado com a segurança, uma vez que sendo um IP privado, não pode sofrer ataques DDoS direcionados diretamente para ele, vindos da Internet.&lt;br /&gt;
* Nem mesmo o cliente da sua rede conhece os '''IPs públicos''' utilizados para recursividade na Internet.&lt;br /&gt;
* Memorizar os IPs '''10.10.10.10''' e '''10.10.9.9''' é tão fácil quanto memorizar o '''8.8.8.8''' e o '''1.1.1.1'''. Mais fácil para o seu técnico guardar essa informação e utilizar onde for necessário.&lt;br /&gt;
Cada servidor DNS Recursivo possui um '''IPv4 público''', aqui representado por '''198.18.x.x/27''' e um '''IPv6 global''' representado por um IP dentro do prefixo '''2001:db8::/32'''. Cada servidor precisa ter os seus próprios IPs e são através destes IPs que as consultas de DNS serão realizadas na Internet.&lt;br /&gt;
&lt;br /&gt;
Nessa topologia usando '''Anycast''', o cliente será sempre atendido pelo '''DNS Recursivo''' mais próximo, desde que os pesos no '''OSPF''' estejam ajustados corretamente.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
== Dados do servidor ==&lt;br /&gt;
Podemos utilizar um sistema virtualizado ou não. Sistemas virtualizados são bem vindos pois são mais simples quando precisamos fazer backups, levantar outros sistemas sem complicações e se precisarmos restaurar rapidamente algum sistema que ficou indisponível por algum motivo. A configuração abaixo tem capacidade para atender algo em torno a '''50.000 assinantes ou mais'''. O DNS Recursivo é um serviço que pode ser utilizado até mesmo em um '''Raspberry Pi''' e atender operações pequenas, nesse caso com o intuito de economizar energia e espaço. Nosso foco aqui é montar uma rede de '''DNS Recursivo Anycast com HyperLocal'''. Como comentei acima o servidor deve ficar o mais próximo dos clientes para termos a '''menor latência possível''' e '''sempre menor que 5ms''' entre o cliente e o servidor.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!CPU&lt;br /&gt;
!Memória&lt;br /&gt;
!Disco&lt;br /&gt;
!Sistema&lt;br /&gt;
|-&lt;br /&gt;
|2.4Ghz 8 cores&lt;br /&gt;
|16G DDR4&lt;br /&gt;
|30G&lt;br /&gt;
|Debian 13 amd64 (Trixie)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Softwares utilizados ==&lt;br /&gt;
* Debian 13 amd64 (Trixie) instalação mínima.&lt;br /&gt;
&lt;br /&gt;
* [https://frrouting.org/ FRRouting].&lt;br /&gt;
* Unbound.&lt;br /&gt;
* Chrony (NTP/NTS).&lt;br /&gt;
* Shell script em bash.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades que teremos ==&lt;br /&gt;
* Sistema em Anycast.&lt;br /&gt;
* Hyperlocal.&lt;br /&gt;
* Controle de acesso por &amp;lt;abbr&amp;gt;ACL&amp;lt;/abbr&amp;gt;.&lt;br /&gt;
* RPZ (Response Policy Zone).&lt;br /&gt;
* Bloqueio de consultas do tipo ANY.&lt;br /&gt;
* QNAME minimization habilitado. (habilitado por default no Unbound)&lt;br /&gt;
* Recursividade em IPv4 e IPv6.&lt;br /&gt;
* DNSSEC habilitado.&lt;br /&gt;
* &amp;lt;abbr&amp;gt;DoH (DNS&amp;lt;/abbr&amp;gt; over HTTPS) habilitado.&lt;br /&gt;
&lt;br /&gt;
== Monitoramento ==&lt;br /&gt;
O monitoramento é algo bem específico e não é o foco deste documento mas é extremamente importante que você monitore seus servidores de DNS por alguma ferramenta como o Zabbix. Aqui mostrarei apenas como enviar as informações para o Zabbix. Algumas coisas que você deveria monitorar nos servidores de DNS Recursivo:&lt;br /&gt;
* Serviço do unbound parou.&lt;br /&gt;
* Perda de pacotes.&lt;br /&gt;
* Latência alta de pacotes.&lt;br /&gt;
* Lentidão na resolução de queries.&lt;br /&gt;
* CPU alta.&lt;br /&gt;
* Load alto.&lt;br /&gt;
* Memória com uso alto.&lt;br /&gt;
* Disco com pouco espaço.&lt;br /&gt;
* Queda brusca nas queries.&lt;br /&gt;
* A recursividade parou de funcionar.&lt;br /&gt;
* A recursividade voltou a funcionar.&lt;br /&gt;
Este abaixo é um exemplo de monitoramento de um sistema de DNS Recursivo que atende 50.000 assinantes:&lt;br /&gt;
[[Arquivo:Grafana dns.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Configurando a Rede ==&lt;br /&gt;
Nossa documentação será baseada no diagrama apresentado acima e por isso configuraremos apenas um dos três servidores, porque os outros serão configurados da mesma forma, só que com dados diferentes. Para tanto assumirei que já temos um sistema Debian instalado com o mínimo de pacotes e somente com sshd, para que possamos acessar remotamente mais tarde. '''Não instale um ambiente gráfico no servidor''', você não deve querer fazer isso por diversos motivos e os principais: primeiro porque não é um Desktop e segundo porque o ambiente gráfico devoraria toda a memória com recursos que não seriam úteis aqui.&lt;br /&gt;
&lt;br /&gt;
Em '''/etc/network/interfaces''' deixaremos assim:&lt;br /&gt;
 # This file describes the network interfaces available on your system&lt;br /&gt;
 # and how to activate them. For more information, see interfaces(5).&lt;br /&gt;
  &lt;br /&gt;
 source /etc/network/interfaces.d/*&lt;br /&gt;
  &lt;br /&gt;
 # The loopback network interface&lt;br /&gt;
 auto lo&lt;br /&gt;
 iface lo inet loopback&lt;br /&gt;
  &lt;br /&gt;
 auto lo:0&lt;br /&gt;
 iface lo:0 inet static&lt;br /&gt;
       address 10.10.10.10/32&lt;br /&gt;
  &lt;br /&gt;
 auto lo:1&lt;br /&gt;
 iface lo:1 inet static&lt;br /&gt;
       address 10.10.9.9/32&lt;br /&gt;
 &lt;br /&gt;
 auto lo:2&lt;br /&gt;
 iface lo:2 inet6 static&lt;br /&gt;
       address fd00::10:10:10:10/128&lt;br /&gt;
 &lt;br /&gt;
 auto lo:3&lt;br /&gt;
 iface lo:3 inet6 static&lt;br /&gt;
       address fd00::10:10:9:9/128&lt;br /&gt;
  &lt;br /&gt;
 # The primary network interface&lt;br /&gt;
 auto ens18&lt;br /&gt;
 iface ens18 inet static&lt;br /&gt;
         address 198.18.1.10/27&lt;br /&gt;
         gateway 198.18.1.1&lt;br /&gt;
  &lt;br /&gt;
 iface ens18 inet6 static&lt;br /&gt;
         address 2001:db8::faca:198:18:1:10/64&lt;br /&gt;
         gateway 2001:db8::faca:198:18:1:1&lt;br /&gt;
  &lt;br /&gt;
 # The secondary network interface&lt;br /&gt;
 auto ens18:0&lt;br /&gt;
 iface ens18:0 inet static&lt;br /&gt;
         address 172.16.0.6/30&lt;br /&gt;
Nesse cenário temos as duas '''loopbacks''' com os IPs '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10''' e '''fd00::10:10:9:9''' que serão anunciados via OSPF para a rede e serem entregues aos clientes via BNG. Os IPs '''198.18.1.10''' e '''2001:db8::faca:198:18:1:10''' serão usados para fazerem a recursividade na Internet tanto em IPv4 quanto em IPv6. Esses IPs não devem ser divulgados para clientes; os IPs públicos são dedicados apenas para essa finalidade.&lt;br /&gt;
&lt;br /&gt;
== Configuração dos repositórios Debian ==&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://security.debian.org/debian-security/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-security&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-updates&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian-backports.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-backports&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
&lt;br /&gt;
 # rm /etc/apt/sources.list&lt;br /&gt;
Após a configuração vamos instalar alguns pacotes necessários e outros úteis:&lt;br /&gt;
 # apt update &amp;amp;&amp;amp; apt full-upgrade&lt;br /&gt;
 # apt install net-tools nftables htop iotop sipcalc tcpdump curl gnupg rsync wget host dnsutils mtr-tiny bmon sudo tmux whois ethtool dnstop&lt;br /&gt;
&lt;br /&gt;
== Fazendo algum tuning no sistema ==&lt;br /&gt;
Em '''/etc/sysctl.d/100-tuning.conf''' adicionamos essas instruções:&lt;br /&gt;
 net.core.rmem_max = 2147483647&lt;br /&gt;
 net.core.wmem_max = 2147483647&lt;br /&gt;
 net.ipv4.tcp_rmem = 4096 87380 2147483647&lt;br /&gt;
 net.ipv4.tcp_wmem = 4096 65536 2147483647&lt;br /&gt;
 net.netfilter.nf_conntrack_buckets = 512000&lt;br /&gt;
 net.netfilter.nf_conntrack_max = 4096000&lt;br /&gt;
 vm.swappiness=10&lt;br /&gt;
Estamos fazendo algumas melhorias de memória, algumas relacionadas a '''conntrack''' porque se for usar um filtro de pacotes stateful, como o '''Netfilter/IPTables''' ou '''Netfilter/NFTables''', o valor default da tabela é pequeno e dependendo da situação, se estourar essa tabela, as consultas de DNS terão problemas também. O DNS Recursivo não deve ficar aberto para qualquer um na Internet, ele deve ser liberado apenas para seus clientes. Podemos fazer através das ACLs do Unbound e pelo filtro de pacotes. O último parâmetro diz respeito ao uso de swap, por padrão o Debian permite o uso de swap após 40% do uso da memória, nesse caso estamos dizendo para o sistema usar o swap com 90% de uso da memória.&lt;br /&gt;
&lt;br /&gt;
Precisamos adicionar o módulo '''nf_conntrack''' em '''/etc/modules''' para que seja carregado em tempo de boot, senão os parâmetros de '''conntrack''' que colocamos em '''/etc/sysctl.conf''' não serão carregados.&lt;br /&gt;
 # echo nf_conntrack &amp;gt;&amp;gt; /etc/modules&lt;br /&gt;
 # modprobe nf_conntrack&lt;br /&gt;
 # sysctl -p&lt;br /&gt;
&lt;br /&gt;
== Instalando o FRRouting ==&lt;br /&gt;
O FRRouting é o programa que usaremos para fazer os anúncios das nossas loopbacks via OSPF. Nesse documento usaremos a versão 10.x:&lt;br /&gt;
 # apt install frr frr-doc frr-pythontools&lt;br /&gt;
Aconselho depois de instalar os pacotes, marcá-los para não atualizar juntamente com os demais pacotes, isso é para evitar de ocorrer alguma atualização no FRRouting, que torne o serviço instável por algum motivo. Não que isso vá ocorrer, mas é melhor fazer essa atualização quando realmente for necessário.&lt;br /&gt;
 # apt-mark hold frr frr-doc frr-pythontools&lt;br /&gt;
Após esse comando acima, o sistema manterá a instalação original do pacote intacta. Para desbloquear basta executar o comando abaixo:&lt;br /&gt;
 # apt-mark unhold frr frr-doc frr-pythontools&lt;br /&gt;
&lt;br /&gt;
== Removendo o APPARMOR ==&lt;br /&gt;
O '''APPARMOR''' às vezes causa mais problemas que solução e se não for fazer uma completa configuração nele, é melhor desabilitá-lo. Para fazer isso efetivamente, o procedimento é esse abaixo:&lt;br /&gt;
 # mkdir -p /etc/default/grub.d&lt;br /&gt;
 # echo 'GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;$GRUB_CMDLINE_LINUX_DEFAULT apparmor=0&amp;quot;' | tee /etc/default/grub.d/apparmor.cfg&lt;br /&gt;
 # update-grub&lt;br /&gt;
 # reboot&lt;br /&gt;
&lt;br /&gt;
== Instalando o Unbound ==&lt;br /&gt;
Nesse momento ainda não iremos configurar o Unbound, apenas instalar o pacote e acertar o ambiente. Vamos instalar o unbound do backports porque este já possui suporte ao DoH que veremos mais à frente.&lt;br /&gt;
 # apt install unbound dns-root-data&lt;br /&gt;
 # mkdir -p /var/log/unbound&lt;br /&gt;
 # touch /var/log/unbound/unbound.log&lt;br /&gt;
 # chown -R unbound:unbound /var/log/unbound/&lt;br /&gt;
 # systemctl restart unbound&lt;br /&gt;
Configurando o logrotate:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/logrotate.d/unbound&lt;br /&gt;
 /var/log/unbound/unbound.log {&lt;br /&gt;
     rotate 5&lt;br /&gt;
     weekly&lt;br /&gt;
     postrotate&lt;br /&gt;
         unbound-control log_reopen&lt;br /&gt;
     endscript&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
Reiniciando o serviço:&lt;br /&gt;
 # systemctl restart logrotate.service&lt;br /&gt;
&lt;br /&gt;
== Desabilitando THP (Transparente Huge Pages) em arquitetura AMD64 ==&lt;br /&gt;
No Debian o '''THP''' vem habilitado como '''always''' e o '''unbound''' por trabalhar bastante com alterações do cache em memória, isso pode acabar causando um consumo crescente de uso de RAM sem necessidade. É uma boa prática desabilitá-lo com os passos abaixo:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/systemd/system/disable-thp.service&lt;br /&gt;
 [Unit]&lt;br /&gt;
 Description=Ajusta Transparent Huge Pages (THP)&lt;br /&gt;
 After=network.target&lt;br /&gt;
 &lt;br /&gt;
 [Service]&lt;br /&gt;
 Type=oneshot&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled&amp;quot;&lt;br /&gt;
 RemainAfterExit=yes&lt;br /&gt;
 &lt;br /&gt;
 [Install]&lt;br /&gt;
 WantedBy=multi-user.target&lt;br /&gt;
 EOF&lt;br /&gt;
Acima configuramos o serviço '''disable-thp.service''' para desabilitar o '''THP''' e abaixo habilitamos no '''systemd''' e iniciamos:&lt;br /&gt;
 # systemctl daemon-reload&lt;br /&gt;
 # systemctl enable --now disable-thp&lt;br /&gt;
&lt;br /&gt;
== Preparando o monitoramento do seu DNS Recursivo ==&lt;br /&gt;
O monitoramento do seu DNS Recursivo é muito importante e para isso vamos usar um '''template para Zabbix''', que modifiquei juntamente com o seu shell script e que enviará os dados para o seu Zabbix server via '''zabbix-sender'''. O projeto original está aqui '''https://github.com/jeftedelima/Unbound-DNS&amp;lt;nowiki/&amp;gt;.''' O xml alterado está aqui '''https://github.com/gondimcodes/template_zabbix_dns_unbound'''. Embora seja antigo é perfeitamente importável no Zabbix 6.0, por exemplo.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;nowiki/&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Teremos um shell script que você precisará colocar no seu '''/etc/crontab'''. No exemplo abaixo assumi que o shell script está em '''/root/scripts'''. De 5 em 5 minutos os dados serão enviados para o seu Zabbix server.&lt;br /&gt;
 */5 * * * *     root    /root/scripts/unboundSend.sh '''IP_zabbix_server''' '''nome_do_host''' 1&amp;gt; /dev/null&lt;br /&gt;
Na linha acima, troque o '''IP_zabbix_server''' pelo '''IP do seu servidor Zabbix''' e o '''nome_do_host''' pelo '''hostname''' '''do seu DNS Recursivo'''. Você precisará instalar o pacote '''zabbix-sender''' no seu DNS Recursivo pois ele será usado para enviar os dados para o Zabbix server.&lt;br /&gt;
&lt;br /&gt;
Abaixo o '''unboundSend.sh''' também alterado com inclusão de mais dados:&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 #       @Jefte de Lima Ferreira&lt;br /&gt;
 #       jeftedelima at gmail dot com&lt;br /&gt;
 #       CRON Example&lt;br /&gt;
 #       Contributor: Marcelo Gondim - gondim at gmail dot com&lt;br /&gt;
 #       */5   **** root sh /home/dir/unboundSend.sh 192.168.10.1 Unbound 1&amp;gt; /dev/null&lt;br /&gt;
  &lt;br /&gt;
 if [ -z ${1} ] || [ -z ${2} ] ; then&lt;br /&gt;
         echo &amp;quot;You need to specify the IP address of zabbix server and hostname of your DNS Unbound on zabbix&amp;quot;&lt;br /&gt;
         echo &amp;quot;Usage example: ./unboundSend.sh 192.168.10.1 UnboundServer&amp;quot;&lt;br /&gt;
         exit 1&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 # ZABBIX_SERVER IP&lt;br /&gt;
 IP_ZABBIX=$1&lt;br /&gt;
 # NAME Unbound on Zabbix&lt;br /&gt;
 NAME_HOST=$2&lt;br /&gt;
 DIR_TEMP=/var/tmp/&lt;br /&gt;
 FILE=&amp;quot;${DIR_TEMP}dump_unbound_control_stats.txt&amp;quot;&lt;br /&gt;
 unbound-control stats &amp;gt; ${FILE}&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_NUM_QUERIES=$(cat ${FILE} | grep -w 'total.num.queries' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEHITS=$(cat ${FILE} | grep -w 'total.num.cachehits' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEMISS=$(cat ${FILE} | grep -w 'total.num.cachemiss' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_PREFETCH=$(cat ${FILE} | grep -w 'total.num.prefetch' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_RECURSIVEREPLIES=$(cat ${FILE} | grep -w 'total.num.recursivereplies' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_REQ_MAX=$(cat ${FILE} | grep -w 'total.requestlist.max' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_AVG=$(cat ${FILE} | grep -w 'total.requestlist.avg' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_OVERWRITTEN=$(cat ${FILE} | grep -w 'total.requestlist.overwritten' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_EXCEEDED=$(cat ${FILE} | grep -w 'total.requestlist.exceeded' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_ALL=$(cat ${FILE} | grep -w 'total.requestlist.current.all' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_USER=$(cat ${FILE} | grep -w 'total.requestlist.current.user' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_TCPUSAGE=$(cat ${FILE} | grep -w 'total.tcpusage' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_QUERY_TYPE_A=$(cat ${FILE} | grep -w 'num.query.type.A' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NS=$(cat ${FILE} | grep -w 'num.query.type.NS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_MX=$(cat ${FILE} | grep -w 'num.query.type.MX' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TXT=$(cat ${FILE} | grep -w 'num.query.type.TXT' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_PTR=$(cat ${FILE} | grep -w 'num.query.type.PTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_AAAA=$(cat ${FILE} | grep -w 'num.query.type.AAAA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SRV=$(cat ${FILE} | grep -w 'num.query.type.SRV' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SOA=$(cat ${FILE} | grep -w 'num.query.type.SOA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HTTPS=$(cat ${FILE} | grep -w 'num.query.type.HTTPS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TYPE0=$(cat ${FILE} | grep -w 'num.query.type.TYPE0' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_CNAME=$(cat ${FILE} | grep -w 'num.query.type.CNAME' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_WKS=$(cat ${FILE} | grep -w 'num.query.type.WKS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HINFO=$(cat ${FILE} | grep -w 'num.query.type.HINFO' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_X25=$(cat ${FILE} | grep -w 'num.query.type.X25' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NAPTR=$(cat ${FILE} | grep -w 'num.query.type.NAPTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DS=$(cat ${FILE} | grep -w 'num.query.type.DS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DNSKEY=$(cat ${FILE} | grep -w 'num.query.type.DNSKEY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TLSA=$(cat ${FILE} | grep -w 'num.query.type.TLSA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SVCB=$(cat ${FILE} | grep -w 'num.query.type.SVCB' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SPF=$(cat ${FILE} | grep -w 'num.query.type.SPF' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_ANY=$(cat ${FILE} | grep -w 'num.query.type.ANY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_OTHER=$(cat ${FILE} | grep -w 'num.query.type.other' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_ANSWER_RCODE_NOERROR=$(cat ${FILE} | grep -w 'num.answer.rcode.NOERROR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_NXDOMAIN=$(cat ${FILE} | grep -w 'num.answer.rcode.NXDOMAIN' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_SERVFAIL=$(cat ${FILE} | grep -w 'num.answer.rcode.SERVFAIL' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_REFUSED=$(cat ${FILE} | grep -w 'num.answer.rcode.REFUSED' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_nodata=$(cat ${FILE} | grep -w 'num.answer.rcode.nodata' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_secure=$(cat ${FILE} | grep -w 'num.answer.secure' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 #       Sending info to zabbix_server.&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.queries -o $(( ${TOTAL_NUM_QUERIES:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachehits -o $(( ${TOTAL_NUM_CACHEHITS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachemiss -o $(( ${TOTAL_NUM_CACHEMISS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.prefetch -o $(( ${TOTAL_NUM_PREFETCH:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.recursivereplies -o $(( ${TOTAL_NUM_RECURSIVEREPLIES:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.max -o $(( ${TOTAL_REQ_MAX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.avg -o $(( ${TOTAL_REQ_AVG:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.overwritten -o $(( ${TOTAL_REQ_OVERWRITTEN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.exceeded -o $(( ${TOTAL_REQ_EXCEEDED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.all -o $(( ${TOTAL_REQ_CURRENT_ALL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.user -o $(( ${TOTAL_REQ_CURRENT_USER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.tcpusage -o $(( ${TOTAL_TCPUSAGE:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.a -o $(( ${NUM_QUERY_TYPE_A:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ns -o $(( ${NUM_QUERY_TYPE_NS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.mx -o $(( ${NUM_QUERY_TYPE_MX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.txt -o $(( ${NUM_QUERY_TYPE_TXT:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ptr -o $(( ${NUM_QUERY_TYPE_PTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.aaaa -o $(( ${NUM_QUERY_TYPE_AAAA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.srv -o $(( ${NUM_QUERY_TYPE_SRV:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.soa -o $(( ${NUM_QUERY_TYPE_SOA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.https -o $(( ${NUM_QUERY_TYPE_HTTPS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.type0 -o $(( ${NUM_QUERY_TYPE_TYPE0:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.cname -o $(( ${NUM_QUERY_TYPE_CNAME:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.wks -o $(( ${NUM_QUERY_TYPE_WKS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.hinfo -o $(( ${NUM_QUERY_TYPE_HINFO:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.X25 -o $(( ${NUM_QUERY_TYPE_X25:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.naptr -o $(( ${NUM_QUERY_TYPE_NAPTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ds -o $(( ${NUM_QUERY_TYPE_DS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.dnskey -o $(( ${NUM_QUERY_TYPE_DNSKEY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.tlsa -o $(( ${NUM_QUERY_TYPE_TLSA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.svcb -o $(( ${NUM_QUERY_TYPE_SVCB:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.spf -o $(( ${NUM_QUERY_TYPE_SPF:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.any -o $(( ${NUM_QUERY_TYPE_ANY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.other -o $(( ${NUM_QUERY_TYPE_OTHER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NOERROR -o $(( ${NUM_ANSWER_RCODE_NOERROR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NXDOMAIN -o $(( ${NUM_ANSWER_RCODE_NXDOMAIN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.SERVFAIL -o $(( ${NUM_ANSWER_RCODE_SERVFAIL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.REFUSED -o $(( ${NUM_ANSWER_RCODE_REFUSED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.nodata -o $(( ${NUM_ANSWER_RCODE_nodata:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.secure -o $(( ${NUM_ANSWER_secure:-0} / 300 ))&lt;br /&gt;
No Zabbix será registrado dados como esses abaixo e posteriormente pode ser montado um Grafana com eles:&lt;br /&gt;
[[Arquivo:Zabbix dns01.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns02.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns03.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns04.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Mantendo a hora certa ==&lt;br /&gt;
Vamos instalar agora o Chrony para manter a data e hora certas no sistema:&lt;br /&gt;
 # apt install chrony&lt;br /&gt;
Após a instalação do Chrony edite o arquivo /etc/chrony/chrony.conf, comente e a linha abaixo e adicione seus servidores NTP. Caso não tenha servidores NTP, estou colocando os do NIC.br aqui.&lt;br /&gt;
 #pool 2.debian.pool.ntp.org iburst&lt;br /&gt;
 server a.st1.ntp.br iburst nts&lt;br /&gt;
 server b.st1.ntp.br iburst nts&lt;br /&gt;
 server c.st1.ntp.br iburst nts&lt;br /&gt;
 server d.st1.ntp.br iburst nts&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart chronyd.service&lt;br /&gt;
Cheque com o '''chronyc''' se os servidores estão OK:&lt;br /&gt;
 # chronyc sourcestats&lt;br /&gt;
 Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev&lt;br /&gt;
 ==============================================================================&lt;br /&gt;
 a.st1.ntp.br               10   5  155m     -0.027      0.030    -71us    51us&lt;br /&gt;
 b.st1.ntp.br               11   7  344m     +0.068      0.079    +23ms   382us&lt;br /&gt;
 c.st1.ntp.br                6   3  344m     +0.026      0.037   -124us    92us&lt;br /&gt;
 200.20.186.76               9   3  138m     -0.022      0.031   +172us    42us&lt;br /&gt;
&lt;br /&gt;
 # chronyc sources&lt;br /&gt;
 MS Name/IP address         Stratum Poll Reach LastRx Last sample&lt;br /&gt;
 ===============================================================================&lt;br /&gt;
 ^* a.st1.ntp.br                  1  10   377   588   +487us[ +397us] +/-   12ms&lt;br /&gt;
 ^- b.st1.ntp.br                  2  10   377   830    +23ms[  +23ms] +/-   49ms&lt;br /&gt;
 ^+ c.st1.ntp.br                  2  10    21  1038   -147us[ -242us] +/-   17ms&lt;br /&gt;
 ^+ 200.20.186.76                 1  10   377  1032   +381us[ +285us] +/-   15ms&lt;br /&gt;
&lt;br /&gt;
== Configurando o FRRouting ==&lt;br /&gt;
Nesse ponto iremos configurar o '''FRRouting''' para enviar os IPs das '''loopbacks''' e o '''/30''' para o nosso PE do diagrama. Em '''/etc/frr/daemons''' habilite o parâmetro conforme abaixo:&lt;br /&gt;
 ospfd=yes&lt;br /&gt;
 ospf6d=yes&lt;br /&gt;
Edite o arquivo '''/etc/frr/frr.conf''' e deixe com o conteúdo abaixo, para ficar conforme nosso diagrama do projeto. Apenas troque '''&amp;lt;SENHA&amp;gt;''' por uma senha para fechar o OSPF com mais segurança. Essa senha deve ser usada dos dois lados.&lt;br /&gt;
 frr version 10.3&lt;br /&gt;
 frr defaults traditional&lt;br /&gt;
 hostname dns-recursivo-01&lt;br /&gt;
 log syslog informational&lt;br /&gt;
 no ip forwarding&lt;br /&gt;
 no ipv6 forwarding&lt;br /&gt;
 service integrated-vtysh-config&lt;br /&gt;
 !&lt;br /&gt;
 interface ens18&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf message-digest-key 5 md5 &amp;lt;SENHA&amp;gt;&lt;br /&gt;
  ip ospf network point-to-point&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 network point-to-point&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 interface lo&lt;br /&gt;
  description LOOPBACKS&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf passive&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 passive&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf&lt;br /&gt;
  ospf router-id 172.16.0.6&lt;br /&gt;
  area 0.0.0.0 authentication message-digest&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf6&lt;br /&gt;
  ospf6 router-id 172.16.0.6&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart frr.service&lt;br /&gt;
Cheque se está tudo OK com o OSPF e verifique no PE se está recebendo os prefixos anunciados.&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL&lt;br /&gt;
 172.16.0.5     1 Full/-          10m49s            35.310s 172.16.0.5   ens18:172.16.0.6                  0     0     0&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri    DeadTime    State/IfState         Duration I/F[State]&lt;br /&gt;
 172.16.0.5       1    00:00:30     Full/PointToPoint 25d22:53:47 ens18[PointToPoint]&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor detail'&lt;br /&gt;
 &lt;br /&gt;
  Neighbor 172.16.0.5, interface address 172.16.0.5&lt;br /&gt;
     In the area 0.0.0.0 via interface ens18&lt;br /&gt;
     Neighbor priority is 1, State is Full/-, 5 state changes&lt;br /&gt;
     Most recent state change statistics:&lt;br /&gt;
       Progressive change 21w3d15h ago&lt;br /&gt;
     DR is 0.0.0.0, BDR is 0.0.0.0&lt;br /&gt;
     Options 18 *|-|-|EA|-|-|E|-&lt;br /&gt;
     Dead timer due in 34.685s&lt;br /&gt;
     Database Summary List 0&lt;br /&gt;
     Link State Request List 0&lt;br /&gt;
     Link State Retransmission List 0&lt;br /&gt;
     Thread Inactivity Timer on&lt;br /&gt;
     Thread Database Description Retransmision off&lt;br /&gt;
     Thread Link State Request Retransmission on&lt;br /&gt;
     Thread Link State Update Retransmission on&lt;br /&gt;
 &lt;br /&gt;
     Graceful restart Helper info:&lt;br /&gt;
       Graceful Restart HELPER Status : None&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor detail'&lt;br /&gt;
  Neighbor 172.16.0.5%ens18&lt;br /&gt;
     Area 0.0.0.0 via interface ens18 (ifindex 4)&lt;br /&gt;
     His IfIndex: 60 Link-local address: fe80::469b:c1ff:fed6:43ee&lt;br /&gt;
     State Full for a duration of 25d22:57:14&lt;br /&gt;
     His choice of DR/BDR 0.0.0.0/0.0.0.0, Priority 1&lt;br /&gt;
     DbDesc status: Master SeqNum: 0xb94b0000&lt;br /&gt;
     Summary-List: 0 LSAs&lt;br /&gt;
     Request-List: 0 LSAs&lt;br /&gt;
     Retrans-List: 0 LSAs&lt;br /&gt;
     0 Pending LSAs for DbDesc in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSReq in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSAck in Time 00:00:00 [thread off]&lt;br /&gt;
     Authentication header not present&lt;br /&gt;
&lt;br /&gt;
== Configurando o Unbound ==&lt;br /&gt;
Abaixo a configuração que usaremos nos servidores atentando para o detalhe do '''num-threads''', esse deve ter o valor igual ao número de CPUs do servidor.&lt;br /&gt;
&lt;br /&gt;
Também os IPs utilizados em '''outgoing-interface''' que serão diferentes em cada servidor, esses serão os IPs usados para '''recursividade'''. Consulte o manual do Unbound para obter mais informações sobre cada parâmetro listado na configuração.&lt;br /&gt;
&lt;br /&gt;
O tuning no Unbound pode ser alterado conforme abaixo:&lt;br /&gt;
 num-threads = nº CPUs&lt;br /&gt;
 so-reuseport = yes&lt;br /&gt;
 *-slabs = potência de 2 próximo ao num-threads&lt;br /&gt;
 msg-cache-size = 1g (quantidade de memória pra usar de cache)&lt;br /&gt;
 rrset-cache-size = 2 * msg-cache-size&lt;br /&gt;
 outgoing-range = 8192&lt;br /&gt;
 num-queries-per-thread = 4096&lt;br /&gt;
 so-rcvbuf e so-sndbuf = 4m ou 8m para servidores com muita requisição&lt;br /&gt;
Agora vamos criar nosso arquivo de configuração base em '''/etc/unbound/unbound.conf.d/local.conf''':&lt;br /&gt;
 server:&lt;br /&gt;
         verbosity: 1&lt;br /&gt;
         statistics-interval: 0&lt;br /&gt;
         statistics-cumulative: no&lt;br /&gt;
         extended-statistics: yes&lt;br /&gt;
         num-threads: 8&lt;br /&gt;
         serve-expired: yes&lt;br /&gt;
         interface: 127.0.0.1&lt;br /&gt;
         interface: 10.10.10.10&lt;br /&gt;
         interface: 10.10.9.9&lt;br /&gt;
         interface: 172.16.0.6&lt;br /&gt;
         interface: fd00::10:10:10:10&lt;br /&gt;
         interface: fd00::10:10:9:9&lt;br /&gt;
         interface: ::1&lt;br /&gt;
         interface-automatic: no&lt;br /&gt;
         outgoing-interface: 198.18.1.10&lt;br /&gt;
         outgoing-interface: 2001:db8::faca:198:18:1:10&lt;br /&gt;
         outgoing-range: 8192&lt;br /&gt;
         outgoing-num-tcp: 1024&lt;br /&gt;
         incoming-num-tcp: 2048&lt;br /&gt;
         so-rcvbuf: 4m&lt;br /&gt;
         so-sndbuf: 4m&lt;br /&gt;
         so-reuseport: yes&lt;br /&gt;
         edns-buffer-size: 1232&lt;br /&gt;
         msg-cache-size: 512m&lt;br /&gt;
         msg-cache-slabs: 4&lt;br /&gt;
         num-queries-per-thread: 4096&lt;br /&gt;
         rrset-cache-size: 1g&lt;br /&gt;
         rrset-cache-slabs: 4&lt;br /&gt;
         infra-cache-slabs: 4&lt;br /&gt;
         do-ip4: yes&lt;br /&gt;
         do-ip6: yes&lt;br /&gt;
         do-udp: yes&lt;br /&gt;
         do-tcp: yes&lt;br /&gt;
         chroot: &amp;quot;&amp;quot;&lt;br /&gt;
         username: &amp;quot;unbound&amp;quot;&lt;br /&gt;
         directory: &amp;quot;/etc/unbound&amp;quot;&lt;br /&gt;
         logfile: &amp;quot;/var/log/unbound/unbound.log&amp;quot;&lt;br /&gt;
         use-syslog: no&lt;br /&gt;
         log-time-ascii: yes&lt;br /&gt;
         log-queries: no&lt;br /&gt;
         pidfile: &amp;quot;/var/run/unbound.pid&amp;quot;&lt;br /&gt;
         root-hints: &amp;quot;/usr/share/dns/root.hints&amp;quot;&lt;br /&gt;
         hide-identity: yes&lt;br /&gt;
         hide-version: yes&lt;br /&gt;
         unwanted-reply-threshold: 10000000&lt;br /&gt;
         prefetch: yes&lt;br /&gt;
         prefetch-key: yes&lt;br /&gt;
         rrset-roundrobin: yes&lt;br /&gt;
         minimal-responses: yes&lt;br /&gt;
         module-config: &amp;quot;respip validator iterator&amp;quot;&lt;br /&gt;
         val-clean-additional: yes&lt;br /&gt;
         val-log-level: 1&lt;br /&gt;
         key-cache-slabs: 4&lt;br /&gt;
         deny-any: yes&lt;br /&gt;
         cache-min-ttl: 60&lt;br /&gt;
         key-cache-size: 128m&lt;br /&gt;
         neg-cache-size: 64m&lt;br /&gt;
         cache-max-ttl: 86400&lt;br /&gt;
         infra-cache-numhosts: 100000&lt;br /&gt;
         access-control: 198.18.0.0/22 allow&lt;br /&gt;
         access-control: 2001:db8::/32 allow&lt;br /&gt;
  &lt;br /&gt;
 rpz:&lt;br /&gt;
   name: rpz.block.host.local.zone&lt;br /&gt;
   zonefile: /etc/unbound/rpz.block.hosts.zone&lt;br /&gt;
   rpz-action-override: nxdomain&lt;br /&gt;
  &lt;br /&gt;
 python:&lt;br /&gt;
  &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;.&amp;quot;&lt;br /&gt;
     master: &amp;quot;b.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;c.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;d.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;f.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;g.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;k.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/root.zone&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;arpa.&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/arpa.zone&amp;quot;&lt;br /&gt;
No parâmetro '''interface''' colocamos os IPs que serão usados para consulta dos clientes como o '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9'''. Ali repare que coloquei também o IP privado '''172.16.0.6''', isso porque cada servidor terá o seu IP privado e este deve ser usado pelo seu sistema de monitoramento para checar cada servidor. No '''outgoing-interface''' teremos os IPs, tanto '''IPv4''' quanto '''IPv6''', para que seja feita a recursividade na Internet utilizando eles. Não tem '''IPv6''' ainda na sua rede? Dê uma olhada nesse artigo. Outro parâmetro importante é o '''access-control''' e é através dele que liberamos os prefixos IP para consultarem no nosso DNS Recursivo. No exemplo estou liberando todo o prefixo '''198.18.0.0/22''' e o prefixo '''2001:db8::/32'''. Além da ACL no Unbound, recomendo que crie um filtro de pacotes com iptables ou nftables protegendo seu sistema e liberando as portas '''53/UDP''', '''53/TCP,'''  '''443/TCP e 853/TCP''' apenas para seus clientes. Falarei sobre a '''443/TCP e 853/TCP''' mais para frente nessa mesma documentação.&lt;br /&gt;
&lt;br /&gt;
Agora criaremos o arquivo '''RPZ''' ('''Response Policy Zones'''). Esse arquivo contém os sites que serão bloqueados via '''&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; Recursivo'''. São aqueles sites que às vezes você recebe um Ofício da Justiça solicitando o bloqueio deles. Não entrarei no mérito da efetividade desses bloqueios, porque muitos de vocês sabem que tecnicamente, existem formas de se fazer um bypass através desses bloqueios. Contudo vamos deixar nosso ambiente preparado para esses bloqueios e por isso crie o arquivo '''/etc/unbound/rpz.block.hosts.zone''' com esse conteúdo de exemplo:&lt;br /&gt;
 $TTL 2h&lt;br /&gt;
 @ IN SOA localhost. root.localhost. (2 6h 1h 1w 2h)&lt;br /&gt;
   IN NS  localhost.&lt;br /&gt;
 ; RPZ manual block hosts&lt;br /&gt;
 *.josedascoves.com CNAME .&lt;br /&gt;
 josedascoves.com CNAME .&lt;br /&gt;
No exemplo acima estamos bloqueando qualquer consulta de DNS para '''josedascoves.com''' ou qualquer coisa '''.josedascoves.com'''.&lt;br /&gt;
&lt;br /&gt;
Para testar podemos fazer assim do próprio servidor:&lt;br /&gt;
 # host josedascoves.com ::1&lt;br /&gt;
 Using domain server:&lt;br /&gt;
 Name: ::1&lt;br /&gt;
 Address: ::1#53&lt;br /&gt;
 Aliases:&lt;br /&gt;
 &lt;br /&gt;
 Host josedascoves.com not found: 3(NXDOMAIN)&lt;br /&gt;
Se a resposta for '''NXDOMAIN''' então está funcionando o bloqueio. Para incluir novos bloqueios basta adicionar os domínios, um abaixo do outro, conforme o exemplo que coloquei no arquivo RPZ.&lt;br /&gt;
&lt;br /&gt;
== Acertando o resolv.conf ==&lt;br /&gt;
Vamos modificar nosso /etc/resolv.conf para utilizar DNS externo. Sim você deve estar se perguntando em qual situação isso seria utilizado. Primeiro entenda que o Unbound não irá utilizar o DNS externo para fazer as consultas na Internet e sim, qualquer teste que você faça do servidor precisará apontar para o Unbound usando os IPs '''127.0.0.1''' ou '''::1'''. Faremos isso pela seguinte situação: imagine que o daemon unbound morreu mas você ainda continua com conectividade na Internet. Você conseguiria acessar qualquer local na Internet através do IP mas não através do hostname porque não conseguiria resolver nomes, seu unbound estaria fora do ar. Imagine ainda que você gostaria que seu servidor te avisasse do problema via Telegram ou e-mail. Por isso estamos utilizando um DNS externo no '''/etc/resolv.conf''', apenas para essas situações. Se você não quiser utilizar desse recurso, pode usar o '''127.0.0.1''' e '''::1''' no lugar.&lt;br /&gt;
 nameserver 8.8.8.8&lt;br /&gt;
 nameserver 8.8.4.4&lt;br /&gt;
 nameserver 2001:4860:4860::8888&lt;br /&gt;
&lt;br /&gt;
== Script de teste de recursividade ==&lt;br /&gt;
Estamos montando uma '''Rede de DNS Recursivo Anycast''', então é muito importante que você monitore essa rede para saber se algum node morreu e iniciar o troubleshooting, resolver o problema e levantar o sistema novamente. Tudo isso é importante mas o cliente não deve ficar esperando até você resolver o problema, seu sistema precisa ser inteligente o suficiente para se remover da Rede quando tiver um problema e se inserir novamente, quando o problema estiver sido solucionado. Se você montar uma Rede de DNS e um dos nodes apresentar algum problema, todos os clientes atendidos por aquele node migrarão automaticamente e transparentemente para outro '''DNS Recursivo Anycast''' mais próximo. Isso se chama '''disponibilidade'''.&lt;br /&gt;
&lt;br /&gt;
O script '''/root/scripts/checa_dns.sh''' abaixo tem a função de fazer os testes de recursividade e checar se o daemon do unbound continua rodando. Se algo acontecer, ele para o anúncio do '''10.10.10.10''' e '''10.10.9.9''' e retorna eles quando tudo estiver resolvido.&lt;br /&gt;
 # mkdir /root/scripts&lt;br /&gt;
&lt;br /&gt;
 #!/usr/bin/env bash&lt;br /&gt;
 #Script para teste de DNS v2.1&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 #Informe um domínio por linha:&lt;br /&gt;
 dominios_testar=(&lt;br /&gt;
 www.google.com&lt;br /&gt;
 www.terra.com.br&lt;br /&gt;
 www.uol.com.br&lt;br /&gt;
 www.globo.com&lt;br /&gt;
 www.facebook.com&lt;br /&gt;
 www.youtube.com&lt;br /&gt;
 www.twitch.com&lt;br /&gt;
 www.discord.com&lt;br /&gt;
 www.debian.org&lt;br /&gt;
 www.redhat.com&lt;br /&gt;
 )&lt;br /&gt;
 corte_taxa_falha=100 #Porcentagem de falha para executar uma ação&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 remove_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; != &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no description' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME morreu!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 adiciona_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; == &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'description LOOPBACKS' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME retornou do inferno!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
 if [ $? -ne 0 ]; then&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME morreu DNS mas tentando levantar!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    systemctl restart unbound&lt;br /&gt;
    systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
    if [ $? -ne 0 ]; then&lt;br /&gt;
       remove_ospf&lt;br /&gt;
       exit&lt;br /&gt;
    fi&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME servico DNS voltou mas tinha morrido!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 qt_falhas=0&lt;br /&gt;
 qt_total=&amp;quot;${#dominios_testar[@]}&amp;quot;&lt;br /&gt;
 echo &amp;quot;total_dominios: $qt_total&amp;quot;&lt;br /&gt;
 for site in &amp;quot;${dominios_testar[@]}&amp;quot;&lt;br /&gt;
 do&lt;br /&gt;
   unbound-control flush $site &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   resolver=&amp;quot;127.0.0.1&amp;quot;&lt;br /&gt;
   echo -e &amp;quot; - dominio $site - $resolver - \c&amp;quot;&lt;br /&gt;
   host $site $resolver &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   if [ $? -ne 0 ]; then&lt;br /&gt;
      ((qt_falhas++))&lt;br /&gt;
      echo -e &amp;quot;[Falhou]&amp;quot;&lt;br /&gt;
   else&lt;br /&gt;
      echo -e &amp;quot;[OK]&amp;quot;&lt;br /&gt;
   fi&lt;br /&gt;
 done&lt;br /&gt;
  &lt;br /&gt;
 taxa_falha=$((qt_falhas*100/qt_total))&lt;br /&gt;
 echo &amp;quot;Falhas $qt_falhas/$qt_total ($taxa_falha%)&amp;quot;&lt;br /&gt;
  &lt;br /&gt;
 if [ &amp;quot;$taxa_falha&amp;quot; -ge &amp;quot;$corte_taxa_falha&amp;quot; ]; then&lt;br /&gt;
    remove_ospf&lt;br /&gt;
    exit&lt;br /&gt;
 fi&lt;br /&gt;
 adiciona_ospf&lt;br /&gt;
Se rodarmos o script manualmente veremos isto:&lt;br /&gt;
 # /root/scripts/checa_dns.sh&lt;br /&gt;
 total_dominios: 10&lt;br /&gt;
  - dominio www.google.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.terra.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.uol.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.globo.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.facebook.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.youtube.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.twitch.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.discord.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.debian.org - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.redhat.com - 127.0.0.1 - [OK]&lt;br /&gt;
 Falhas 0/10 (0%)&lt;br /&gt;
Se acontecer 100% de falhas o script irá remover os anúncios do OSPF. Se o daemon do unbound morrer, ele tentará reiniciá-lo. Se tudo normalizar o script irá retornar os anúncios para o OSPF. Deixei comentado no script as partes que enviariam uma notificação para o Telegram. Existem diversas documentações sobre isso na Internet, eu mesmo tenho uma. Assim que eu publicar aqui, atualizo essa documentação e sinta-se à vontade de modificar como desejar.&lt;br /&gt;
 # chmod 700 /root/scripts/checa_dns.sh&lt;br /&gt;
Adicione a linha abaixo em seu '''/etc/crontab''':&lt;br /&gt;
 */1 *   * * *   root    /root/scripts/checa_dns.sh&lt;br /&gt;
&lt;br /&gt;
== Habilitando o DoH (&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; over HTTPS) - opcional ==&lt;br /&gt;
Para habilitar o '''DoH''' no Unbound é bem simples. O recurso do '''DoH''' vem para trazer mais segurança e privacidade para o usuário. É um recurso muito pouco utilizado ainda mas que seu cliente pode vir a pedir algum dia.&lt;br /&gt;
&lt;br /&gt;
Você precisará gerar certificados SSL legítimos e para isso você poderá usar o '''Let's Encrypt''' só que de uma forma não tão convencional.&lt;br /&gt;
&lt;br /&gt;
Na sequência vamos instalar o Let's Encrypt para gerarmos nosso certificado SSL:&lt;br /&gt;
 # apt install letsencrypt&lt;br /&gt;
Escolha um '''hostname''' para ser usado no nosso '''DoH''' e aponte ele no seu DNS Autoritativo para seus IPs 10.10.10.10 e 10.10.9.9. Aqui vamos usar o seguinte como exemplo: '''doh.brasilpeeringforum.org'''. Para gerarmos nosso certificado iremos usar o tipo '''DNS-01''', ele não necessita que tenhamos um servidor web rodando no servidor e nem tão pouco levanta um serviço na porta 80 para checar o hostname. Ele utiliza o DNS como validador e vai te solicitar que crie um registro '''CNAME''' no seu '''DNS Autoritativo''' para provar que você tem o controle sobre aquele hostname. Antes disso vamos instalar um programa em Python para podermos automatizar nossa renovação de certificado no futuro. Esse programa se encontra '''[https://github.com/joohoi/acme-dns-certbot-joohoi/raw/master/acme-dns-auth.py aqui]''' mas vou deixá-lo abaixo já modificado o interpretador.&lt;br /&gt;
&lt;br /&gt;
Crie o arquivo '''/etc/letsencrypt/acme-dns-auth.py''' com o conteúdo abaixo:&lt;br /&gt;
 #!/usr/bin/env python3&lt;br /&gt;
 import json&lt;br /&gt;
 import os&lt;br /&gt;
 import requests&lt;br /&gt;
 import sys&lt;br /&gt;
 &lt;br /&gt;
 ### EDIT THESE: Configuration values ###&lt;br /&gt;
 &lt;br /&gt;
 # URL to acme-dns instance&lt;br /&gt;
 ACMEDNS_URL = &amp;quot;&amp;lt;nowiki&amp;gt;https://auth.acme-dns.io&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
 # Path for acme-dns credential storage&lt;br /&gt;
 STORAGE_PATH = &amp;quot;/etc/letsencrypt/acmedns.json&amp;quot;&lt;br /&gt;
 # Whitelist for address ranges to allow the updates from&lt;br /&gt;
 # Example: ALLOW_FROM = [&amp;quot;192.168.10.0/24&amp;quot;, &amp;quot;::1/128&amp;quot;]&lt;br /&gt;
 ALLOW_FROM = []&lt;br /&gt;
 # Force re-registration. Overwrites the already existing acme-dns accounts.&lt;br /&gt;
 FORCE_REGISTER = False&lt;br /&gt;
 &lt;br /&gt;
 ###   DO NOT EDIT BELOW THIS POINT   ###&lt;br /&gt;
 ###         HERE BE DRAGONS          ###&lt;br /&gt;
 &lt;br /&gt;
 DOMAIN = os.environ[&amp;quot;CERTBOT_DOMAIN&amp;quot;]&lt;br /&gt;
 if DOMAIN.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
     DOMAIN = DOMAIN[2:]&lt;br /&gt;
 VALIDATION_DOMAIN = &amp;quot;_acme-challenge.&amp;quot;+DOMAIN&lt;br /&gt;
 VALIDATION_TOKEN = os.environ[&amp;quot;CERTBOT_VALIDATION&amp;quot;]&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 class AcmeDnsClient(object):&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
     Handles the communication with ACME-DNS API&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
     def __init__(self, acmedns_url):&lt;br /&gt;
         self.acmedns_url = acmedns_url&lt;br /&gt;
 &lt;br /&gt;
     def register_account(self, allowfrom):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Registers a new ACME-DNS account&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
         if allowfrom:&lt;br /&gt;
             # Include whitelisted networks to the registration call&lt;br /&gt;
             reg_data = {&amp;quot;allowfrom&amp;quot;: allowfrom}&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;,&lt;br /&gt;
                                 data=json.dumps(reg_data))&lt;br /&gt;
         else:&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;)&lt;br /&gt;
         if res.status_code == 201:&lt;br /&gt;
             # The request was successful&lt;br /&gt;
             return res.json()&lt;br /&gt;
         else:&lt;br /&gt;
             # Encountered an error&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to register a new acme-dns &amp;quot;&lt;br /&gt;
                    &amp;quot;account. HTTP status {}, Response body: {}&amp;quot;)&lt;br /&gt;
             print(msg.format(res.status_code, res.text))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def update_txt_record(self, account, txt):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Updates the TXT challenge record to ACME-DNS subdomain.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         update = {&amp;quot;subdomain&amp;quot;: account['subdomain'], &amp;quot;txt&amp;quot;: txt}&lt;br /&gt;
         headers = {&amp;quot;X-Api-User&amp;quot;: account['username'],&lt;br /&gt;
                    &amp;quot;X-Api-Key&amp;quot;: account['password'],&lt;br /&gt;
                    &amp;quot;Content-Type&amp;quot;: &amp;quot;application/json&amp;quot;}&lt;br /&gt;
         res = requests.post(self.acmedns_url+&amp;quot;/update&amp;quot;,&lt;br /&gt;
                             headers=headers,&lt;br /&gt;
                             data=json.dumps(update))&lt;br /&gt;
         if res.status_code == 200:&lt;br /&gt;
             # Successful update&lt;br /&gt;
             return&lt;br /&gt;
         else:&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to update TXT record in &amp;quot;&lt;br /&gt;
                    &amp;quot;acme-dns. \n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request headers:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request body:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response HTTP status: {}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response body: {}&amp;quot;)&lt;br /&gt;
             s_headers = json.dumps(headers, indent=2, sort_keys=True)&lt;br /&gt;
             s_update = json.dumps(update, indent=2, sort_keys=True)&lt;br /&gt;
             s_body = json.dumps(res.json(), indent=2, sort_keys=True)&lt;br /&gt;
             print(msg.format(s_headers, s_update, res.status_code, s_body))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
 class Storage(object):&lt;br /&gt;
     def __init__(self, storagepath):&lt;br /&gt;
         self.storagepath = storagepath&lt;br /&gt;
         self._data = self.load()&lt;br /&gt;
 &lt;br /&gt;
     def load(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Reads the storage content from the disk to a dict structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         data = dict()&lt;br /&gt;
         filedata = &amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             with open(self.storagepath, 'r') as fh:&lt;br /&gt;
                 filedata = fh.read()&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             if os.path.isfile(self.storagepath):&lt;br /&gt;
                 # Only error out if file exists, but cannot be read&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage file exists but cannot be read&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         try:&lt;br /&gt;
             data = json.loads(filedata)&lt;br /&gt;
         except ValueError:&lt;br /&gt;
             if len(filedata) &amp;gt; 0:&lt;br /&gt;
                 # Storage file is corrupted&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage JSON is corrupted&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         return data&lt;br /&gt;
 &lt;br /&gt;
     def save(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Saves the storage content to disk&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         serialized = json.dumps(self._data)&lt;br /&gt;
         try:&lt;br /&gt;
             with os.fdopen(os.open(self.storagepath,&lt;br /&gt;
                                    os.O_WRONLY | os.O_CREAT, 0o600), 'w') as fh:&lt;br /&gt;
                 fh.truncate()&lt;br /&gt;
                 fh.write(serialized)&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             print(&amp;quot;ERROR: Could not write storage file.&amp;quot;)&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def put(self, key, value):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Puts the configuration value to storage and sanitize it&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         # If wildcard domain, remove the wildcard part as this will use the&lt;br /&gt;
         # same validation record name as the base domain&lt;br /&gt;
         if key.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
             key = key[2:]&lt;br /&gt;
         self._data[key] = value&lt;br /&gt;
 &lt;br /&gt;
     def fetch(self, key):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Gets configuration value from storage&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             return self._data[key]&lt;br /&gt;
         except KeyError:&lt;br /&gt;
             return None&lt;br /&gt;
 &lt;br /&gt;
 if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
     # Init&lt;br /&gt;
     client = AcmeDnsClient(ACMEDNS_URL)&lt;br /&gt;
     storage = Storage(STORAGE_PATH)&lt;br /&gt;
 &lt;br /&gt;
     # Check if an account already exists in storage&lt;br /&gt;
     account = storage.fetch(DOMAIN)&lt;br /&gt;
     if FORCE_REGISTER or not account:&lt;br /&gt;
         # Create and save the new account&lt;br /&gt;
         account = client.register_account(ALLOW_FROM)&lt;br /&gt;
         storage.put(DOMAIN, account)&lt;br /&gt;
         storage.save()&lt;br /&gt;
 &lt;br /&gt;
         # Display the notification for the user to update the main zone&lt;br /&gt;
         msg = &amp;quot;Please add the following CNAME record to your main DNS zone:\n{}&amp;quot;&lt;br /&gt;
         cname = &amp;quot;{} CNAME {}.&amp;quot;.format(VALIDATION_DOMAIN, account[&amp;quot;fulldomain&amp;quot;])&lt;br /&gt;
         print(msg.format(cname))&lt;br /&gt;
 &lt;br /&gt;
     # Update the TXT record in acme-dns instance&lt;br /&gt;
     client.update_txt_record(account, VALIDATION_TOKEN)&lt;br /&gt;
&lt;br /&gt;
 # chmod +x /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
Usaremos a seguinte instrução para criar nosso certificado:&lt;br /&gt;
 # certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d doh.brasilpeeringforum.org&lt;br /&gt;
 Saving debug log to /var/log/letsencrypt/letsencrypt.log&lt;br /&gt;
 Plugins selected: Authenticator manual, Installer None&lt;br /&gt;
 Cert is due for renewal, auto-renewing...&lt;br /&gt;
 Renewing an existing certificate for doh.brasilpeeringforum.org&lt;br /&gt;
 Performing the following challenges:&lt;br /&gt;
 dns-01 challenge for doh.brasilpeeringforum.org&lt;br /&gt;
 Running manual-auth-hook command: /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
 Output from manual-auth-hook command acme-dns-auth.py:&lt;br /&gt;
 Please add the following CNAME record to your main DNS zone:&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
 &lt;br /&gt;
 Waiting for verification...&lt;br /&gt;
 &lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Challenges loaded. Press continue to submit to CA. Pass &amp;quot;-v&amp;quot; for more info about&lt;br /&gt;
 challenges.&lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Press Enter to Continue&lt;br /&gt;
Nesse momento você cria o registro '''CNAME''' no seu DNS Autoritativo conforme ele solicitou: '''_acme-challenge.doh.brasilpeeringforum.org IN CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.''' e somente depois de criado e checado no DNS, você pressiona o '''Enter''' para continuar. Você pode checar dessa forma:&lt;br /&gt;
 # host -t cname _acme-challenge.doh.brasilpeeringforum.org&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org is an alias for b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
Para que nosso certificado seja automaticamente renovado colocaremos no '''/etc/crontab''' a seguinte linha abaixo:&lt;br /&gt;
 00 00   1 * *   root    /usr/bin/certbot -q renew --deploy-hook &amp;quot;/usr/sbin/unbound-control reload_keep_cache&amp;quot;&lt;br /&gt;
Acima temos a instrução para renovação automática do certificado. Repare que você vai precisar também copiar esse certificado para seus outros servidores, escolha um servidor para manter o certificado sempre atualizado e crie um script que faça a mesma cópia remotamente para os outros servidores. O '''scp''' e o '''rsync''' são seus aliados nisso.&lt;br /&gt;
&lt;br /&gt;
=== Configurando o Unbound ===&lt;br /&gt;
Em nosso '''/etc/unbound/unbound.conf.d/local.conf''', adicionaremos no bloco &amp;quot;'''server:'''&amp;quot; o seguinte:&lt;br /&gt;
 interface: 10.10.10.10@443 &lt;br /&gt;
 interface: 10.10.9.9@443&lt;br /&gt;
 interface: fd00::10:10:10:10@443&lt;br /&gt;
 interface: fd00::10:10:9:9@443&lt;br /&gt;
 tls-service-key: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/privkey.pem&amp;quot; &lt;br /&gt;
 tls-service-pem: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/fullchain.pem&amp;quot;&lt;br /&gt;
Para usar o recurso do '''DoH''' você precisará habilitar o recurso no seu navegador e informar a URL. Vou colocar o exemplo do '''Google Chrome''': Digite '''chrome://settings/security?search=dns''' no seu Chrome e ative '''Usar DNS seguro''', selecione '''Personalizado''' e adicione nossa URL:&lt;br /&gt;
[[Arquivo:Doh bpf2.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Finalizando ==&lt;br /&gt;
Aqui finalizamos nosso projeto para uma Rede de DNS(s) Recursivos Anycast com Hyperlocal. Esse projeto é escalável, seguro, resiliente e você entregará muito mais qualidade de Internet para o seu cliente. Pare de entregar o '''8.8.8.8''' para os seus clientes, você está contribuindo para uma Internet mais lenta, sem a qualidade que o seu cliente merece. Investi meu tempo, que é muito pouco, para deixar esse documento para a comunidade, para você melhorar o seu ISP, para dar um UP! nele, então vamos começar 2023 com o pé direito. O que acha?&lt;br /&gt;
&lt;br /&gt;
Como prova de conceito, uma imagem abaixo onde temos uma Rede em produção de DNS(s) Recursivos Anycast e apontando exatamente o momento em que houve alguma situação que fez com que as queries de DNS, convergissem de um node para outro, de forma transparente e automática para o cliente. Podemos notar também que ao ser resolvido o problema, o tráfego retornou para o seu node correto:&lt;br /&gt;
[[Arquivo:Convergencia.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== KINDNS (Stands for Knowledge-Sharing and Instantiating Norms for DNS and Naming Security) ==&lt;br /&gt;
Achou que havia terminado? Agora que você tem a capacidade de montar uma '''Rede de DNS Recursivo''' com todas essas features acima, com todas as ferramentas que foram comentadas, o que acha de certificar o que fez?&lt;br /&gt;
&lt;br /&gt;
Assim como o [https://www.manrs.org/ MANRS] veio para certificar nosso sistema de roteamento na Internet, agora temos o [https://kindns.org/ KINDNS] para certificar que nossos sistemas de DNS estão bem feitos e dentro dos padrões de segurança. Existem '''7 ações''' que podem ser certificadas para nossos DNS Recursivos e estão aqui em https://kindns.org/shared-private-resolvers/. Com essa nossa documentação, se bem aplicada, você pode se candidatar ao KINDNS e ter seu ASN listado aqui https://kindns.org/participants/&lt;br /&gt;
&lt;br /&gt;
Obter e manter o '''MANRS''' e '''KINDNS''' demonstra seu compromisso com as Boas Práticas, contribui para termos uma '''Internet''' mais segura e te abre portas para novos negócios que possam exigir essas conformidades.&lt;br /&gt;
&lt;br /&gt;
Autor: [[Usuário:Gondim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Infraestrutura]]&lt;br /&gt;
__FORCARTDC__&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3985</id>
		<title>DNS Recursivo Anycast Hyperlocal</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3985"/>
		<updated>2025-11-24T14:44:13Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
==Introdução==&lt;br /&gt;
Você sabe como funciona a Internet? Essa é uma pergunta que meu amigo '''Thiago Ayub''' sempre faz aos seus candidatos à vagas de emprego e não importa o quanto tenham de experiência em '''Engenharia de Redes''', todos sempre travam nesse momento. Todos estão sempre prontos e preparados para resolver os problemas mais cabeludos em '''BGP''', '''OSPF''', '''MPLS''', etc mas travam com essa simples pergunta. Para contextualizar e visualizarmos melhor vamos nos atentar à imagem abaixo e uma explicação simplificada de como funciona:&lt;br /&gt;
[[Arquivo:Dns hierarquia.png|esquerda|commoldura]]&lt;br /&gt;
Tudo começa com um usuário sentado confortavelmente e querendo acessar um conteúdo disponível na Internet. Ele digita em seu navegador preferido a URL: '''&amp;lt;nowiki&amp;gt;https://wiki.brasilpeeringforum.org&amp;lt;/nowiki&amp;gt;''',&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;1)&amp;lt;/big&amp;gt;''' &amp;lt;big&amp;gt;O&amp;lt;/big&amp;gt; &amp;lt;big&amp;gt;navegador irá requisitar do '''DNS Recursivo''' utilizado pelo usuário, o '''endereço IP''' que responde pelo nome '''wiki.'''&amp;lt;/big&amp;gt;'''brasilpeeringforum.org'''&amp;lt;big&amp;gt;. Isso porque todos os acessos se dão na Internet através do '''endereço''' '''IP''' e não através do '''nome'''. Imaginem se tivéssemos que decorar os endereços IPs de todos os sites e serviços que quiséssemos acessar na Internet?&amp;lt;/big&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;big&amp;gt;'''2)''' Nosso DNS Recursivo checa se a informação consta em seu cache.&amp;lt;/big&amp;gt; Se a informação existir ela é devolvida ao navegador do usuário e aí este consegue acessar o site.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Do contrário o DNS Recursivo pergunta ao '''Root Server''' quem é o '''TLD (Top Level Domain)''' responsável para atender a requisição. &lt;br /&gt;
&lt;br /&gt;
'''4)''' O '''Root Server''' informa ao DNS Recursivo o endereço do '''TLD responsável'''. No Brasil o '''TLD''' responsável pelo '''.br''' seria o '''Registro.br'''.&lt;br /&gt;
&lt;br /&gt;
'''5)''' O DNS Recursivo pergunta ao '''TLD''' sobre '''wiki.brasilpeeringforum.org''' e este responde com os endereços IP dos '''DNS Autoritativos''' responsáveis pelo domínio '''brasilpeeringforum.org.'''&lt;br /&gt;
&lt;br /&gt;
'''6)''' O DNS Recursivo pergunta aos '''DNS Autoritativos''' pelo '''wiki.brasilpeeringforum.org''' e este responde com o '''endereço IP'''.&lt;br /&gt;
&lt;br /&gt;
'''7)''' Por último o DNS Recursivo devolve a informação para o navegador do usuário.&lt;br /&gt;
&lt;br /&gt;
Como que se dá a comunicação entre os '''DNS(s) Recursivos, Root Servers, TLDs''' e '''Autoritativos'''? Como que o navegador do usuário, após receber o IP do site, consegue chegar no servidor que tem o conteúdo? Isso só é possível devido ao protocolo chamado '''BGP (Border Gateway Protocol)''', todos os caminhos que conhecemos como rotas de destino, são anunciadas por milhares de participantes na '''Internet''' conhecidos como '''AS (Autonomous System)''', esses participantes se interligam para disponibilizar conteúdos e acessos pelo mundo aos milhares de usuários. É uma imensa rede colaborativa formada por Empresas, Universidades, Governos e todos que queiram se interconectar. Percebam que sem o '''BGP''', que serve de caminho para chegarmos nos conteúdos e sem o '''DNS (Domain Name System)''' para traduzir o nome para o endereço IP, a '''Internet''' não funcionaria e por isso precisamos cuidar muito bem desses dois serviços.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Mas não acaba por aí. O '''DNS Recursivo''' tem um papel muito importante para o Provedor de Internet e que envolve segurança, qualidade de acesso à Internet e a disponibilidade do serviço entregue ao cliente. Quando bem configurado acelera as consultas dos acessos graças ao seu cache interno, mas para que isso seja percebido pelo assinante, é necessário que esteja o mais próximo possível do seu cliente.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Um erro que destrói a qualidade do nosso serviço ==&lt;br /&gt;
Um erro muito comum que muitas operadoras cometem é utilizar DNS Recursivo externo, como o '''8.8.8.8''', '''1.1.1.1''' e outros, para seus clientes. Quanto mais próximo dos seus clientes, mais qualidade de serviço estará entregando a eles. Conteúdos serão entregues mais rapidamente pois serão resolvidos e armazenados em caches locais e não consultados remotamente na Internet. Para falar mais sobre isso, te convido leitor desse documento, que assista essa palestra do '''Thiago Ayub''' no '''GTER 51/GTS 37''' (2022) '''8.888 MOTIVOS PARA NÃO USAR DNS RECURSIVO EXTERNO EM SEU AS''': https://www.youtube.com/watch?v=Rsvpu5uF2Io&lt;br /&gt;
&lt;br /&gt;
== Objetivo ==&lt;br /&gt;
O objetivo desta documentação não é te ensinar tudo sobre '''DNS''', '''BGP''', '''OSPF''' e nem tão pouco sobre GNU/Linux e sim te mostrar um exemplo de servidor DNS Recursivo implementado pensando em segurança, qualidade e resiliência. Usaremos em todas as nossas documentações o [https://www.debian.org/ Debian GNU/Linux], por ser uma distribuição que considero uma obra de arte criada por uma enorme comunidade séria, com vasta experiência de anos, qualidade no empacotamento dos programas, estável e com uma equipe de segurança excelente e ativa. Caso você leitor, utilize alguma outra distribuição GNU/Linux, todo conteúdo apresentado aqui pode ser aplicado em outras distros, desde que respeitando as particularidades de cada uma.&lt;br /&gt;
&lt;br /&gt;
Aqui construiremos um sistema do tipo '''Anycast''', ou seja, terás o serviço rodando em diversas localidades da sua Rede utilizando o mesmo endereçamento IP e que atenderá seu cliente mais próximo. Em caso de falhas, seus clientes automaticamente e de forma transparente continuarão consultando o DNS mais próximo deles. Para que ele funcione dessa forma você precisará ter uma '''Rede OSPF''' implementada no seu Provedor Internet ou algum outro protocolo como por exemplo o '''ISIS,''' mas esse documento não irá abordar o '''ISIS'''. Também utilizaremos o '''Hyperlocal''' como recurso adicional para gerar algumas proteções de segurança e velocidade na resposta relacionada aos servidores de DNS Raiz da Internet.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
Para exemplificar nosso servidor de DNS Recursivo, usaremos como base das explicações um diagrama demonstrando o uso do DNS Recursivo em uma Rede fictícia. Adotaremos IPs privados e reservados para demonstrar todo o ambiente do Provedor de Internet.&lt;br /&gt;
[[Arquivo:Recursivo99.png|esquerda|miniaturadaimagem|695x695px]]&lt;br /&gt;
Nesse diagrama podemos observar alguns detalhes técnicos como por exemplo: existem '''3 servidores de DNS Recursivo''' posicionados em locais diferentes, que poderiam estar em bairros diferentes e até em cidades diferentes. Em cada servidor teremos '''2 loopbacks''' com os IPs:&lt;br /&gt;
&lt;br /&gt;
'''10.10.10.10/32 - fd00::10:10:10:10/128'''&lt;br /&gt;
&lt;br /&gt;
'''10.10.9.9/32 - fd00::10:10:9:9/128'''&lt;br /&gt;
&lt;br /&gt;
Esses IPs serão entregues pelos concentradores '''PPPoE''' ou '''IPoE''' ('''BNG''') para seus clientes como '''DNS primário''' e '''secundário'''. Podemos usar IPs privados como DNS primário e secundário em um ambiente real? Sim podemos, desde que não sejam IPs que possam ter problemas com as redes privadas dos clientes. Ex.: rede do cliente usando '''192.168.0.0/24'''. Se entregarmos o DNS sendo '''192.168.0.10''' e '''192.168.0.20''' teremos problemas e o cliente ficará sem Internet, porque '''192.168.0.10''' e '''192.168.0.20''' fazem parte da rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
Agora entregando '''10.10.10.10,''' '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9''' não teríamos problemas com a rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
'''Motivos para usarmos IPs privados:'''&lt;br /&gt;
* O principal motivo está relacionado com a segurança, uma vez que sendo um IP privado, não pode sofrer ataques DDoS direcionados diretamente para ele, vindos da Internet.&lt;br /&gt;
* Nem mesmo o cliente da sua rede conhece os '''IPs públicos''' utilizados para recursividade na Internet.&lt;br /&gt;
* Memorizar os IPs '''10.10.10.10''' e '''10.10.9.9''' é tão fácil quanto memorizar o '''8.8.8.8''' e o '''1.1.1.1'''. Mais fácil para o seu técnico guardar essa informação e utilizar onde for necessário.&lt;br /&gt;
Cada servidor DNS Recursivo possui um '''IPv4 público''', aqui representado por '''198.18.x.x/27''' e um '''IPv6 global''' representado por um IP dentro do prefixo '''2001:db8::/32'''. Cada servidor precisa ter os seus próprios IPs e são através destes IPs que as consultas de DNS serão realizadas na Internet.&lt;br /&gt;
&lt;br /&gt;
Nessa topologia usando '''Anycast''', o cliente será sempre atendido pelo '''DNS Recursivo''' mais próximo, desde que os pesos no '''OSPF''' estejam ajustados corretamente.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
== Dados do servidor ==&lt;br /&gt;
Podemos utilizar um sistema virtualizado ou não. Sistemas virtualizados são bem vindos pois são mais simples quando precisamos fazer backups, levantar outros sistemas sem complicações e se precisarmos restaurar rapidamente algum sistema que ficou indisponível por algum motivo. A configuração abaixo tem capacidade para atender algo em torno a '''50.000 assinantes ou mais'''. O DNS Recursivo é um serviço que pode ser utilizado até mesmo em um '''Raspberry Pi''' e atender operações pequenas, nesse caso com o intuito de economizar energia e espaço. Nosso foco aqui é montar uma rede de '''DNS Recursivo Anycast com HyperLocal'''. Como comentei acima o servidor deve ficar o mais próximo dos clientes para termos a '''menor latência possível''' e '''sempre menor que 5ms''' entre o cliente e o servidor.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!CPU&lt;br /&gt;
!Memória&lt;br /&gt;
!Disco&lt;br /&gt;
!Sistema&lt;br /&gt;
|-&lt;br /&gt;
|2.4Ghz 8 cores&lt;br /&gt;
|16G DDR4&lt;br /&gt;
|30G&lt;br /&gt;
|Debian 13 amd64 (Trixie)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Softwares utilizados ==&lt;br /&gt;
* Debian 13 amd64 (Trixie) instalação mínima.&lt;br /&gt;
&lt;br /&gt;
* [https://frrouting.org/ FRRouting].&lt;br /&gt;
* Unbound.&lt;br /&gt;
* Chrony (NTP/NTS).&lt;br /&gt;
* Shell script em bash.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades que teremos ==&lt;br /&gt;
* Sistema em Anycast.&lt;br /&gt;
* Hyperlocal.&lt;br /&gt;
* Controle de acesso por &amp;lt;abbr&amp;gt;ACL&amp;lt;/abbr&amp;gt;.&lt;br /&gt;
* RPZ (Response Policy Zone).&lt;br /&gt;
* Bloqueio de consultas do tipo ANY.&lt;br /&gt;
* QNAME minimization habilitado. (habilitado por default no Unbound)&lt;br /&gt;
* Recursividade em IPv4 e IPv6.&lt;br /&gt;
* DNSSEC habilitado.&lt;br /&gt;
* &amp;lt;abbr&amp;gt;DoH (DNS&amp;lt;/abbr&amp;gt; over HTTPS) habilitado.&lt;br /&gt;
&lt;br /&gt;
== Monitoramento ==&lt;br /&gt;
O monitoramento é algo bem específico e não é o foco deste documento mas é extremamente importante que você monitore seus servidores de DNS por alguma ferramenta como o Zabbix. Aqui mostrarei apenas como enviar as informações para o Zabbix. Algumas coisas que você deveria monitorar nos servidores de DNS Recursivo:&lt;br /&gt;
* Serviço do unbound parou.&lt;br /&gt;
* Perda de pacotes.&lt;br /&gt;
* Latência alta de pacotes.&lt;br /&gt;
* Lentidão na resolução de queries.&lt;br /&gt;
* CPU alta.&lt;br /&gt;
* Load alto.&lt;br /&gt;
* Memória com uso alto.&lt;br /&gt;
* Disco com pouco espaço.&lt;br /&gt;
* Queda brusca nas queries.&lt;br /&gt;
* A recursividade parou de funcionar.&lt;br /&gt;
* A recursividade voltou a funcionar.&lt;br /&gt;
Este abaixo é um exemplo de monitoramento de um sistema de DNS Recursivo que atende 50.000 assinantes:&lt;br /&gt;
[[Arquivo:Grafana dns.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Configurando a Rede ==&lt;br /&gt;
Nossa documentação será baseada no diagrama apresentado acima e por isso configuraremos apenas um dos três servidores, porque os outros serão configurados da mesma forma, só que com dados diferentes. Para tanto assumirei que já temos um sistema Debian instalado com o mínimo de pacotes e somente com sshd, para que possamos acessar remotamente mais tarde. '''Não instale um ambiente gráfico no servidor''', você não deve querer fazer isso por diversos motivos e os principais: primeiro porque não é um Desktop e segundo porque o ambiente gráfico devoraria toda a memória com recursos que não seriam úteis aqui.&lt;br /&gt;
&lt;br /&gt;
Em '''/etc/network/interfaces''' deixaremos assim:&lt;br /&gt;
 # This file describes the network interfaces available on your system&lt;br /&gt;
 # and how to activate them. For more information, see interfaces(5).&lt;br /&gt;
  &lt;br /&gt;
 source /etc/network/interfaces.d/*&lt;br /&gt;
  &lt;br /&gt;
 # The loopback network interface&lt;br /&gt;
 auto lo&lt;br /&gt;
 iface lo inet loopback&lt;br /&gt;
  &lt;br /&gt;
 auto lo:0&lt;br /&gt;
 iface lo:0 inet static&lt;br /&gt;
       address 10.10.10.10/32&lt;br /&gt;
  &lt;br /&gt;
 auto lo:1&lt;br /&gt;
 iface lo:1 inet static&lt;br /&gt;
       address 10.10.9.9/32&lt;br /&gt;
 &lt;br /&gt;
 auto lo:2&lt;br /&gt;
 iface lo:2 inet6 static&lt;br /&gt;
       address fd00::10:10:10:10/128&lt;br /&gt;
 &lt;br /&gt;
 auto lo:3&lt;br /&gt;
 iface lo:3 inet6 static&lt;br /&gt;
       address fd00::10:10:9:9/128&lt;br /&gt;
  &lt;br /&gt;
 # The primary network interface&lt;br /&gt;
 auto ens18&lt;br /&gt;
 iface ens18 inet static&lt;br /&gt;
         address 198.18.1.10/27&lt;br /&gt;
         gateway 198.18.1.1&lt;br /&gt;
  &lt;br /&gt;
 iface ens18 inet6 static&lt;br /&gt;
         address 2001:db8::faca:198:18:1:10/64&lt;br /&gt;
         gateway 2001:db8::faca:198:18:1:1&lt;br /&gt;
  &lt;br /&gt;
 # The secondary network interface&lt;br /&gt;
 auto ens18:0&lt;br /&gt;
 iface ens18:0 inet static&lt;br /&gt;
         address 172.16.0.6/30&lt;br /&gt;
Nesse cenário temos as duas '''loopbacks''' com os IPs '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10''' e '''fd00::10:10:9:9''' que serão anunciados via OSPF para a rede e serem entregues aos clientes via BNG. Os IPs '''198.18.1.10''' e '''2001:db8::faca:198:18:1:10''' serão usados para fazerem a recursividade na Internet tanto em IPv4 quanto em IPv6. Esses IPs não devem ser divulgados para clientes; os IPs públicos são dedicados apenas para essa finalidade.&lt;br /&gt;
&lt;br /&gt;
== Configuração dos repositórios Debian ==&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://security.debian.org/debian-security/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-security&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-updates&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian-backports.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-backports&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
&lt;br /&gt;
 # rm /etc/apt/sources.list&lt;br /&gt;
Após a configuração vamos instalar alguns pacotes necessários e outros úteis:&lt;br /&gt;
 # apt update &amp;amp;&amp;amp; apt full-upgrade&lt;br /&gt;
 # apt install net-tools nftables htop iotop sipcalc tcpdump curl gnupg rsync wget host dnsutils mtr-tiny bmon sudo tmux whois ethtool dnstop&lt;br /&gt;
&lt;br /&gt;
== Fazendo algum tuning no sistema ==&lt;br /&gt;
Em '''/etc/sysctl.d/100-tuning.conf''' adicionamos essas instruções:&lt;br /&gt;
 net.core.rmem_max = 2147483647&lt;br /&gt;
 net.core.wmem_max = 2147483647&lt;br /&gt;
 net.ipv4.tcp_rmem = 4096 87380 2147483647&lt;br /&gt;
 net.ipv4.tcp_wmem = 4096 65536 2147483647&lt;br /&gt;
 net.netfilter.nf_conntrack_buckets = 512000&lt;br /&gt;
 net.netfilter.nf_conntrack_max = 4096000&lt;br /&gt;
 vm.swappiness=10&lt;br /&gt;
Estamos fazendo algumas melhorias de memória, algumas relacionadas a '''conntrack''' porque se for usar um filtro de pacotes stateful, como o '''Netfilter/IPTables''' ou '''Netfilter/NFTables''', o valor default da tabela é pequeno e dependendo da situação, se estourar essa tabela, as consultas de DNS terão problemas também. O DNS Recursivo não deve ficar aberto para qualquer um na Internet, ele deve ser liberado apenas para seus clientes. Podemos fazer através das ACLs do Unbound e pelo filtro de pacotes. O último parâmetro diz respeito ao uso de swap, por padrão o Debian permite o uso de swap após 40% do uso da memória, nesse caso estamos dizendo para o sistema usar o swap com 90% de uso da memória.&lt;br /&gt;
&lt;br /&gt;
Precisamos adicionar o módulo '''nf_conntrack''' em '''/etc/modules''' para que seja carregado em tempo de boot, senão os parâmetros de '''conntrack''' que colocamos em '''/etc/sysctl.conf''' não serão carregados.&lt;br /&gt;
 # echo nf_conntrack &amp;gt;&amp;gt; /etc/modules&lt;br /&gt;
 # modprobe nf_conntrack&lt;br /&gt;
 # sysctl -p&lt;br /&gt;
&lt;br /&gt;
== Instalando o FRRouting ==&lt;br /&gt;
O FRRouting é o programa que usaremos para fazer os anúncios das nossas loopbacks via OSPF. Nesse documento usaremos a versão 10.x:&lt;br /&gt;
 # apt install frr frr-doc frr-pythontools&lt;br /&gt;
Aconselho depois de instalar os pacotes, marcá-los para não atualizar juntamente com os demais pacotes, isso é para evitar de ocorrer alguma atualização no FRRouting, que torne o serviço instável por algum motivo. Não que isso vá ocorrer, mas é melhor fazer essa atualização quando realmente for necessário.&lt;br /&gt;
 # apt-mark hold frr frr-doc frr-pythontools&lt;br /&gt;
Após esse comando acima, o sistema manterá a instalação original do pacote intacta. Para desbloquear basta executar o comando abaixo:&lt;br /&gt;
 # apt-mark unhold frr frr-doc frr-pythontools&lt;br /&gt;
&lt;br /&gt;
== Removendo o APPARMOR ==&lt;br /&gt;
O '''APPARMOR''' às vezes causa mais problemas que solução e se não for fazer uma completa configuração nele, é melhor desabilitá-lo. Para fazer isso efetivamente, o procedimento é esse abaixo:&lt;br /&gt;
 # mkdir -p /etc/default/grub.d&lt;br /&gt;
 # echo 'GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;$GRUB_CMDLINE_LINUX_DEFAULT apparmor=0&amp;quot;' | tee /etc/default/grub.d/apparmor.cfg&lt;br /&gt;
 # update-grub&lt;br /&gt;
 # reboot&lt;br /&gt;
&lt;br /&gt;
== Instalando o Unbound ==&lt;br /&gt;
Nesse momento ainda não iremos configurar o Unbound, apenas instalar o pacote e acertar o ambiente. Vamos instalar o unbound do backports porque este já possui suporte ao DoH que veremos mais à frente.&lt;br /&gt;
 # apt install unbound dns-root-data&lt;br /&gt;
 # mkdir -p /var/log/unbound&lt;br /&gt;
 # touch /var/log/unbound/unbound.log&lt;br /&gt;
 # chown -R unbound:unbound /var/log/unbound/&lt;br /&gt;
 # systemctl restart unbound&lt;br /&gt;
Configurando o logrotate:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/logrotate.d/unbound&lt;br /&gt;
 /var/log/unbound/unbound.log {&lt;br /&gt;
     rotate 5&lt;br /&gt;
     weekly&lt;br /&gt;
     postrotate&lt;br /&gt;
         unbound-control log_reopen&lt;br /&gt;
     endscript&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
Reiniciando o serviço:&lt;br /&gt;
 # systemctl restart logrotate.service&lt;br /&gt;
&lt;br /&gt;
== Ajustando THP (Transparente Huge Pages) em arquitetura AMD64 ==&lt;br /&gt;
No Debian o '''THP''' vem habilitado como '''always''' e o '''unbound''' por trabalhar bastante com alterações do cache em memória, isso pode acabar causando um consumo crescente de uso de RAM sem necessidade. É uma boa prática ajustá-lo com os passos abaixo:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/systemd/system/ajusta-thp.service&lt;br /&gt;
 [Unit]&lt;br /&gt;
 Description=Ajusta Transparent Huge Pages (THP)&lt;br /&gt;
 After=network.target&lt;br /&gt;
 &lt;br /&gt;
 [Service]&lt;br /&gt;
 Type=oneshot&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo madvise &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled&amp;quot;&lt;br /&gt;
 RemainAfterExit=yes&lt;br /&gt;
 &lt;br /&gt;
 [Install]&lt;br /&gt;
 WantedBy=multi-user.target&lt;br /&gt;
 EOF&lt;br /&gt;
Acima configuramos o serviço '''ajusta-thp.service''' para ajustar o '''THP''' e abaixo habilitamos no '''systemd''' e iniciamos:&lt;br /&gt;
 # systemctl daemon-reload&lt;br /&gt;
 # systemctl enable --now ajusta-thp&lt;br /&gt;
&lt;br /&gt;
== Preparando o monitoramento do seu DNS Recursivo ==&lt;br /&gt;
O monitoramento do seu DNS Recursivo é muito importante e para isso vamos usar um '''template para Zabbix''', que modifiquei juntamente com o seu shell script e que enviará os dados para o seu Zabbix server via '''zabbix-sender'''. O projeto original está aqui '''https://github.com/jeftedelima/Unbound-DNS&amp;lt;nowiki/&amp;gt;.''' O xml alterado está aqui '''https://github.com/gondimcodes/template_zabbix_dns_unbound'''. Embora seja antigo é perfeitamente importável no Zabbix 6.0, por exemplo.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;nowiki/&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Teremos um shell script que você precisará colocar no seu '''/etc/crontab'''. No exemplo abaixo assumi que o shell script está em '''/root/scripts'''. De 5 em 5 minutos os dados serão enviados para o seu Zabbix server.&lt;br /&gt;
 */5 * * * *     root    /root/scripts/unboundSend.sh '''IP_zabbix_server''' '''nome_do_host''' 1&amp;gt; /dev/null&lt;br /&gt;
Na linha acima, troque o '''IP_zabbix_server''' pelo '''IP do seu servidor Zabbix''' e o '''nome_do_host''' pelo '''hostname''' '''do seu DNS Recursivo'''. Você precisará instalar o pacote '''zabbix-sender''' no seu DNS Recursivo pois ele será usado para enviar os dados para o Zabbix server.&lt;br /&gt;
&lt;br /&gt;
Abaixo o '''unboundSend.sh''' também alterado com inclusão de mais dados:&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 #       @Jefte de Lima Ferreira&lt;br /&gt;
 #       jeftedelima at gmail dot com&lt;br /&gt;
 #       CRON Example&lt;br /&gt;
 #       Contributor: Marcelo Gondim - gondim at gmail dot com&lt;br /&gt;
 #       */5   **** root sh /home/dir/unboundSend.sh 192.168.10.1 Unbound 1&amp;gt; /dev/null&lt;br /&gt;
  &lt;br /&gt;
 if [ -z ${1} ] || [ -z ${2} ] ; then&lt;br /&gt;
         echo &amp;quot;You need to specify the IP address of zabbix server and hostname of your DNS Unbound on zabbix&amp;quot;&lt;br /&gt;
         echo &amp;quot;Usage example: ./unboundSend.sh 192.168.10.1 UnboundServer&amp;quot;&lt;br /&gt;
         exit 1&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 # ZABBIX_SERVER IP&lt;br /&gt;
 IP_ZABBIX=$1&lt;br /&gt;
 # NAME Unbound on Zabbix&lt;br /&gt;
 NAME_HOST=$2&lt;br /&gt;
 DIR_TEMP=/var/tmp/&lt;br /&gt;
 FILE=&amp;quot;${DIR_TEMP}dump_unbound_control_stats.txt&amp;quot;&lt;br /&gt;
 unbound-control stats &amp;gt; ${FILE}&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_NUM_QUERIES=$(cat ${FILE} | grep -w 'total.num.queries' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEHITS=$(cat ${FILE} | grep -w 'total.num.cachehits' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEMISS=$(cat ${FILE} | grep -w 'total.num.cachemiss' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_PREFETCH=$(cat ${FILE} | grep -w 'total.num.prefetch' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_RECURSIVEREPLIES=$(cat ${FILE} | grep -w 'total.num.recursivereplies' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_REQ_MAX=$(cat ${FILE} | grep -w 'total.requestlist.max' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_AVG=$(cat ${FILE} | grep -w 'total.requestlist.avg' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_OVERWRITTEN=$(cat ${FILE} | grep -w 'total.requestlist.overwritten' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_EXCEEDED=$(cat ${FILE} | grep -w 'total.requestlist.exceeded' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_ALL=$(cat ${FILE} | grep -w 'total.requestlist.current.all' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_USER=$(cat ${FILE} | grep -w 'total.requestlist.current.user' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_TCPUSAGE=$(cat ${FILE} | grep -w 'total.tcpusage' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_QUERY_TYPE_A=$(cat ${FILE} | grep -w 'num.query.type.A' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NS=$(cat ${FILE} | grep -w 'num.query.type.NS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_MX=$(cat ${FILE} | grep -w 'num.query.type.MX' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TXT=$(cat ${FILE} | grep -w 'num.query.type.TXT' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_PTR=$(cat ${FILE} | grep -w 'num.query.type.PTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_AAAA=$(cat ${FILE} | grep -w 'num.query.type.AAAA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SRV=$(cat ${FILE} | grep -w 'num.query.type.SRV' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SOA=$(cat ${FILE} | grep -w 'num.query.type.SOA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HTTPS=$(cat ${FILE} | grep -w 'num.query.type.HTTPS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TYPE0=$(cat ${FILE} | grep -w 'num.query.type.TYPE0' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_CNAME=$(cat ${FILE} | grep -w 'num.query.type.CNAME' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_WKS=$(cat ${FILE} | grep -w 'num.query.type.WKS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HINFO=$(cat ${FILE} | grep -w 'num.query.type.HINFO' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_X25=$(cat ${FILE} | grep -w 'num.query.type.X25' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NAPTR=$(cat ${FILE} | grep -w 'num.query.type.NAPTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DS=$(cat ${FILE} | grep -w 'num.query.type.DS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DNSKEY=$(cat ${FILE} | grep -w 'num.query.type.DNSKEY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TLSA=$(cat ${FILE} | grep -w 'num.query.type.TLSA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SVCB=$(cat ${FILE} | grep -w 'num.query.type.SVCB' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SPF=$(cat ${FILE} | grep -w 'num.query.type.SPF' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_ANY=$(cat ${FILE} | grep -w 'num.query.type.ANY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_OTHER=$(cat ${FILE} | grep -w 'num.query.type.other' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_ANSWER_RCODE_NOERROR=$(cat ${FILE} | grep -w 'num.answer.rcode.NOERROR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_NXDOMAIN=$(cat ${FILE} | grep -w 'num.answer.rcode.NXDOMAIN' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_SERVFAIL=$(cat ${FILE} | grep -w 'num.answer.rcode.SERVFAIL' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_REFUSED=$(cat ${FILE} | grep -w 'num.answer.rcode.REFUSED' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_nodata=$(cat ${FILE} | grep -w 'num.answer.rcode.nodata' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_secure=$(cat ${FILE} | grep -w 'num.answer.secure' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 #       Sending info to zabbix_server.&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.queries -o $(( ${TOTAL_NUM_QUERIES:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachehits -o $(( ${TOTAL_NUM_CACHEHITS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachemiss -o $(( ${TOTAL_NUM_CACHEMISS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.prefetch -o $(( ${TOTAL_NUM_PREFETCH:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.recursivereplies -o $(( ${TOTAL_NUM_RECURSIVEREPLIES:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.max -o $(( ${TOTAL_REQ_MAX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.avg -o $(( ${TOTAL_REQ_AVG:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.overwritten -o $(( ${TOTAL_REQ_OVERWRITTEN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.exceeded -o $(( ${TOTAL_REQ_EXCEEDED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.all -o $(( ${TOTAL_REQ_CURRENT_ALL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.user -o $(( ${TOTAL_REQ_CURRENT_USER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.tcpusage -o $(( ${TOTAL_TCPUSAGE:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.a -o $(( ${NUM_QUERY_TYPE_A:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ns -o $(( ${NUM_QUERY_TYPE_NS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.mx -o $(( ${NUM_QUERY_TYPE_MX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.txt -o $(( ${NUM_QUERY_TYPE_TXT:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ptr -o $(( ${NUM_QUERY_TYPE_PTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.aaaa -o $(( ${NUM_QUERY_TYPE_AAAA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.srv -o $(( ${NUM_QUERY_TYPE_SRV:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.soa -o $(( ${NUM_QUERY_TYPE_SOA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.https -o $(( ${NUM_QUERY_TYPE_HTTPS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.type0 -o $(( ${NUM_QUERY_TYPE_TYPE0:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.cname -o $(( ${NUM_QUERY_TYPE_CNAME:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.wks -o $(( ${NUM_QUERY_TYPE_WKS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.hinfo -o $(( ${NUM_QUERY_TYPE_HINFO:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.X25 -o $(( ${NUM_QUERY_TYPE_X25:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.naptr -o $(( ${NUM_QUERY_TYPE_NAPTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ds -o $(( ${NUM_QUERY_TYPE_DS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.dnskey -o $(( ${NUM_QUERY_TYPE_DNSKEY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.tlsa -o $(( ${NUM_QUERY_TYPE_TLSA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.svcb -o $(( ${NUM_QUERY_TYPE_SVCB:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.spf -o $(( ${NUM_QUERY_TYPE_SPF:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.any -o $(( ${NUM_QUERY_TYPE_ANY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.other -o $(( ${NUM_QUERY_TYPE_OTHER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NOERROR -o $(( ${NUM_ANSWER_RCODE_NOERROR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NXDOMAIN -o $(( ${NUM_ANSWER_RCODE_NXDOMAIN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.SERVFAIL -o $(( ${NUM_ANSWER_RCODE_SERVFAIL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.REFUSED -o $(( ${NUM_ANSWER_RCODE_REFUSED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.nodata -o $(( ${NUM_ANSWER_RCODE_nodata:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.secure -o $(( ${NUM_ANSWER_secure:-0} / 300 ))&lt;br /&gt;
No Zabbix será registrado dados como esses abaixo e posteriormente pode ser montado um Grafana com eles:&lt;br /&gt;
[[Arquivo:Zabbix dns01.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns02.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns03.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns04.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Mantendo a hora certa ==&lt;br /&gt;
Vamos instalar agora o Chrony para manter a data e hora certas no sistema:&lt;br /&gt;
 # apt install chrony&lt;br /&gt;
Após a instalação do Chrony edite o arquivo /etc/chrony/chrony.conf, comente e a linha abaixo e adicione seus servidores NTP. Caso não tenha servidores NTP, estou colocando os do NIC.br aqui.&lt;br /&gt;
 #pool 2.debian.pool.ntp.org iburst&lt;br /&gt;
 server a.st1.ntp.br iburst nts&lt;br /&gt;
 server b.st1.ntp.br iburst nts&lt;br /&gt;
 server c.st1.ntp.br iburst nts&lt;br /&gt;
 server d.st1.ntp.br iburst nts&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart chronyd.service&lt;br /&gt;
Cheque com o '''chronyc''' se os servidores estão OK:&lt;br /&gt;
 # chronyc sourcestats&lt;br /&gt;
 Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev&lt;br /&gt;
 ==============================================================================&lt;br /&gt;
 a.st1.ntp.br               10   5  155m     -0.027      0.030    -71us    51us&lt;br /&gt;
 b.st1.ntp.br               11   7  344m     +0.068      0.079    +23ms   382us&lt;br /&gt;
 c.st1.ntp.br                6   3  344m     +0.026      0.037   -124us    92us&lt;br /&gt;
 200.20.186.76               9   3  138m     -0.022      0.031   +172us    42us&lt;br /&gt;
&lt;br /&gt;
 # chronyc sources&lt;br /&gt;
 MS Name/IP address         Stratum Poll Reach LastRx Last sample&lt;br /&gt;
 ===============================================================================&lt;br /&gt;
 ^* a.st1.ntp.br                  1  10   377   588   +487us[ +397us] +/-   12ms&lt;br /&gt;
 ^- b.st1.ntp.br                  2  10   377   830    +23ms[  +23ms] +/-   49ms&lt;br /&gt;
 ^+ c.st1.ntp.br                  2  10    21  1038   -147us[ -242us] +/-   17ms&lt;br /&gt;
 ^+ 200.20.186.76                 1  10   377  1032   +381us[ +285us] +/-   15ms&lt;br /&gt;
&lt;br /&gt;
== Configurando o FRRouting ==&lt;br /&gt;
Nesse ponto iremos configurar o '''FRRouting''' para enviar os IPs das '''loopbacks''' e o '''/30''' para o nosso PE do diagrama. Em '''/etc/frr/daemons''' habilite o parâmetro conforme abaixo:&lt;br /&gt;
 ospfd=yes&lt;br /&gt;
 ospf6d=yes&lt;br /&gt;
Edite o arquivo '''/etc/frr/frr.conf''' e deixe com o conteúdo abaixo, para ficar conforme nosso diagrama do projeto. Apenas troque '''&amp;lt;SENHA&amp;gt;''' por uma senha para fechar o OSPF com mais segurança. Essa senha deve ser usada dos dois lados.&lt;br /&gt;
 frr version 10.3&lt;br /&gt;
 frr defaults traditional&lt;br /&gt;
 hostname dns-recursivo-01&lt;br /&gt;
 log syslog informational&lt;br /&gt;
 no ip forwarding&lt;br /&gt;
 no ipv6 forwarding&lt;br /&gt;
 service integrated-vtysh-config&lt;br /&gt;
 !&lt;br /&gt;
 interface ens18&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf message-digest-key 5 md5 &amp;lt;SENHA&amp;gt;&lt;br /&gt;
  ip ospf network point-to-point&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 network point-to-point&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 interface lo&lt;br /&gt;
  description LOOPBACKS&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf passive&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 passive&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf&lt;br /&gt;
  ospf router-id 172.16.0.6&lt;br /&gt;
  area 0.0.0.0 authentication message-digest&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf6&lt;br /&gt;
  ospf6 router-id 172.16.0.6&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart frr.service&lt;br /&gt;
Cheque se está tudo OK com o OSPF e verifique no PE se está recebendo os prefixos anunciados.&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL&lt;br /&gt;
 172.16.0.5     1 Full/-          10m49s            35.310s 172.16.0.5   ens18:172.16.0.6                  0     0     0&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri    DeadTime    State/IfState         Duration I/F[State]&lt;br /&gt;
 172.16.0.5       1    00:00:30     Full/PointToPoint 25d22:53:47 ens18[PointToPoint]&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor detail'&lt;br /&gt;
 &lt;br /&gt;
  Neighbor 172.16.0.5, interface address 172.16.0.5&lt;br /&gt;
     In the area 0.0.0.0 via interface ens18&lt;br /&gt;
     Neighbor priority is 1, State is Full/-, 5 state changes&lt;br /&gt;
     Most recent state change statistics:&lt;br /&gt;
       Progressive change 21w3d15h ago&lt;br /&gt;
     DR is 0.0.0.0, BDR is 0.0.0.0&lt;br /&gt;
     Options 18 *|-|-|EA|-|-|E|-&lt;br /&gt;
     Dead timer due in 34.685s&lt;br /&gt;
     Database Summary List 0&lt;br /&gt;
     Link State Request List 0&lt;br /&gt;
     Link State Retransmission List 0&lt;br /&gt;
     Thread Inactivity Timer on&lt;br /&gt;
     Thread Database Description Retransmision off&lt;br /&gt;
     Thread Link State Request Retransmission on&lt;br /&gt;
     Thread Link State Update Retransmission on&lt;br /&gt;
 &lt;br /&gt;
     Graceful restart Helper info:&lt;br /&gt;
       Graceful Restart HELPER Status : None&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor detail'&lt;br /&gt;
  Neighbor 172.16.0.5%ens18&lt;br /&gt;
     Area 0.0.0.0 via interface ens18 (ifindex 4)&lt;br /&gt;
     His IfIndex: 60 Link-local address: fe80::469b:c1ff:fed6:43ee&lt;br /&gt;
     State Full for a duration of 25d22:57:14&lt;br /&gt;
     His choice of DR/BDR 0.0.0.0/0.0.0.0, Priority 1&lt;br /&gt;
     DbDesc status: Master SeqNum: 0xb94b0000&lt;br /&gt;
     Summary-List: 0 LSAs&lt;br /&gt;
     Request-List: 0 LSAs&lt;br /&gt;
     Retrans-List: 0 LSAs&lt;br /&gt;
     0 Pending LSAs for DbDesc in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSReq in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSAck in Time 00:00:00 [thread off]&lt;br /&gt;
     Authentication header not present&lt;br /&gt;
&lt;br /&gt;
== Configurando o Unbound ==&lt;br /&gt;
Abaixo a configuração que usaremos nos servidores atentando para o detalhe do '''num-threads''', esse deve ter o valor igual ao número de CPUs do servidor.&lt;br /&gt;
&lt;br /&gt;
Também os IPs utilizados em '''outgoing-interface''' que serão diferentes em cada servidor, esses serão os IPs usados para '''recursividade'''. Consulte o manual do Unbound para obter mais informações sobre cada parâmetro listado na configuração.&lt;br /&gt;
&lt;br /&gt;
O tuning no Unbound pode ser alterado conforme abaixo:&lt;br /&gt;
 num-threads = nº CPUs&lt;br /&gt;
 so-reuseport = yes&lt;br /&gt;
 *-slabs = potência de 2 próximo ao num-threads&lt;br /&gt;
 msg-cache-size = 1g (quantidade de memória pra usar de cache)&lt;br /&gt;
 rrset-cache-size = 2 * msg-cache-size&lt;br /&gt;
 outgoing-range = 8192&lt;br /&gt;
 num-queries-per-thread = 4096&lt;br /&gt;
 so-rcvbuf e so-sndbuf = 4m ou 8m para servidores com muita requisição&lt;br /&gt;
Agora vamos criar nosso arquivo de configuração base em '''/etc/unbound/unbound.conf.d/local.conf''':&lt;br /&gt;
 server:&lt;br /&gt;
         verbosity: 1&lt;br /&gt;
         statistics-interval: 0&lt;br /&gt;
         statistics-cumulative: no&lt;br /&gt;
         extended-statistics: yes&lt;br /&gt;
         num-threads: 8&lt;br /&gt;
         serve-expired: yes&lt;br /&gt;
         interface: 127.0.0.1&lt;br /&gt;
         interface: 10.10.10.10&lt;br /&gt;
         interface: 10.10.9.9&lt;br /&gt;
         interface: 172.16.0.6&lt;br /&gt;
         interface: fd00::10:10:10:10&lt;br /&gt;
         interface: fd00::10:10:9:9&lt;br /&gt;
         interface: ::1&lt;br /&gt;
         interface-automatic: no&lt;br /&gt;
         outgoing-interface: 198.18.1.10&lt;br /&gt;
         outgoing-interface: 2001:db8::faca:198:18:1:10&lt;br /&gt;
         outgoing-range: 8192&lt;br /&gt;
         outgoing-num-tcp: 1024&lt;br /&gt;
         incoming-num-tcp: 2048&lt;br /&gt;
         so-rcvbuf: 4m&lt;br /&gt;
         so-sndbuf: 4m&lt;br /&gt;
         so-reuseport: yes&lt;br /&gt;
         edns-buffer-size: 1232&lt;br /&gt;
         msg-cache-size: 512m&lt;br /&gt;
         msg-cache-slabs: 4&lt;br /&gt;
         num-queries-per-thread: 4096&lt;br /&gt;
         rrset-cache-size: 1g&lt;br /&gt;
         rrset-cache-slabs: 4&lt;br /&gt;
         infra-cache-slabs: 4&lt;br /&gt;
         do-ip4: yes&lt;br /&gt;
         do-ip6: yes&lt;br /&gt;
         do-udp: yes&lt;br /&gt;
         do-tcp: yes&lt;br /&gt;
         chroot: &amp;quot;&amp;quot;&lt;br /&gt;
         username: &amp;quot;unbound&amp;quot;&lt;br /&gt;
         directory: &amp;quot;/etc/unbound&amp;quot;&lt;br /&gt;
         logfile: &amp;quot;/var/log/unbound/unbound.log&amp;quot;&lt;br /&gt;
         use-syslog: no&lt;br /&gt;
         log-time-ascii: yes&lt;br /&gt;
         log-queries: no&lt;br /&gt;
         pidfile: &amp;quot;/var/run/unbound.pid&amp;quot;&lt;br /&gt;
         root-hints: &amp;quot;/usr/share/dns/root.hints&amp;quot;&lt;br /&gt;
         hide-identity: yes&lt;br /&gt;
         hide-version: yes&lt;br /&gt;
         unwanted-reply-threshold: 10000000&lt;br /&gt;
         prefetch: yes&lt;br /&gt;
         prefetch-key: yes&lt;br /&gt;
         rrset-roundrobin: yes&lt;br /&gt;
         minimal-responses: yes&lt;br /&gt;
         module-config: &amp;quot;respip validator iterator&amp;quot;&lt;br /&gt;
         val-clean-additional: yes&lt;br /&gt;
         val-log-level: 1&lt;br /&gt;
         key-cache-slabs: 4&lt;br /&gt;
         deny-any: yes&lt;br /&gt;
         cache-min-ttl: 60&lt;br /&gt;
         key-cache-size: 128m&lt;br /&gt;
         neg-cache-size: 64m&lt;br /&gt;
         cache-max-ttl: 86400&lt;br /&gt;
         infra-cache-numhosts: 100000&lt;br /&gt;
         access-control: 198.18.0.0/22 allow&lt;br /&gt;
         access-control: 2001:db8::/32 allow&lt;br /&gt;
  &lt;br /&gt;
 rpz:&lt;br /&gt;
   name: rpz.block.host.local.zone&lt;br /&gt;
   zonefile: /etc/unbound/rpz.block.hosts.zone&lt;br /&gt;
   rpz-action-override: nxdomain&lt;br /&gt;
  &lt;br /&gt;
 python:&lt;br /&gt;
  &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;.&amp;quot;&lt;br /&gt;
     master: &amp;quot;b.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;c.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;d.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;f.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;g.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;k.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/root.zone&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;arpa.&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/arpa.zone&amp;quot;&lt;br /&gt;
No parâmetro '''interface''' colocamos os IPs que serão usados para consulta dos clientes como o '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9'''. Ali repare que coloquei também o IP privado '''172.16.0.6''', isso porque cada servidor terá o seu IP privado e este deve ser usado pelo seu sistema de monitoramento para checar cada servidor. No '''outgoing-interface''' teremos os IPs, tanto '''IPv4''' quanto '''IPv6''', para que seja feita a recursividade na Internet utilizando eles. Não tem '''IPv6''' ainda na sua rede? Dê uma olhada nesse artigo. Outro parâmetro importante é o '''access-control''' e é através dele que liberamos os prefixos IP para consultarem no nosso DNS Recursivo. No exemplo estou liberando todo o prefixo '''198.18.0.0/22''' e o prefixo '''2001:db8::/32'''. Além da ACL no Unbound, recomendo que crie um filtro de pacotes com iptables ou nftables protegendo seu sistema e liberando as portas '''53/UDP''', '''53/TCP,'''  '''443/TCP e 853/TCP''' apenas para seus clientes. Falarei sobre a '''443/TCP e 853/TCP''' mais para frente nessa mesma documentação.&lt;br /&gt;
&lt;br /&gt;
Agora criaremos o arquivo '''RPZ''' ('''Response Policy Zones'''). Esse arquivo contém os sites que serão bloqueados via '''&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; Recursivo'''. São aqueles sites que às vezes você recebe um Ofício da Justiça solicitando o bloqueio deles. Não entrarei no mérito da efetividade desses bloqueios, porque muitos de vocês sabem que tecnicamente, existem formas de se fazer um bypass através desses bloqueios. Contudo vamos deixar nosso ambiente preparado para esses bloqueios e por isso crie o arquivo '''/etc/unbound/rpz.block.hosts.zone''' com esse conteúdo de exemplo:&lt;br /&gt;
 $TTL 2h&lt;br /&gt;
 @ IN SOA localhost. root.localhost. (2 6h 1h 1w 2h)&lt;br /&gt;
   IN NS  localhost.&lt;br /&gt;
 ; RPZ manual block hosts&lt;br /&gt;
 *.josedascoves.com CNAME .&lt;br /&gt;
 josedascoves.com CNAME .&lt;br /&gt;
No exemplo acima estamos bloqueando qualquer consulta de DNS para '''josedascoves.com''' ou qualquer coisa '''.josedascoves.com'''.&lt;br /&gt;
&lt;br /&gt;
Para testar podemos fazer assim do próprio servidor:&lt;br /&gt;
 # host josedascoves.com ::1&lt;br /&gt;
 Using domain server:&lt;br /&gt;
 Name: ::1&lt;br /&gt;
 Address: ::1#53&lt;br /&gt;
 Aliases:&lt;br /&gt;
 &lt;br /&gt;
 Host josedascoves.com not found: 3(NXDOMAIN)&lt;br /&gt;
Se a resposta for '''NXDOMAIN''' então está funcionando o bloqueio. Para incluir novos bloqueios basta adicionar os domínios, um abaixo do outro, conforme o exemplo que coloquei no arquivo RPZ.&lt;br /&gt;
&lt;br /&gt;
== Acertando o resolv.conf ==&lt;br /&gt;
Vamos modificar nosso /etc/resolv.conf para utilizar DNS externo. Sim você deve estar se perguntando em qual situação isso seria utilizado. Primeiro entenda que o Unbound não irá utilizar o DNS externo para fazer as consultas na Internet e sim, qualquer teste que você faça do servidor precisará apontar para o Unbound usando os IPs '''127.0.0.1''' ou '''::1'''. Faremos isso pela seguinte situação: imagine que o daemon unbound morreu mas você ainda continua com conectividade na Internet. Você conseguiria acessar qualquer local na Internet através do IP mas não através do hostname porque não conseguiria resolver nomes, seu unbound estaria fora do ar. Imagine ainda que você gostaria que seu servidor te avisasse do problema via Telegram ou e-mail. Por isso estamos utilizando um DNS externo no '''/etc/resolv.conf''', apenas para essas situações. Se você não quiser utilizar desse recurso, pode usar o '''127.0.0.1''' e '''::1''' no lugar.&lt;br /&gt;
 nameserver 8.8.8.8&lt;br /&gt;
 nameserver 8.8.4.4&lt;br /&gt;
 nameserver 2001:4860:4860::8888&lt;br /&gt;
&lt;br /&gt;
== Script de teste de recursividade ==&lt;br /&gt;
Estamos montando uma '''Rede de DNS Recursivo Anycast''', então é muito importante que você monitore essa rede para saber se algum node morreu e iniciar o troubleshooting, resolver o problema e levantar o sistema novamente. Tudo isso é importante mas o cliente não deve ficar esperando até você resolver o problema, seu sistema precisa ser inteligente o suficiente para se remover da Rede quando tiver um problema e se inserir novamente, quando o problema estiver sido solucionado. Se você montar uma Rede de DNS e um dos nodes apresentar algum problema, todos os clientes atendidos por aquele node migrarão automaticamente e transparentemente para outro '''DNS Recursivo Anycast''' mais próximo. Isso se chama '''disponibilidade'''.&lt;br /&gt;
&lt;br /&gt;
O script '''/root/scripts/checa_dns.sh''' abaixo tem a função de fazer os testes de recursividade e checar se o daemon do unbound continua rodando. Se algo acontecer, ele para o anúncio do '''10.10.10.10''' e '''10.10.9.9''' e retorna eles quando tudo estiver resolvido.&lt;br /&gt;
 # mkdir /root/scripts&lt;br /&gt;
&lt;br /&gt;
 #!/usr/bin/env bash&lt;br /&gt;
 #Script para teste de DNS v2.1&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 #Informe um domínio por linha:&lt;br /&gt;
 dominios_testar=(&lt;br /&gt;
 www.google.com&lt;br /&gt;
 www.terra.com.br&lt;br /&gt;
 www.uol.com.br&lt;br /&gt;
 www.globo.com&lt;br /&gt;
 www.facebook.com&lt;br /&gt;
 www.youtube.com&lt;br /&gt;
 www.twitch.com&lt;br /&gt;
 www.discord.com&lt;br /&gt;
 www.debian.org&lt;br /&gt;
 www.redhat.com&lt;br /&gt;
 )&lt;br /&gt;
 corte_taxa_falha=100 #Porcentagem de falha para executar uma ação&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 remove_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; != &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no description' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME morreu!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 adiciona_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; == &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'description LOOPBACKS' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME retornou do inferno!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
 if [ $? -ne 0 ]; then&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME morreu DNS mas tentando levantar!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    systemctl restart unbound&lt;br /&gt;
    systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
    if [ $? -ne 0 ]; then&lt;br /&gt;
       remove_ospf&lt;br /&gt;
       exit&lt;br /&gt;
    fi&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME servico DNS voltou mas tinha morrido!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 qt_falhas=0&lt;br /&gt;
 qt_total=&amp;quot;${#dominios_testar[@]}&amp;quot;&lt;br /&gt;
 echo &amp;quot;total_dominios: $qt_total&amp;quot;&lt;br /&gt;
 for site in &amp;quot;${dominios_testar[@]}&amp;quot;&lt;br /&gt;
 do&lt;br /&gt;
   unbound-control flush $site &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   resolver=&amp;quot;127.0.0.1&amp;quot;&lt;br /&gt;
   echo -e &amp;quot; - dominio $site - $resolver - \c&amp;quot;&lt;br /&gt;
   host $site $resolver &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   if [ $? -ne 0 ]; then&lt;br /&gt;
      ((qt_falhas++))&lt;br /&gt;
      echo -e &amp;quot;[Falhou]&amp;quot;&lt;br /&gt;
   else&lt;br /&gt;
      echo -e &amp;quot;[OK]&amp;quot;&lt;br /&gt;
   fi&lt;br /&gt;
 done&lt;br /&gt;
  &lt;br /&gt;
 taxa_falha=$((qt_falhas*100/qt_total))&lt;br /&gt;
 echo &amp;quot;Falhas $qt_falhas/$qt_total ($taxa_falha%)&amp;quot;&lt;br /&gt;
  &lt;br /&gt;
 if [ &amp;quot;$taxa_falha&amp;quot; -ge &amp;quot;$corte_taxa_falha&amp;quot; ]; then&lt;br /&gt;
    remove_ospf&lt;br /&gt;
    exit&lt;br /&gt;
 fi&lt;br /&gt;
 adiciona_ospf&lt;br /&gt;
Se rodarmos o script manualmente veremos isto:&lt;br /&gt;
 # /root/scripts/checa_dns.sh&lt;br /&gt;
 total_dominios: 10&lt;br /&gt;
  - dominio www.google.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.terra.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.uol.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.globo.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.facebook.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.youtube.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.twitch.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.discord.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.debian.org - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.redhat.com - 127.0.0.1 - [OK]&lt;br /&gt;
 Falhas 0/10 (0%)&lt;br /&gt;
Se acontecer 100% de falhas o script irá remover os anúncios do OSPF. Se o daemon do unbound morrer, ele tentará reiniciá-lo. Se tudo normalizar o script irá retornar os anúncios para o OSPF. Deixei comentado no script as partes que enviariam uma notificação para o Telegram. Existem diversas documentações sobre isso na Internet, eu mesmo tenho uma. Assim que eu publicar aqui, atualizo essa documentação e sinta-se à vontade de modificar como desejar.&lt;br /&gt;
 # chmod 700 /root/scripts/checa_dns.sh&lt;br /&gt;
Adicione a linha abaixo em seu '''/etc/crontab''':&lt;br /&gt;
 */1 *   * * *   root    /root/scripts/checa_dns.sh&lt;br /&gt;
&lt;br /&gt;
== Habilitando o DoH (&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; over HTTPS) - opcional ==&lt;br /&gt;
Para habilitar o '''DoH''' no Unbound é bem simples. O recurso do '''DoH''' vem para trazer mais segurança e privacidade para o usuário. É um recurso muito pouco utilizado ainda mas que seu cliente pode vir a pedir algum dia.&lt;br /&gt;
&lt;br /&gt;
Você precisará gerar certificados SSL legítimos e para isso você poderá usar o '''Let's Encrypt''' só que de uma forma não tão convencional.&lt;br /&gt;
&lt;br /&gt;
Na sequência vamos instalar o Let's Encrypt para gerarmos nosso certificado SSL:&lt;br /&gt;
 # apt install letsencrypt&lt;br /&gt;
Escolha um '''hostname''' para ser usado no nosso '''DoH''' e aponte ele no seu DNS Autoritativo para seus IPs 10.10.10.10 e 10.10.9.9. Aqui vamos usar o seguinte como exemplo: '''doh.brasilpeeringforum.org'''. Para gerarmos nosso certificado iremos usar o tipo '''DNS-01''', ele não necessita que tenhamos um servidor web rodando no servidor e nem tão pouco levanta um serviço na porta 80 para checar o hostname. Ele utiliza o DNS como validador e vai te solicitar que crie um registro '''CNAME''' no seu '''DNS Autoritativo''' para provar que você tem o controle sobre aquele hostname. Antes disso vamos instalar um programa em Python para podermos automatizar nossa renovação de certificado no futuro. Esse programa se encontra '''[https://github.com/joohoi/acme-dns-certbot-joohoi/raw/master/acme-dns-auth.py aqui]''' mas vou deixá-lo abaixo já modificado o interpretador.&lt;br /&gt;
&lt;br /&gt;
Crie o arquivo '''/etc/letsencrypt/acme-dns-auth.py''' com o conteúdo abaixo:&lt;br /&gt;
 #!/usr/bin/env python3&lt;br /&gt;
 import json&lt;br /&gt;
 import os&lt;br /&gt;
 import requests&lt;br /&gt;
 import sys&lt;br /&gt;
 &lt;br /&gt;
 ### EDIT THESE: Configuration values ###&lt;br /&gt;
 &lt;br /&gt;
 # URL to acme-dns instance&lt;br /&gt;
 ACMEDNS_URL = &amp;quot;&amp;lt;nowiki&amp;gt;https://auth.acme-dns.io&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
 # Path for acme-dns credential storage&lt;br /&gt;
 STORAGE_PATH = &amp;quot;/etc/letsencrypt/acmedns.json&amp;quot;&lt;br /&gt;
 # Whitelist for address ranges to allow the updates from&lt;br /&gt;
 # Example: ALLOW_FROM = [&amp;quot;192.168.10.0/24&amp;quot;, &amp;quot;::1/128&amp;quot;]&lt;br /&gt;
 ALLOW_FROM = []&lt;br /&gt;
 # Force re-registration. Overwrites the already existing acme-dns accounts.&lt;br /&gt;
 FORCE_REGISTER = False&lt;br /&gt;
 &lt;br /&gt;
 ###   DO NOT EDIT BELOW THIS POINT   ###&lt;br /&gt;
 ###         HERE BE DRAGONS          ###&lt;br /&gt;
 &lt;br /&gt;
 DOMAIN = os.environ[&amp;quot;CERTBOT_DOMAIN&amp;quot;]&lt;br /&gt;
 if DOMAIN.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
     DOMAIN = DOMAIN[2:]&lt;br /&gt;
 VALIDATION_DOMAIN = &amp;quot;_acme-challenge.&amp;quot;+DOMAIN&lt;br /&gt;
 VALIDATION_TOKEN = os.environ[&amp;quot;CERTBOT_VALIDATION&amp;quot;]&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 class AcmeDnsClient(object):&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
     Handles the communication with ACME-DNS API&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
     def __init__(self, acmedns_url):&lt;br /&gt;
         self.acmedns_url = acmedns_url&lt;br /&gt;
 &lt;br /&gt;
     def register_account(self, allowfrom):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Registers a new ACME-DNS account&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
         if allowfrom:&lt;br /&gt;
             # Include whitelisted networks to the registration call&lt;br /&gt;
             reg_data = {&amp;quot;allowfrom&amp;quot;: allowfrom}&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;,&lt;br /&gt;
                                 data=json.dumps(reg_data))&lt;br /&gt;
         else:&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;)&lt;br /&gt;
         if res.status_code == 201:&lt;br /&gt;
             # The request was successful&lt;br /&gt;
             return res.json()&lt;br /&gt;
         else:&lt;br /&gt;
             # Encountered an error&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to register a new acme-dns &amp;quot;&lt;br /&gt;
                    &amp;quot;account. HTTP status {}, Response body: {}&amp;quot;)&lt;br /&gt;
             print(msg.format(res.status_code, res.text))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def update_txt_record(self, account, txt):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Updates the TXT challenge record to ACME-DNS subdomain.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         update = {&amp;quot;subdomain&amp;quot;: account['subdomain'], &amp;quot;txt&amp;quot;: txt}&lt;br /&gt;
         headers = {&amp;quot;X-Api-User&amp;quot;: account['username'],&lt;br /&gt;
                    &amp;quot;X-Api-Key&amp;quot;: account['password'],&lt;br /&gt;
                    &amp;quot;Content-Type&amp;quot;: &amp;quot;application/json&amp;quot;}&lt;br /&gt;
         res = requests.post(self.acmedns_url+&amp;quot;/update&amp;quot;,&lt;br /&gt;
                             headers=headers,&lt;br /&gt;
                             data=json.dumps(update))&lt;br /&gt;
         if res.status_code == 200:&lt;br /&gt;
             # Successful update&lt;br /&gt;
             return&lt;br /&gt;
         else:&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to update TXT record in &amp;quot;&lt;br /&gt;
                    &amp;quot;acme-dns. \n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request headers:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request body:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response HTTP status: {}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response body: {}&amp;quot;)&lt;br /&gt;
             s_headers = json.dumps(headers, indent=2, sort_keys=True)&lt;br /&gt;
             s_update = json.dumps(update, indent=2, sort_keys=True)&lt;br /&gt;
             s_body = json.dumps(res.json(), indent=2, sort_keys=True)&lt;br /&gt;
             print(msg.format(s_headers, s_update, res.status_code, s_body))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
 class Storage(object):&lt;br /&gt;
     def __init__(self, storagepath):&lt;br /&gt;
         self.storagepath = storagepath&lt;br /&gt;
         self._data = self.load()&lt;br /&gt;
 &lt;br /&gt;
     def load(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Reads the storage content from the disk to a dict structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         data = dict()&lt;br /&gt;
         filedata = &amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             with open(self.storagepath, 'r') as fh:&lt;br /&gt;
                 filedata = fh.read()&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             if os.path.isfile(self.storagepath):&lt;br /&gt;
                 # Only error out if file exists, but cannot be read&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage file exists but cannot be read&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         try:&lt;br /&gt;
             data = json.loads(filedata)&lt;br /&gt;
         except ValueError:&lt;br /&gt;
             if len(filedata) &amp;gt; 0:&lt;br /&gt;
                 # Storage file is corrupted&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage JSON is corrupted&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         return data&lt;br /&gt;
 &lt;br /&gt;
     def save(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Saves the storage content to disk&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         serialized = json.dumps(self._data)&lt;br /&gt;
         try:&lt;br /&gt;
             with os.fdopen(os.open(self.storagepath,&lt;br /&gt;
                                    os.O_WRONLY | os.O_CREAT, 0o600), 'w') as fh:&lt;br /&gt;
                 fh.truncate()&lt;br /&gt;
                 fh.write(serialized)&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             print(&amp;quot;ERROR: Could not write storage file.&amp;quot;)&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def put(self, key, value):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Puts the configuration value to storage and sanitize it&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         # If wildcard domain, remove the wildcard part as this will use the&lt;br /&gt;
         # same validation record name as the base domain&lt;br /&gt;
         if key.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
             key = key[2:]&lt;br /&gt;
         self._data[key] = value&lt;br /&gt;
 &lt;br /&gt;
     def fetch(self, key):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Gets configuration value from storage&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             return self._data[key]&lt;br /&gt;
         except KeyError:&lt;br /&gt;
             return None&lt;br /&gt;
 &lt;br /&gt;
 if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
     # Init&lt;br /&gt;
     client = AcmeDnsClient(ACMEDNS_URL)&lt;br /&gt;
     storage = Storage(STORAGE_PATH)&lt;br /&gt;
 &lt;br /&gt;
     # Check if an account already exists in storage&lt;br /&gt;
     account = storage.fetch(DOMAIN)&lt;br /&gt;
     if FORCE_REGISTER or not account:&lt;br /&gt;
         # Create and save the new account&lt;br /&gt;
         account = client.register_account(ALLOW_FROM)&lt;br /&gt;
         storage.put(DOMAIN, account)&lt;br /&gt;
         storage.save()&lt;br /&gt;
 &lt;br /&gt;
         # Display the notification for the user to update the main zone&lt;br /&gt;
         msg = &amp;quot;Please add the following CNAME record to your main DNS zone:\n{}&amp;quot;&lt;br /&gt;
         cname = &amp;quot;{} CNAME {}.&amp;quot;.format(VALIDATION_DOMAIN, account[&amp;quot;fulldomain&amp;quot;])&lt;br /&gt;
         print(msg.format(cname))&lt;br /&gt;
 &lt;br /&gt;
     # Update the TXT record in acme-dns instance&lt;br /&gt;
     client.update_txt_record(account, VALIDATION_TOKEN)&lt;br /&gt;
&lt;br /&gt;
 # chmod +x /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
Usaremos a seguinte instrução para criar nosso certificado:&lt;br /&gt;
 # certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d doh.brasilpeeringforum.org&lt;br /&gt;
 Saving debug log to /var/log/letsencrypt/letsencrypt.log&lt;br /&gt;
 Plugins selected: Authenticator manual, Installer None&lt;br /&gt;
 Cert is due for renewal, auto-renewing...&lt;br /&gt;
 Renewing an existing certificate for doh.brasilpeeringforum.org&lt;br /&gt;
 Performing the following challenges:&lt;br /&gt;
 dns-01 challenge for doh.brasilpeeringforum.org&lt;br /&gt;
 Running manual-auth-hook command: /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
 Output from manual-auth-hook command acme-dns-auth.py:&lt;br /&gt;
 Please add the following CNAME record to your main DNS zone:&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
 &lt;br /&gt;
 Waiting for verification...&lt;br /&gt;
 &lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Challenges loaded. Press continue to submit to CA. Pass &amp;quot;-v&amp;quot; for more info about&lt;br /&gt;
 challenges.&lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Press Enter to Continue&lt;br /&gt;
Nesse momento você cria o registro '''CNAME''' no seu DNS Autoritativo conforme ele solicitou: '''_acme-challenge.doh.brasilpeeringforum.org IN CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.''' e somente depois de criado e checado no DNS, você pressiona o '''Enter''' para continuar. Você pode checar dessa forma:&lt;br /&gt;
 # host -t cname _acme-challenge.doh.brasilpeeringforum.org&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org is an alias for b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
Para que nosso certificado seja automaticamente renovado colocaremos no '''/etc/crontab''' a seguinte linha abaixo:&lt;br /&gt;
 00 00   1 * *   root    /usr/bin/certbot -q renew --deploy-hook &amp;quot;/usr/sbin/unbound-control reload_keep_cache&amp;quot;&lt;br /&gt;
Acima temos a instrução para renovação automática do certificado. Repare que você vai precisar também copiar esse certificado para seus outros servidores, escolha um servidor para manter o certificado sempre atualizado e crie um script que faça a mesma cópia remotamente para os outros servidores. O '''scp''' e o '''rsync''' são seus aliados nisso.&lt;br /&gt;
&lt;br /&gt;
=== Configurando o Unbound ===&lt;br /&gt;
Em nosso '''/etc/unbound/unbound.conf.d/local.conf''', adicionaremos no bloco &amp;quot;'''server:'''&amp;quot; o seguinte:&lt;br /&gt;
 interface: 10.10.10.10@443 &lt;br /&gt;
 interface: 10.10.9.9@443&lt;br /&gt;
 interface: fd00::10:10:10:10@443&lt;br /&gt;
 interface: fd00::10:10:9:9@443&lt;br /&gt;
 tls-service-key: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/privkey.pem&amp;quot; &lt;br /&gt;
 tls-service-pem: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/fullchain.pem&amp;quot;&lt;br /&gt;
Para usar o recurso do '''DoH''' você precisará habilitar o recurso no seu navegador e informar a URL. Vou colocar o exemplo do '''Google Chrome''': Digite '''chrome://settings/security?search=dns''' no seu Chrome e ative '''Usar DNS seguro''', selecione '''Personalizado''' e adicione nossa URL:&lt;br /&gt;
[[Arquivo:Doh bpf2.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Finalizando ==&lt;br /&gt;
Aqui finalizamos nosso projeto para uma Rede de DNS(s) Recursivos Anycast com Hyperlocal. Esse projeto é escalável, seguro, resiliente e você entregará muito mais qualidade de Internet para o seu cliente. Pare de entregar o '''8.8.8.8''' para os seus clientes, você está contribuindo para uma Internet mais lenta, sem a qualidade que o seu cliente merece. Investi meu tempo, que é muito pouco, para deixar esse documento para a comunidade, para você melhorar o seu ISP, para dar um UP! nele, então vamos começar 2023 com o pé direito. O que acha?&lt;br /&gt;
&lt;br /&gt;
Como prova de conceito, uma imagem abaixo onde temos uma Rede em produção de DNS(s) Recursivos Anycast e apontando exatamente o momento em que houve alguma situação que fez com que as queries de DNS, convergissem de um node para outro, de forma transparente e automática para o cliente. Podemos notar também que ao ser resolvido o problema, o tráfego retornou para o seu node correto:&lt;br /&gt;
[[Arquivo:Convergencia.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== KINDNS (Stands for Knowledge-Sharing and Instantiating Norms for DNS and Naming Security) ==&lt;br /&gt;
Achou que havia terminado? Agora que você tem a capacidade de montar uma '''Rede de DNS Recursivo''' com todas essas features acima, com todas as ferramentas que foram comentadas, o que acha de certificar o que fez?&lt;br /&gt;
&lt;br /&gt;
Assim como o [https://www.manrs.org/ MANRS] veio para certificar nosso sistema de roteamento na Internet, agora temos o [https://kindns.org/ KINDNS] para certificar que nossos sistemas de DNS estão bem feitos e dentro dos padrões de segurança. Existem '''7 ações''' que podem ser certificadas para nossos DNS Recursivos e estão aqui em https://kindns.org/shared-private-resolvers/. Com essa nossa documentação, se bem aplicada, você pode se candidatar ao KINDNS e ter seu ASN listado aqui https://kindns.org/participants/&lt;br /&gt;
&lt;br /&gt;
Obter e manter o '''MANRS''' e '''KINDNS''' demonstra seu compromisso com as Boas Práticas, contribui para termos uma '''Internet''' mais segura e te abre portas para novos negócios que possam exigir essas conformidades.&lt;br /&gt;
&lt;br /&gt;
Autor: [[Usuário:Gondim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Infraestrutura]]&lt;br /&gt;
__FORCARTDC__&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3984</id>
		<title>DNS Recursivo Anycast Hyperlocal</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3984"/>
		<updated>2025-11-22T17:00:47Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
==Introdução==&lt;br /&gt;
Você sabe como funciona a Internet? Essa é uma pergunta que meu amigo '''Thiago Ayub''' sempre faz aos seus candidatos à vagas de emprego e não importa o quanto tenham de experiência em '''Engenharia de Redes''', todos sempre travam nesse momento. Todos estão sempre prontos e preparados para resolver os problemas mais cabeludos em '''BGP''', '''OSPF''', '''MPLS''', etc mas travam com essa simples pergunta. Para contextualizar e visualizarmos melhor vamos nos atentar à imagem abaixo e uma explicação simplificada de como funciona:&lt;br /&gt;
[[Arquivo:Dns hierarquia.png|esquerda|commoldura]]&lt;br /&gt;
Tudo começa com um usuário sentado confortavelmente e querendo acessar um conteúdo disponível na Internet. Ele digita em seu navegador preferido a URL: '''&amp;lt;nowiki&amp;gt;https://wiki.brasilpeeringforum.org&amp;lt;/nowiki&amp;gt;''',&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;1)&amp;lt;/big&amp;gt;''' &amp;lt;big&amp;gt;O&amp;lt;/big&amp;gt; &amp;lt;big&amp;gt;navegador irá requisitar do '''DNS Recursivo''' utilizado pelo usuário, o '''endereço IP''' que responde pelo nome '''wiki.'''&amp;lt;/big&amp;gt;'''brasilpeeringforum.org'''&amp;lt;big&amp;gt;. Isso porque todos os acessos se dão na Internet através do '''endereço''' '''IP''' e não através do '''nome'''. Imaginem se tivéssemos que decorar os endereços IPs de todos os sites e serviços que quiséssemos acessar na Internet?&amp;lt;/big&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;big&amp;gt;'''2)''' Nosso DNS Recursivo checa se a informação consta em seu cache.&amp;lt;/big&amp;gt; Se a informação existir ela é devolvida ao navegador do usuário e aí este consegue acessar o site.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Do contrário o DNS Recursivo pergunta ao '''Root Server''' quem é o '''TLD (Top Level Domain)''' responsável para atender a requisição. &lt;br /&gt;
&lt;br /&gt;
'''4)''' O '''Root Server''' informa ao DNS Recursivo o endereço do '''TLD responsável'''. No Brasil o '''TLD''' responsável pelo '''.br''' seria o '''Registro.br'''.&lt;br /&gt;
&lt;br /&gt;
'''5)''' O DNS Recursivo pergunta ao '''TLD''' sobre '''wiki.brasilpeeringforum.org''' e este responde com os endereços IP dos '''DNS Autoritativos''' responsáveis pelo domínio '''brasilpeeringforum.org.'''&lt;br /&gt;
&lt;br /&gt;
'''6)''' O DNS Recursivo pergunta aos '''DNS Autoritativos''' pelo '''wiki.brasilpeeringforum.org''' e este responde com o '''endereço IP'''.&lt;br /&gt;
&lt;br /&gt;
'''7)''' Por último o DNS Recursivo devolve a informação para o navegador do usuário.&lt;br /&gt;
&lt;br /&gt;
Como que se dá a comunicação entre os '''DNS(s) Recursivos, Root Servers, TLDs''' e '''Autoritativos'''? Como que o navegador do usuário, após receber o IP do site, consegue chegar no servidor que tem o conteúdo? Isso só é possível devido ao protocolo chamado '''BGP (Border Gateway Protocol)''', todos os caminhos que conhecemos como rotas de destino, são anunciadas por milhares de participantes na '''Internet''' conhecidos como '''AS (Autonomous System)''', esses participantes se interligam para disponibilizar conteúdos e acessos pelo mundo aos milhares de usuários. É uma imensa rede colaborativa formada por Empresas, Universidades, Governos e todos que queiram se interconectar. Percebam que sem o '''BGP''', que serve de caminho para chegarmos nos conteúdos e sem o '''DNS (Domain Name System)''' para traduzir o nome para o endereço IP, a '''Internet''' não funcionaria e por isso precisamos cuidar muito bem desses dois serviços.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Mas não acaba por aí. O '''DNS Recursivo''' tem um papel muito importante para o Provedor de Internet e que envolve segurança, qualidade de acesso à Internet e a disponibilidade do serviço entregue ao cliente. Quando bem configurado acelera as consultas dos acessos graças ao seu cache interno, mas para que isso seja percebido pelo assinante, é necessário que esteja o mais próximo possível do seu cliente.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Um erro que destrói a qualidade do nosso serviço ==&lt;br /&gt;
Um erro muito comum que muitas operadoras cometem é utilizar DNS Recursivo externo, como o '''8.8.8.8''', '''1.1.1.1''' e outros, para seus clientes. Quanto mais próximo dos seus clientes, mais qualidade de serviço estará entregando a eles. Conteúdos serão entregues mais rapidamente pois serão resolvidos e armazenados em caches locais e não consultados remotamente na Internet. Para falar mais sobre isso, te convido leitor desse documento, que assista essa palestra do '''Thiago Ayub''' no '''GTER 51/GTS 37''' (2022) '''8.888 MOTIVOS PARA NÃO USAR DNS RECURSIVO EXTERNO EM SEU AS''': https://www.youtube.com/watch?v=Rsvpu5uF2Io&lt;br /&gt;
&lt;br /&gt;
== Objetivo ==&lt;br /&gt;
O objetivo desta documentação não é te ensinar tudo sobre '''DNS''', '''BGP''', '''OSPF''' e nem tão pouco sobre GNU/Linux e sim te mostrar um exemplo de servidor DNS Recursivo implementado pensando em segurança, qualidade e resiliência. Usaremos em todas as nossas documentações o [https://www.debian.org/ Debian GNU/Linux], por ser uma distribuição que considero uma obra de arte criada por uma enorme comunidade séria, com vasta experiência de anos, qualidade no empacotamento dos programas, estável e com uma equipe de segurança excelente e ativa. Caso você leitor, utilize alguma outra distribuição GNU/Linux, todo conteúdo apresentado aqui pode ser aplicado em outras distros, desde que respeitando as particularidades de cada uma.&lt;br /&gt;
&lt;br /&gt;
Aqui construiremos um sistema do tipo '''Anycast''', ou seja, terás o serviço rodando em diversas localidades da sua Rede utilizando o mesmo endereçamento IP e que atenderá seu cliente mais próximo. Em caso de falhas, seus clientes automaticamente e de forma transparente continuarão consultando o DNS mais próximo deles. Para que ele funcione dessa forma você precisará ter uma '''Rede OSPF''' implementada no seu Provedor Internet ou algum outro protocolo como por exemplo o '''ISIS,''' mas esse documento não irá abordar o '''ISIS'''. Também utilizaremos o '''Hyperlocal''' como recurso adicional para gerar algumas proteções de segurança e velocidade na resposta relacionada aos servidores de DNS Raiz da Internet.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
Para exemplificar nosso servidor de DNS Recursivo, usaremos como base das explicações um diagrama demonstrando o uso do DNS Recursivo em uma Rede fictícia. Adotaremos IPs privados e reservados para demonstrar todo o ambiente do Provedor de Internet.&lt;br /&gt;
[[Arquivo:Recursivo99.png|esquerda|miniaturadaimagem|695x695px]]&lt;br /&gt;
Nesse diagrama podemos observar alguns detalhes técnicos como por exemplo: existem '''3 servidores de DNS Recursivo''' posicionados em locais diferentes, que poderiam estar em bairros diferentes e até em cidades diferentes. Em cada servidor teremos '''2 loopbacks''' com os IPs:&lt;br /&gt;
&lt;br /&gt;
'''10.10.10.10/32 - fd00::10:10:10:10/128'''&lt;br /&gt;
&lt;br /&gt;
'''10.10.9.9/32 - fd00::10:10:9:9/128'''&lt;br /&gt;
&lt;br /&gt;
Esses IPs serão entregues pelos concentradores '''PPPoE''' ou '''IPoE''' ('''BNG''') para seus clientes como '''DNS primário''' e '''secundário'''. Podemos usar IPs privados como DNS primário e secundário em um ambiente real? Sim podemos, desde que não sejam IPs que possam ter problemas com as redes privadas dos clientes. Ex.: rede do cliente usando '''192.168.0.0/24'''. Se entregarmos o DNS sendo '''192.168.0.10''' e '''192.168.0.20''' teremos problemas e o cliente ficará sem Internet, porque '''192.168.0.10''' e '''192.168.0.20''' fazem parte da rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
Agora entregando '''10.10.10.10,''' '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9''' não teríamos problemas com a rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
'''Motivos para usarmos IPs privados:'''&lt;br /&gt;
* O principal motivo está relacionado com a segurança, uma vez que sendo um IP privado, não pode sofrer ataques DDoS direcionados diretamente para ele, vindos da Internet.&lt;br /&gt;
* Nem mesmo o cliente da sua rede conhece os '''IPs públicos''' utilizados para recursividade na Internet.&lt;br /&gt;
* Memorizar os IPs '''10.10.10.10''' e '''10.10.9.9''' é tão fácil quanto memorizar o '''8.8.8.8''' e o '''1.1.1.1'''. Mais fácil para o seu técnico guardar essa informação e utilizar onde for necessário.&lt;br /&gt;
Cada servidor DNS Recursivo possui um '''IPv4 público''', aqui representado por '''198.18.x.x/27''' e um '''IPv6 global''' representado por um IP dentro do prefixo '''2001:db8::/32'''. Cada servidor precisa ter os seus próprios IPs e são através destes IPs que as consultas de DNS serão realizadas na Internet.&lt;br /&gt;
&lt;br /&gt;
Nessa topologia usando '''Anycast''', o cliente será sempre atendido pelo '''DNS Recursivo''' mais próximo, desde que os pesos no '''OSPF''' estejam ajustados corretamente.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
== Dados do servidor ==&lt;br /&gt;
Podemos utilizar um sistema virtualizado ou não. Sistemas virtualizados são bem vindos pois são mais simples quando precisamos fazer backups, levantar outros sistemas sem complicações e se precisarmos restaurar rapidamente algum sistema que ficou indisponível por algum motivo. A configuração abaixo tem capacidade para atender algo em torno a '''50.000 assinantes ou mais'''. O DNS Recursivo é um serviço que pode ser utilizado até mesmo em um '''Raspberry Pi''' e atender operações pequenas, nesse caso com o intuito de economizar energia e espaço. Nosso foco aqui é montar uma rede de '''DNS Recursivo Anycast com HyperLocal'''. Como comentei acima o servidor deve ficar o mais próximo dos clientes para termos a '''menor latência possível''' e '''sempre menor que 5ms''' entre o cliente e o servidor.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!CPU&lt;br /&gt;
!Memória&lt;br /&gt;
!Disco&lt;br /&gt;
!Sistema&lt;br /&gt;
|-&lt;br /&gt;
|2.4Ghz 8 cores&lt;br /&gt;
|16G DDR4&lt;br /&gt;
|30G&lt;br /&gt;
|Debian 13 amd64 (Trixie)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Softwares utilizados ==&lt;br /&gt;
* Debian 13 amd64 (Trixie) instalação mínima.&lt;br /&gt;
&lt;br /&gt;
* [https://frrouting.org/ FRRouting].&lt;br /&gt;
* Unbound.&lt;br /&gt;
* Chrony (NTP/NTS).&lt;br /&gt;
* Shell script em bash.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades que teremos ==&lt;br /&gt;
* Sistema em Anycast.&lt;br /&gt;
* Hyperlocal.&lt;br /&gt;
* Controle de acesso por &amp;lt;abbr&amp;gt;ACL&amp;lt;/abbr&amp;gt;.&lt;br /&gt;
* RPZ (Response Policy Zone).&lt;br /&gt;
* Bloqueio de consultas do tipo ANY.&lt;br /&gt;
* QNAME minimization habilitado. (habilitado por default no Unbound)&lt;br /&gt;
* Recursividade em IPv4 e IPv6.&lt;br /&gt;
* DNSSEC habilitado.&lt;br /&gt;
* &amp;lt;abbr&amp;gt;DoH (DNS&amp;lt;/abbr&amp;gt; over HTTPS) habilitado.&lt;br /&gt;
&lt;br /&gt;
== Monitoramento ==&lt;br /&gt;
O monitoramento é algo bem específico e não é o foco deste documento mas é extremamente importante que você monitore seus servidores de DNS por alguma ferramenta como o Zabbix. Aqui mostrarei apenas como enviar as informações para o Zabbix. Algumas coisas que você deveria monitorar nos servidores de DNS Recursivo:&lt;br /&gt;
* Serviço do unbound parou.&lt;br /&gt;
* Perda de pacotes.&lt;br /&gt;
* Latência alta de pacotes.&lt;br /&gt;
* Lentidão na resolução de queries.&lt;br /&gt;
* CPU alta.&lt;br /&gt;
* Load alto.&lt;br /&gt;
* Memória com uso alto.&lt;br /&gt;
* Disco com pouco espaço.&lt;br /&gt;
* Queda brusca nas queries.&lt;br /&gt;
* A recursividade parou de funcionar.&lt;br /&gt;
* A recursividade voltou a funcionar.&lt;br /&gt;
Este abaixo é um exemplo de monitoramento de um sistema de DNS Recursivo que atende 50.000 assinantes:&lt;br /&gt;
[[Arquivo:Grafana dns.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Configurando a Rede ==&lt;br /&gt;
Nossa documentação será baseada no diagrama apresentado acima e por isso configuraremos apenas um dos três servidores, porque os outros serão configurados da mesma forma, só que com dados diferentes. Para tanto assumirei que já temos um sistema Debian instalado com o mínimo de pacotes e somente com sshd, para que possamos acessar remotamente mais tarde. '''Não instale um ambiente gráfico no servidor''', você não deve querer fazer isso por diversos motivos e os principais: primeiro porque não é um Desktop e segundo porque o ambiente gráfico devoraria toda a memória com recursos que não seriam úteis aqui.&lt;br /&gt;
&lt;br /&gt;
Em '''/etc/network/interfaces''' deixaremos assim:&lt;br /&gt;
 # This file describes the network interfaces available on your system&lt;br /&gt;
 # and how to activate them. For more information, see interfaces(5).&lt;br /&gt;
  &lt;br /&gt;
 source /etc/network/interfaces.d/*&lt;br /&gt;
  &lt;br /&gt;
 # The loopback network interface&lt;br /&gt;
 auto lo&lt;br /&gt;
 iface lo inet loopback&lt;br /&gt;
  &lt;br /&gt;
 auto lo:0&lt;br /&gt;
 iface lo:0 inet static&lt;br /&gt;
       address 10.10.10.10/32&lt;br /&gt;
  &lt;br /&gt;
 auto lo:1&lt;br /&gt;
 iface lo:1 inet static&lt;br /&gt;
       address 10.10.9.9/32&lt;br /&gt;
 &lt;br /&gt;
 auto lo:2&lt;br /&gt;
 iface lo:2 inet6 static&lt;br /&gt;
       address fd00::10:10:10:10/128&lt;br /&gt;
 &lt;br /&gt;
 auto lo:3&lt;br /&gt;
 iface lo:3 inet6 static&lt;br /&gt;
       address fd00::10:10:9:9/128&lt;br /&gt;
  &lt;br /&gt;
 # The primary network interface&lt;br /&gt;
 auto ens18&lt;br /&gt;
 iface ens18 inet static&lt;br /&gt;
         address 198.18.1.10/27&lt;br /&gt;
         gateway 198.18.1.1&lt;br /&gt;
  &lt;br /&gt;
 iface ens18 inet6 static&lt;br /&gt;
         address 2001:db8::faca:198:18:1:10/64&lt;br /&gt;
         gateway 2001:db8::faca:198:18:1:1&lt;br /&gt;
  &lt;br /&gt;
 # The secondary network interface&lt;br /&gt;
 auto ens18:0&lt;br /&gt;
 iface ens18:0 inet static&lt;br /&gt;
         address 172.16.0.6/30&lt;br /&gt;
Nesse cenário temos as duas '''loopbacks''' com os IPs '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10''' e '''fd00::10:10:9:9''' que serão anunciados via OSPF para a rede e serem entregues aos clientes via BNG. Os IPs '''198.18.1.10''' e '''2001:db8::faca:198:18:1:10''' serão usados para fazerem a recursividade na Internet tanto em IPv4 quanto em IPv6. Esses IPs não devem ser divulgados para clientes; os IPs públicos são dedicados apenas para essa finalidade.&lt;br /&gt;
&lt;br /&gt;
== Configuração dos repositórios Debian ==&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://security.debian.org/debian-security/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-security&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-updates&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian-backports.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-backports&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
&lt;br /&gt;
 # rm /etc/apt/sources.list&lt;br /&gt;
Após a configuração vamos instalar alguns pacotes necessários e outros úteis:&lt;br /&gt;
 # apt update &amp;amp;&amp;amp; apt full-upgrade&lt;br /&gt;
 # apt install net-tools nftables htop iotop sipcalc tcpdump curl gnupg rsync wget host dnsutils mtr-tiny bmon sudo tmux whois ethtool dnstop&lt;br /&gt;
&lt;br /&gt;
== Fazendo algum tuning no sistema ==&lt;br /&gt;
Em '''/etc/sysctl.d/100-tuning.conf''' adicionamos essas instruções:&lt;br /&gt;
 net.core.rmem_max = 2147483647&lt;br /&gt;
 net.core.wmem_max = 2147483647&lt;br /&gt;
 net.ipv4.tcp_rmem = 4096 87380 2147483647&lt;br /&gt;
 net.ipv4.tcp_wmem = 4096 65536 2147483647&lt;br /&gt;
 net.netfilter.nf_conntrack_buckets = 512000&lt;br /&gt;
 net.netfilter.nf_conntrack_max = 4096000&lt;br /&gt;
 vm.swappiness=10&lt;br /&gt;
Estamos fazendo algumas melhorias de memória, algumas relacionadas a '''conntrack''' porque se for usar um filtro de pacotes stateful, como o '''Netfilter/IPTables''' ou '''Netfilter/NFTables''', o valor default da tabela é pequeno e dependendo da situação, se estourar essa tabela, as consultas de DNS terão problemas também. O DNS Recursivo não deve ficar aberto para qualquer um na Internet, ele deve ser liberado apenas para seus clientes. Podemos fazer através das ACLs do Unbound e pelo filtro de pacotes. O último parâmetro diz respeito ao uso de swap, por padrão o Debian permite o uso de swap após 40% do uso da memória, nesse caso estamos dizendo para o sistema usar o swap com 90% de uso da memória.&lt;br /&gt;
&lt;br /&gt;
Precisamos adicionar o módulo '''nf_conntrack''' em '''/etc/modules''' para que seja carregado em tempo de boot, senão os parâmetros de '''conntrack''' que colocamos em '''/etc/sysctl.conf''' não serão carregados.&lt;br /&gt;
 # echo nf_conntrack &amp;gt;&amp;gt; /etc/modules&lt;br /&gt;
 # modprobe nf_conntrack&lt;br /&gt;
 # sysctl -p&lt;br /&gt;
&lt;br /&gt;
== Instalando o FRRouting ==&lt;br /&gt;
O FRRouting é o programa que usaremos para fazer os anúncios das nossas loopbacks via OSPF. Nesse documento usaremos a versão 10.x:&lt;br /&gt;
 # apt install frr frr-doc frr-pythontools&lt;br /&gt;
Aconselho depois de instalar os pacotes, marcá-los para não atualizar juntamente com os demais pacotes, isso é para evitar de ocorrer alguma atualização no FRRouting, que torne o serviço instável por algum motivo. Não que isso vá ocorrer, mas é melhor fazer essa atualização quando realmente for necessário.&lt;br /&gt;
 # apt-mark hold frr frr-doc frr-pythontools&lt;br /&gt;
Após esse comando acima, o sistema manterá a instalação original do pacote intacta. Para desbloquear basta executar o comando abaixo:&lt;br /&gt;
 # apt-mark unhold frr frr-doc frr-pythontools&lt;br /&gt;
&lt;br /&gt;
== Removendo o APPARMOR ==&lt;br /&gt;
O '''APPARMOR''' às vezes causa mais problemas que solução e se não for fazer uma completa configuração nele, é melhor desabilitá-lo. Para fazer isso efetivamente, o procedimento é esse abaixo:&lt;br /&gt;
 # mkdir -p /etc/default/grub.d&lt;br /&gt;
 # echo 'GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;$GRUB_CMDLINE_LINUX_DEFAULT apparmor=0&amp;quot;' | tee /etc/default/grub.d/apparmor.cfg&lt;br /&gt;
 # update-grub&lt;br /&gt;
 # reboot&lt;br /&gt;
&lt;br /&gt;
== Instalando o Unbound ==&lt;br /&gt;
Nesse momento ainda não iremos configurar o Unbound, apenas instalar o pacote e acertar o ambiente. Vamos instalar o unbound do backports porque este já possui suporte ao DoH que veremos mais à frente.&lt;br /&gt;
 # apt install unbound dns-root-data&lt;br /&gt;
 # mkdir -p /var/log/unbound&lt;br /&gt;
 # touch /var/log/unbound/unbound.log&lt;br /&gt;
 # chown -R unbound:unbound /var/log/unbound/&lt;br /&gt;
 # systemctl restart unbound&lt;br /&gt;
Configurando o logrotate:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/logrotate.d/unbound&lt;br /&gt;
 /var/log/unbound/unbound.log {&lt;br /&gt;
     rotate 5&lt;br /&gt;
     weekly&lt;br /&gt;
     postrotate&lt;br /&gt;
         unbound-control log_reopen&lt;br /&gt;
     endscript&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
Reiniciando o serviço:&lt;br /&gt;
 # systemctl restart logrotate.service&lt;br /&gt;
&lt;br /&gt;
== Desabilitando THP (Transparente Huge Pages) em arquitetura AMD64 ==&lt;br /&gt;
No Debian o '''THP''' vem habilitado como '''always''' e o '''unbound''' por trabalhar bastante com alterações do cache em memória, isso pode acabar causando um consumo crescente de uso de RAM sem necessidade. É uma boa prática desabilitá-lo com os passos abaixo:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/systemd/system/disable-thp.service&lt;br /&gt;
 [Unit]&lt;br /&gt;
 Description=Desativa Transparent Huge Pages (THP)&lt;br /&gt;
 After=network.target&lt;br /&gt;
 &lt;br /&gt;
 [Service]&lt;br /&gt;
 Type=oneshot&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled&amp;quot;&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/defrag&amp;quot;&lt;br /&gt;
 RemainAfterExit=yes&lt;br /&gt;
 &lt;br /&gt;
 [Install]&lt;br /&gt;
 WantedBy=multi-user.target&lt;br /&gt;
 EOF&lt;br /&gt;
Acima configuramos o serviço '''disable-thp.service''' para desabilitar o '''THP''' e abaixo habilitamos no '''systemd''' e iniciamos:&lt;br /&gt;
 # systemctl daemon-reload&lt;br /&gt;
 # systemctl enable --now disable-thp&lt;br /&gt;
&lt;br /&gt;
== Preparando o monitoramento do seu DNS Recursivo ==&lt;br /&gt;
O monitoramento do seu DNS Recursivo é muito importante e para isso vamos usar um '''template para Zabbix''', que modifiquei juntamente com o seu shell script e que enviará os dados para o seu Zabbix server via '''zabbix-sender'''. O projeto original está aqui '''https://github.com/jeftedelima/Unbound-DNS&amp;lt;nowiki/&amp;gt;.''' O xml alterado está aqui '''https://github.com/gondimcodes/template_zabbix_dns_unbound'''. Embora seja antigo é perfeitamente importável no Zabbix 6.0, por exemplo.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;nowiki/&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Teremos um shell script que você precisará colocar no seu '''/etc/crontab'''. No exemplo abaixo assumi que o shell script está em '''/root/scripts'''. De 5 em 5 minutos os dados serão enviados para o seu Zabbix server.&lt;br /&gt;
 */5 * * * *     root    /root/scripts/unboundSend.sh '''IP_zabbix_server''' '''nome_do_host''' 1&amp;gt; /dev/null&lt;br /&gt;
Na linha acima, troque o '''IP_zabbix_server''' pelo '''IP do seu servidor Zabbix''' e o '''nome_do_host''' pelo '''hostname''' '''do seu DNS Recursivo'''. Você precisará instalar o pacote '''zabbix-sender''' no seu DNS Recursivo pois ele será usado para enviar os dados para o Zabbix server.&lt;br /&gt;
&lt;br /&gt;
Abaixo o '''unboundSend.sh''' também alterado com inclusão de mais dados:&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 #       @Jefte de Lima Ferreira&lt;br /&gt;
 #       jeftedelima at gmail dot com&lt;br /&gt;
 #       CRON Example&lt;br /&gt;
 #       Contributor: Marcelo Gondim - gondim at gmail dot com&lt;br /&gt;
 #       */5   **** root sh /home/dir/unboundSend.sh 192.168.10.1 Unbound 1&amp;gt; /dev/null&lt;br /&gt;
  &lt;br /&gt;
 if [ -z ${1} ] || [ -z ${2} ] ; then&lt;br /&gt;
         echo &amp;quot;You need to specify the IP address of zabbix server and hostname of your DNS Unbound on zabbix&amp;quot;&lt;br /&gt;
         echo &amp;quot;Usage example: ./unboundSend.sh 192.168.10.1 UnboundServer&amp;quot;&lt;br /&gt;
         exit 1&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 # ZABBIX_SERVER IP&lt;br /&gt;
 IP_ZABBIX=$1&lt;br /&gt;
 # NAME Unbound on Zabbix&lt;br /&gt;
 NAME_HOST=$2&lt;br /&gt;
 DIR_TEMP=/var/tmp/&lt;br /&gt;
 FILE=&amp;quot;${DIR_TEMP}dump_unbound_control_stats.txt&amp;quot;&lt;br /&gt;
 unbound-control stats &amp;gt; ${FILE}&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_NUM_QUERIES=$(cat ${FILE} | grep -w 'total.num.queries' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEHITS=$(cat ${FILE} | grep -w 'total.num.cachehits' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEMISS=$(cat ${FILE} | grep -w 'total.num.cachemiss' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_PREFETCH=$(cat ${FILE} | grep -w 'total.num.prefetch' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_RECURSIVEREPLIES=$(cat ${FILE} | grep -w 'total.num.recursivereplies' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_REQ_MAX=$(cat ${FILE} | grep -w 'total.requestlist.max' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_AVG=$(cat ${FILE} | grep -w 'total.requestlist.avg' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_OVERWRITTEN=$(cat ${FILE} | grep -w 'total.requestlist.overwritten' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_EXCEEDED=$(cat ${FILE} | grep -w 'total.requestlist.exceeded' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_ALL=$(cat ${FILE} | grep -w 'total.requestlist.current.all' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_USER=$(cat ${FILE} | grep -w 'total.requestlist.current.user' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_TCPUSAGE=$(cat ${FILE} | grep -w 'total.tcpusage' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_QUERY_TYPE_A=$(cat ${FILE} | grep -w 'num.query.type.A' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NS=$(cat ${FILE} | grep -w 'num.query.type.NS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_MX=$(cat ${FILE} | grep -w 'num.query.type.MX' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TXT=$(cat ${FILE} | grep -w 'num.query.type.TXT' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_PTR=$(cat ${FILE} | grep -w 'num.query.type.PTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_AAAA=$(cat ${FILE} | grep -w 'num.query.type.AAAA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SRV=$(cat ${FILE} | grep -w 'num.query.type.SRV' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SOA=$(cat ${FILE} | grep -w 'num.query.type.SOA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HTTPS=$(cat ${FILE} | grep -w 'num.query.type.HTTPS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TYPE0=$(cat ${FILE} | grep -w 'num.query.type.TYPE0' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_CNAME=$(cat ${FILE} | grep -w 'num.query.type.CNAME' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_WKS=$(cat ${FILE} | grep -w 'num.query.type.WKS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HINFO=$(cat ${FILE} | grep -w 'num.query.type.HINFO' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_X25=$(cat ${FILE} | grep -w 'num.query.type.X25' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NAPTR=$(cat ${FILE} | grep -w 'num.query.type.NAPTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DS=$(cat ${FILE} | grep -w 'num.query.type.DS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DNSKEY=$(cat ${FILE} | grep -w 'num.query.type.DNSKEY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TLSA=$(cat ${FILE} | grep -w 'num.query.type.TLSA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SVCB=$(cat ${FILE} | grep -w 'num.query.type.SVCB' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SPF=$(cat ${FILE} | grep -w 'num.query.type.SPF' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_ANY=$(cat ${FILE} | grep -w 'num.query.type.ANY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_OTHER=$(cat ${FILE} | grep -w 'num.query.type.other' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_ANSWER_RCODE_NOERROR=$(cat ${FILE} | grep -w 'num.answer.rcode.NOERROR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_NXDOMAIN=$(cat ${FILE} | grep -w 'num.answer.rcode.NXDOMAIN' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_SERVFAIL=$(cat ${FILE} | grep -w 'num.answer.rcode.SERVFAIL' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_REFUSED=$(cat ${FILE} | grep -w 'num.answer.rcode.REFUSED' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_nodata=$(cat ${FILE} | grep -w 'num.answer.rcode.nodata' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_secure=$(cat ${FILE} | grep -w 'num.answer.secure' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 #       Sending info to zabbix_server.&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.queries -o $(( ${TOTAL_NUM_QUERIES:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachehits -o $(( ${TOTAL_NUM_CACHEHITS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachemiss -o $(( ${TOTAL_NUM_CACHEMISS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.prefetch -o $(( ${TOTAL_NUM_PREFETCH:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.recursivereplies -o $(( ${TOTAL_NUM_RECURSIVEREPLIES:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.max -o $(( ${TOTAL_REQ_MAX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.avg -o $(( ${TOTAL_REQ_AVG:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.overwritten -o $(( ${TOTAL_REQ_OVERWRITTEN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.exceeded -o $(( ${TOTAL_REQ_EXCEEDED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.all -o $(( ${TOTAL_REQ_CURRENT_ALL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.user -o $(( ${TOTAL_REQ_CURRENT_USER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.tcpusage -o $(( ${TOTAL_TCPUSAGE:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.a -o $(( ${NUM_QUERY_TYPE_A:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ns -o $(( ${NUM_QUERY_TYPE_NS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.mx -o $(( ${NUM_QUERY_TYPE_MX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.txt -o $(( ${NUM_QUERY_TYPE_TXT:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ptr -o $(( ${NUM_QUERY_TYPE_PTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.aaaa -o $(( ${NUM_QUERY_TYPE_AAAA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.srv -o $(( ${NUM_QUERY_TYPE_SRV:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.soa -o $(( ${NUM_QUERY_TYPE_SOA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.https -o $(( ${NUM_QUERY_TYPE_HTTPS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.type0 -o $(( ${NUM_QUERY_TYPE_TYPE0:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.cname -o $(( ${NUM_QUERY_TYPE_CNAME:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.wks -o $(( ${NUM_QUERY_TYPE_WKS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.hinfo -o $(( ${NUM_QUERY_TYPE_HINFO:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.X25 -o $(( ${NUM_QUERY_TYPE_X25:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.naptr -o $(( ${NUM_QUERY_TYPE_NAPTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ds -o $(( ${NUM_QUERY_TYPE_DS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.dnskey -o $(( ${NUM_QUERY_TYPE_DNSKEY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.tlsa -o $(( ${NUM_QUERY_TYPE_TLSA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.svcb -o $(( ${NUM_QUERY_TYPE_SVCB:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.spf -o $(( ${NUM_QUERY_TYPE_SPF:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.any -o $(( ${NUM_QUERY_TYPE_ANY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.other -o $(( ${NUM_QUERY_TYPE_OTHER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NOERROR -o $(( ${NUM_ANSWER_RCODE_NOERROR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NXDOMAIN -o $(( ${NUM_ANSWER_RCODE_NXDOMAIN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.SERVFAIL -o $(( ${NUM_ANSWER_RCODE_SERVFAIL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.REFUSED -o $(( ${NUM_ANSWER_RCODE_REFUSED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.nodata -o $(( ${NUM_ANSWER_RCODE_nodata:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.secure -o $(( ${NUM_ANSWER_secure:-0} / 300 ))&lt;br /&gt;
No Zabbix será registrado dados como esses abaixo e posteriormente pode ser montado um Grafana com eles:&lt;br /&gt;
[[Arquivo:Zabbix dns01.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns02.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns03.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns04.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Mantendo a hora certa ==&lt;br /&gt;
Vamos instalar agora o Chrony para manter a data e hora certas no sistema:&lt;br /&gt;
 # apt install chrony&lt;br /&gt;
Após a instalação do Chrony edite o arquivo /etc/chrony/chrony.conf, comente e a linha abaixo e adicione seus servidores NTP. Caso não tenha servidores NTP, estou colocando os do NIC.br aqui.&lt;br /&gt;
 #pool 2.debian.pool.ntp.org iburst&lt;br /&gt;
 server a.st1.ntp.br iburst nts&lt;br /&gt;
 server b.st1.ntp.br iburst nts&lt;br /&gt;
 server c.st1.ntp.br iburst nts&lt;br /&gt;
 server d.st1.ntp.br iburst nts&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart chronyd.service&lt;br /&gt;
Cheque com o '''chronyc''' se os servidores estão OK:&lt;br /&gt;
 # chronyc sourcestats&lt;br /&gt;
 Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev&lt;br /&gt;
 ==============================================================================&lt;br /&gt;
 a.st1.ntp.br               10   5  155m     -0.027      0.030    -71us    51us&lt;br /&gt;
 b.st1.ntp.br               11   7  344m     +0.068      0.079    +23ms   382us&lt;br /&gt;
 c.st1.ntp.br                6   3  344m     +0.026      0.037   -124us    92us&lt;br /&gt;
 200.20.186.76               9   3  138m     -0.022      0.031   +172us    42us&lt;br /&gt;
&lt;br /&gt;
 # chronyc sources&lt;br /&gt;
 MS Name/IP address         Stratum Poll Reach LastRx Last sample&lt;br /&gt;
 ===============================================================================&lt;br /&gt;
 ^* a.st1.ntp.br                  1  10   377   588   +487us[ +397us] +/-   12ms&lt;br /&gt;
 ^- b.st1.ntp.br                  2  10   377   830    +23ms[  +23ms] +/-   49ms&lt;br /&gt;
 ^+ c.st1.ntp.br                  2  10    21  1038   -147us[ -242us] +/-   17ms&lt;br /&gt;
 ^+ 200.20.186.76                 1  10   377  1032   +381us[ +285us] +/-   15ms&lt;br /&gt;
&lt;br /&gt;
== Configurando o FRRouting ==&lt;br /&gt;
Nesse ponto iremos configurar o '''FRRouting''' para enviar os IPs das '''loopbacks''' e o '''/30''' para o nosso PE do diagrama. Em '''/etc/frr/daemons''' habilite o parâmetro conforme abaixo:&lt;br /&gt;
 ospfd=yes&lt;br /&gt;
 ospf6d=yes&lt;br /&gt;
Edite o arquivo '''/etc/frr/frr.conf''' e deixe com o conteúdo abaixo, para ficar conforme nosso diagrama do projeto. Apenas troque '''&amp;lt;SENHA&amp;gt;''' por uma senha para fechar o OSPF com mais segurança. Essa senha deve ser usada dos dois lados.&lt;br /&gt;
 frr version 10.3&lt;br /&gt;
 frr defaults traditional&lt;br /&gt;
 hostname dns-recursivo-01&lt;br /&gt;
 log syslog informational&lt;br /&gt;
 no ip forwarding&lt;br /&gt;
 no ipv6 forwarding&lt;br /&gt;
 service integrated-vtysh-config&lt;br /&gt;
 !&lt;br /&gt;
 interface ens18&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf message-digest-key 5 md5 &amp;lt;SENHA&amp;gt;&lt;br /&gt;
  ip ospf network point-to-point&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 network point-to-point&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 interface lo&lt;br /&gt;
  description LOOPBACKS&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf passive&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 passive&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf&lt;br /&gt;
  ospf router-id 172.16.0.6&lt;br /&gt;
  area 0.0.0.0 authentication message-digest&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf6&lt;br /&gt;
  ospf6 router-id 172.16.0.6&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart frr.service&lt;br /&gt;
Cheque se está tudo OK com o OSPF e verifique no PE se está recebendo os prefixos anunciados.&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL&lt;br /&gt;
 172.16.0.5     1 Full/-          10m49s            35.310s 172.16.0.5   ens18:172.16.0.6                  0     0     0&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri    DeadTime    State/IfState         Duration I/F[State]&lt;br /&gt;
 172.16.0.5       1    00:00:30     Full/PointToPoint 25d22:53:47 ens18[PointToPoint]&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor detail'&lt;br /&gt;
 &lt;br /&gt;
  Neighbor 172.16.0.5, interface address 172.16.0.5&lt;br /&gt;
     In the area 0.0.0.0 via interface ens18&lt;br /&gt;
     Neighbor priority is 1, State is Full/-, 5 state changes&lt;br /&gt;
     Most recent state change statistics:&lt;br /&gt;
       Progressive change 21w3d15h ago&lt;br /&gt;
     DR is 0.0.0.0, BDR is 0.0.0.0&lt;br /&gt;
     Options 18 *|-|-|EA|-|-|E|-&lt;br /&gt;
     Dead timer due in 34.685s&lt;br /&gt;
     Database Summary List 0&lt;br /&gt;
     Link State Request List 0&lt;br /&gt;
     Link State Retransmission List 0&lt;br /&gt;
     Thread Inactivity Timer on&lt;br /&gt;
     Thread Database Description Retransmision off&lt;br /&gt;
     Thread Link State Request Retransmission on&lt;br /&gt;
     Thread Link State Update Retransmission on&lt;br /&gt;
 &lt;br /&gt;
     Graceful restart Helper info:&lt;br /&gt;
       Graceful Restart HELPER Status : None&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor detail'&lt;br /&gt;
  Neighbor 172.16.0.5%ens18&lt;br /&gt;
     Area 0.0.0.0 via interface ens18 (ifindex 4)&lt;br /&gt;
     His IfIndex: 60 Link-local address: fe80::469b:c1ff:fed6:43ee&lt;br /&gt;
     State Full for a duration of 25d22:57:14&lt;br /&gt;
     His choice of DR/BDR 0.0.0.0/0.0.0.0, Priority 1&lt;br /&gt;
     DbDesc status: Master SeqNum: 0xb94b0000&lt;br /&gt;
     Summary-List: 0 LSAs&lt;br /&gt;
     Request-List: 0 LSAs&lt;br /&gt;
     Retrans-List: 0 LSAs&lt;br /&gt;
     0 Pending LSAs for DbDesc in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSReq in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSAck in Time 00:00:00 [thread off]&lt;br /&gt;
     Authentication header not present&lt;br /&gt;
&lt;br /&gt;
== Configurando o Unbound ==&lt;br /&gt;
Abaixo a configuração que usaremos nos servidores atentando para o detalhe do '''num-threads''', esse deve ter o valor igual ao número de CPUs do servidor.&lt;br /&gt;
&lt;br /&gt;
Também os IPs utilizados em '''outgoing-interface''' que serão diferentes em cada servidor, esses serão os IPs usados para '''recursividade'''. Consulte o manual do Unbound para obter mais informações sobre cada parâmetro listado na configuração.&lt;br /&gt;
&lt;br /&gt;
O tuning no Unbound pode ser alterado conforme abaixo:&lt;br /&gt;
 num-threads = nº CPUs&lt;br /&gt;
 so-reuseport = yes&lt;br /&gt;
 *-slabs = potência de 2 próximo ao num-threads&lt;br /&gt;
 msg-cache-size = 1g (quantidade de memória pra usar de cache)&lt;br /&gt;
 rrset-cache-size = 2 * msg-cache-size&lt;br /&gt;
 outgoing-range = 8192&lt;br /&gt;
 num-queries-per-thread = 4096&lt;br /&gt;
 so-rcvbuf e so-sndbuf = 4m ou 8m para servidores com muita requisição&lt;br /&gt;
Agora vamos criar nosso arquivo de configuração base em '''/etc/unbound/unbound.conf.d/local.conf''':&lt;br /&gt;
 server:&lt;br /&gt;
         verbosity: 1&lt;br /&gt;
         statistics-interval: 0&lt;br /&gt;
         statistics-cumulative: no&lt;br /&gt;
         extended-statistics: yes&lt;br /&gt;
         num-threads: 8&lt;br /&gt;
         serve-expired: yes&lt;br /&gt;
         interface: 127.0.0.1&lt;br /&gt;
         interface: 10.10.10.10&lt;br /&gt;
         interface: 10.10.9.9&lt;br /&gt;
         interface: 172.16.0.6&lt;br /&gt;
         interface: fd00::10:10:10:10&lt;br /&gt;
         interface: fd00::10:10:9:9&lt;br /&gt;
         interface: ::1&lt;br /&gt;
         interface-automatic: no&lt;br /&gt;
         outgoing-interface: 198.18.1.10&lt;br /&gt;
         outgoing-interface: 2001:db8::faca:198:18:1:10&lt;br /&gt;
         outgoing-range: 8192&lt;br /&gt;
         outgoing-num-tcp: 1024&lt;br /&gt;
         incoming-num-tcp: 2048&lt;br /&gt;
         so-rcvbuf: 4m&lt;br /&gt;
         so-sndbuf: 4m&lt;br /&gt;
         so-reuseport: yes&lt;br /&gt;
         edns-buffer-size: 1232&lt;br /&gt;
         msg-cache-size: 512m&lt;br /&gt;
         msg-cache-slabs: 4&lt;br /&gt;
         num-queries-per-thread: 4096&lt;br /&gt;
         rrset-cache-size: 1g&lt;br /&gt;
         rrset-cache-slabs: 4&lt;br /&gt;
         infra-cache-slabs: 4&lt;br /&gt;
         do-ip4: yes&lt;br /&gt;
         do-ip6: yes&lt;br /&gt;
         do-udp: yes&lt;br /&gt;
         do-tcp: yes&lt;br /&gt;
         chroot: &amp;quot;&amp;quot;&lt;br /&gt;
         username: &amp;quot;unbound&amp;quot;&lt;br /&gt;
         directory: &amp;quot;/etc/unbound&amp;quot;&lt;br /&gt;
         logfile: &amp;quot;/var/log/unbound/unbound.log&amp;quot;&lt;br /&gt;
         use-syslog: no&lt;br /&gt;
         log-time-ascii: yes&lt;br /&gt;
         log-queries: no&lt;br /&gt;
         pidfile: &amp;quot;/var/run/unbound.pid&amp;quot;&lt;br /&gt;
         root-hints: &amp;quot;/usr/share/dns/root.hints&amp;quot;&lt;br /&gt;
         hide-identity: yes&lt;br /&gt;
         hide-version: yes&lt;br /&gt;
         unwanted-reply-threshold: 10000000&lt;br /&gt;
         prefetch: yes&lt;br /&gt;
         prefetch-key: yes&lt;br /&gt;
         rrset-roundrobin: yes&lt;br /&gt;
         minimal-responses: yes&lt;br /&gt;
         module-config: &amp;quot;respip validator iterator&amp;quot;&lt;br /&gt;
         val-clean-additional: yes&lt;br /&gt;
         val-log-level: 1&lt;br /&gt;
         key-cache-slabs: 4&lt;br /&gt;
         deny-any: yes&lt;br /&gt;
         cache-min-ttl: 60&lt;br /&gt;
         key-cache-size: 128m&lt;br /&gt;
         neg-cache-size: 64m&lt;br /&gt;
         cache-max-ttl: 86400&lt;br /&gt;
         infra-cache-numhosts: 100000&lt;br /&gt;
         access-control: 198.18.0.0/22 allow&lt;br /&gt;
         access-control: 2001:db8::/32 allow&lt;br /&gt;
  &lt;br /&gt;
 rpz:&lt;br /&gt;
   name: rpz.block.host.local.zone&lt;br /&gt;
   zonefile: /etc/unbound/rpz.block.hosts.zone&lt;br /&gt;
   rpz-action-override: nxdomain&lt;br /&gt;
  &lt;br /&gt;
 python:&lt;br /&gt;
  &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;.&amp;quot;&lt;br /&gt;
     master: &amp;quot;b.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;c.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;d.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;f.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;g.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;k.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/root.zone&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;arpa.&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/arpa.zone&amp;quot;&lt;br /&gt;
No parâmetro '''interface''' colocamos os IPs que serão usados para consulta dos clientes como o '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9'''. Ali repare que coloquei também o IP privado '''172.16.0.6''', isso porque cada servidor terá o seu IP privado e este deve ser usado pelo seu sistema de monitoramento para checar cada servidor. No '''outgoing-interface''' teremos os IPs, tanto '''IPv4''' quanto '''IPv6''', para que seja feita a recursividade na Internet utilizando eles. Não tem '''IPv6''' ainda na sua rede? Dê uma olhada nesse artigo. Outro parâmetro importante é o '''access-control''' e é através dele que liberamos os prefixos IP para consultarem no nosso DNS Recursivo. No exemplo estou liberando todo o prefixo '''198.18.0.0/22''' e o prefixo '''2001:db8::/32'''. Além da ACL no Unbound, recomendo que crie um filtro de pacotes com iptables ou nftables protegendo seu sistema e liberando as portas '''53/UDP''', '''53/TCP,'''  '''443/TCP e 853/TCP''' apenas para seus clientes. Falarei sobre a '''443/TCP e 853/TCP''' mais para frente nessa mesma documentação.&lt;br /&gt;
&lt;br /&gt;
Agora criaremos o arquivo '''RPZ''' ('''Response Policy Zones'''). Esse arquivo contém os sites que serão bloqueados via '''&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; Recursivo'''. São aqueles sites que às vezes você recebe um Ofício da Justiça solicitando o bloqueio deles. Não entrarei no mérito da efetividade desses bloqueios, porque muitos de vocês sabem que tecnicamente, existem formas de se fazer um bypass através desses bloqueios. Contudo vamos deixar nosso ambiente preparado para esses bloqueios e por isso crie o arquivo '''/etc/unbound/rpz.block.hosts.zone''' com esse conteúdo de exemplo:&lt;br /&gt;
 $TTL 2h&lt;br /&gt;
 @ IN SOA localhost. root.localhost. (2 6h 1h 1w 2h)&lt;br /&gt;
   IN NS  localhost.&lt;br /&gt;
 ; RPZ manual block hosts&lt;br /&gt;
 *.josedascoves.com CNAME .&lt;br /&gt;
 josedascoves.com CNAME .&lt;br /&gt;
No exemplo acima estamos bloqueando qualquer consulta de DNS para '''josedascoves.com''' ou qualquer coisa '''.josedascoves.com'''.&lt;br /&gt;
&lt;br /&gt;
Para testar podemos fazer assim do próprio servidor:&lt;br /&gt;
 # host josedascoves.com ::1&lt;br /&gt;
 Using domain server:&lt;br /&gt;
 Name: ::1&lt;br /&gt;
 Address: ::1#53&lt;br /&gt;
 Aliases:&lt;br /&gt;
 &lt;br /&gt;
 Host josedascoves.com not found: 3(NXDOMAIN)&lt;br /&gt;
Se a resposta for '''NXDOMAIN''' então está funcionando o bloqueio. Para incluir novos bloqueios basta adicionar os domínios, um abaixo do outro, conforme o exemplo que coloquei no arquivo RPZ.&lt;br /&gt;
&lt;br /&gt;
== Acertando o resolv.conf ==&lt;br /&gt;
Vamos modificar nosso /etc/resolv.conf para utilizar DNS externo. Sim você deve estar se perguntando em qual situação isso seria utilizado. Primeiro entenda que o Unbound não irá utilizar o DNS externo para fazer as consultas na Internet e sim, qualquer teste que você faça do servidor precisará apontar para o Unbound usando os IPs '''127.0.0.1''' ou '''::1'''. Faremos isso pela seguinte situação: imagine que o daemon unbound morreu mas você ainda continua com conectividade na Internet. Você conseguiria acessar qualquer local na Internet através do IP mas não através do hostname porque não conseguiria resolver nomes, seu unbound estaria fora do ar. Imagine ainda que você gostaria que seu servidor te avisasse do problema via Telegram ou e-mail. Por isso estamos utilizando um DNS externo no '''/etc/resolv.conf''', apenas para essas situações. Se você não quiser utilizar desse recurso, pode usar o '''127.0.0.1''' e '''::1''' no lugar.&lt;br /&gt;
 nameserver 8.8.8.8&lt;br /&gt;
 nameserver 8.8.4.4&lt;br /&gt;
 nameserver 2001:4860:4860::8888&lt;br /&gt;
&lt;br /&gt;
== Script de teste de recursividade ==&lt;br /&gt;
Estamos montando uma '''Rede de DNS Recursivo Anycast''', então é muito importante que você monitore essa rede para saber se algum node morreu e iniciar o troubleshooting, resolver o problema e levantar o sistema novamente. Tudo isso é importante mas o cliente não deve ficar esperando até você resolver o problema, seu sistema precisa ser inteligente o suficiente para se remover da Rede quando tiver um problema e se inserir novamente, quando o problema estiver sido solucionado. Se você montar uma Rede de DNS e um dos nodes apresentar algum problema, todos os clientes atendidos por aquele node migrarão automaticamente e transparentemente para outro '''DNS Recursivo Anycast''' mais próximo. Isso se chama '''disponibilidade'''.&lt;br /&gt;
&lt;br /&gt;
O script '''/root/scripts/checa_dns.sh''' abaixo tem a função de fazer os testes de recursividade e checar se o daemon do unbound continua rodando. Se algo acontecer, ele para o anúncio do '''10.10.10.10''' e '''10.10.9.9''' e retorna eles quando tudo estiver resolvido.&lt;br /&gt;
 # mkdir /root/scripts&lt;br /&gt;
&lt;br /&gt;
 #!/usr/bin/env bash&lt;br /&gt;
 #Script para teste de DNS v2.1&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 #Informe um domínio por linha:&lt;br /&gt;
 dominios_testar=(&lt;br /&gt;
 www.google.com&lt;br /&gt;
 www.terra.com.br&lt;br /&gt;
 www.uol.com.br&lt;br /&gt;
 www.globo.com&lt;br /&gt;
 www.facebook.com&lt;br /&gt;
 www.youtube.com&lt;br /&gt;
 www.twitch.com&lt;br /&gt;
 www.discord.com&lt;br /&gt;
 www.debian.org&lt;br /&gt;
 www.redhat.com&lt;br /&gt;
 )&lt;br /&gt;
 corte_taxa_falha=100 #Porcentagem de falha para executar uma ação&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 remove_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; != &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no description' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME morreu!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 adiciona_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; == &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'description LOOPBACKS' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME retornou do inferno!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
 if [ $? -ne 0 ]; then&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME morreu DNS mas tentando levantar!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    systemctl restart unbound&lt;br /&gt;
    systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
    if [ $? -ne 0 ]; then&lt;br /&gt;
       remove_ospf&lt;br /&gt;
       exit&lt;br /&gt;
    fi&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME servico DNS voltou mas tinha morrido!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 qt_falhas=0&lt;br /&gt;
 qt_total=&amp;quot;${#dominios_testar[@]}&amp;quot;&lt;br /&gt;
 echo &amp;quot;total_dominios: $qt_total&amp;quot;&lt;br /&gt;
 for site in &amp;quot;${dominios_testar[@]}&amp;quot;&lt;br /&gt;
 do&lt;br /&gt;
   unbound-control flush $site &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   resolver=&amp;quot;127.0.0.1&amp;quot;&lt;br /&gt;
   echo -e &amp;quot; - dominio $site - $resolver - \c&amp;quot;&lt;br /&gt;
   host $site $resolver &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   if [ $? -ne 0 ]; then&lt;br /&gt;
      ((qt_falhas++))&lt;br /&gt;
      echo -e &amp;quot;[Falhou]&amp;quot;&lt;br /&gt;
   else&lt;br /&gt;
      echo -e &amp;quot;[OK]&amp;quot;&lt;br /&gt;
   fi&lt;br /&gt;
 done&lt;br /&gt;
  &lt;br /&gt;
 taxa_falha=$((qt_falhas*100/qt_total))&lt;br /&gt;
 echo &amp;quot;Falhas $qt_falhas/$qt_total ($taxa_falha%)&amp;quot;&lt;br /&gt;
  &lt;br /&gt;
 if [ &amp;quot;$taxa_falha&amp;quot; -ge &amp;quot;$corte_taxa_falha&amp;quot; ]; then&lt;br /&gt;
    remove_ospf&lt;br /&gt;
    exit&lt;br /&gt;
 fi&lt;br /&gt;
 adiciona_ospf&lt;br /&gt;
Se rodarmos o script manualmente veremos isto:&lt;br /&gt;
 # /root/scripts/checa_dns.sh&lt;br /&gt;
 total_dominios: 10&lt;br /&gt;
  - dominio www.google.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.terra.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.uol.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.globo.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.facebook.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.youtube.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.twitch.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.discord.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.debian.org - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.redhat.com - 127.0.0.1 - [OK]&lt;br /&gt;
 Falhas 0/10 (0%)&lt;br /&gt;
Se acontecer 100% de falhas o script irá remover os anúncios do OSPF. Se o daemon do unbound morrer, ele tentará reiniciá-lo. Se tudo normalizar o script irá retornar os anúncios para o OSPF. Deixei comentado no script as partes que enviariam uma notificação para o Telegram. Existem diversas documentações sobre isso na Internet, eu mesmo tenho uma. Assim que eu publicar aqui, atualizo essa documentação e sinta-se à vontade de modificar como desejar.&lt;br /&gt;
 # chmod 700 /root/scripts/checa_dns.sh&lt;br /&gt;
Adicione a linha abaixo em seu '''/etc/crontab''':&lt;br /&gt;
 */1 *   * * *   root    /root/scripts/checa_dns.sh&lt;br /&gt;
&lt;br /&gt;
== Habilitando o DoH (&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; over HTTPS) - opcional ==&lt;br /&gt;
Para habilitar o '''DoH''' no Unbound é bem simples. O recurso do '''DoH''' vem para trazer mais segurança e privacidade para o usuário. É um recurso muito pouco utilizado ainda mas que seu cliente pode vir a pedir algum dia.&lt;br /&gt;
&lt;br /&gt;
Você precisará gerar certificados SSL legítimos e para isso você poderá usar o '''Let's Encrypt''' só que de uma forma não tão convencional.&lt;br /&gt;
&lt;br /&gt;
Na sequência vamos instalar o Let's Encrypt para gerarmos nosso certificado SSL:&lt;br /&gt;
 # apt install letsencrypt&lt;br /&gt;
Escolha um '''hostname''' para ser usado no nosso '''DoH''' e aponte ele no seu DNS Autoritativo para seus IPs 10.10.10.10 e 10.10.9.9. Aqui vamos usar o seguinte como exemplo: '''doh.brasilpeeringforum.org'''. Para gerarmos nosso certificado iremos usar o tipo '''DNS-01''', ele não necessita que tenhamos um servidor web rodando no servidor e nem tão pouco levanta um serviço na porta 80 para checar o hostname. Ele utiliza o DNS como validador e vai te solicitar que crie um registro '''CNAME''' no seu '''DNS Autoritativo''' para provar que você tem o controle sobre aquele hostname. Antes disso vamos instalar um programa em Python para podermos automatizar nossa renovação de certificado no futuro. Esse programa se encontra '''[https://github.com/joohoi/acme-dns-certbot-joohoi/raw/master/acme-dns-auth.py aqui]''' mas vou deixá-lo abaixo já modificado o interpretador.&lt;br /&gt;
&lt;br /&gt;
Crie o arquivo '''/etc/letsencrypt/acme-dns-auth.py''' com o conteúdo abaixo:&lt;br /&gt;
 #!/usr/bin/env python3&lt;br /&gt;
 import json&lt;br /&gt;
 import os&lt;br /&gt;
 import requests&lt;br /&gt;
 import sys&lt;br /&gt;
 &lt;br /&gt;
 ### EDIT THESE: Configuration values ###&lt;br /&gt;
 &lt;br /&gt;
 # URL to acme-dns instance&lt;br /&gt;
 ACMEDNS_URL = &amp;quot;&amp;lt;nowiki&amp;gt;https://auth.acme-dns.io&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
 # Path for acme-dns credential storage&lt;br /&gt;
 STORAGE_PATH = &amp;quot;/etc/letsencrypt/acmedns.json&amp;quot;&lt;br /&gt;
 # Whitelist for address ranges to allow the updates from&lt;br /&gt;
 # Example: ALLOW_FROM = [&amp;quot;192.168.10.0/24&amp;quot;, &amp;quot;::1/128&amp;quot;]&lt;br /&gt;
 ALLOW_FROM = []&lt;br /&gt;
 # Force re-registration. Overwrites the already existing acme-dns accounts.&lt;br /&gt;
 FORCE_REGISTER = False&lt;br /&gt;
 &lt;br /&gt;
 ###   DO NOT EDIT BELOW THIS POINT   ###&lt;br /&gt;
 ###         HERE BE DRAGONS          ###&lt;br /&gt;
 &lt;br /&gt;
 DOMAIN = os.environ[&amp;quot;CERTBOT_DOMAIN&amp;quot;]&lt;br /&gt;
 if DOMAIN.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
     DOMAIN = DOMAIN[2:]&lt;br /&gt;
 VALIDATION_DOMAIN = &amp;quot;_acme-challenge.&amp;quot;+DOMAIN&lt;br /&gt;
 VALIDATION_TOKEN = os.environ[&amp;quot;CERTBOT_VALIDATION&amp;quot;]&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 class AcmeDnsClient(object):&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
     Handles the communication with ACME-DNS API&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
     def __init__(self, acmedns_url):&lt;br /&gt;
         self.acmedns_url = acmedns_url&lt;br /&gt;
 &lt;br /&gt;
     def register_account(self, allowfrom):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Registers a new ACME-DNS account&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
         if allowfrom:&lt;br /&gt;
             # Include whitelisted networks to the registration call&lt;br /&gt;
             reg_data = {&amp;quot;allowfrom&amp;quot;: allowfrom}&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;,&lt;br /&gt;
                                 data=json.dumps(reg_data))&lt;br /&gt;
         else:&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;)&lt;br /&gt;
         if res.status_code == 201:&lt;br /&gt;
             # The request was successful&lt;br /&gt;
             return res.json()&lt;br /&gt;
         else:&lt;br /&gt;
             # Encountered an error&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to register a new acme-dns &amp;quot;&lt;br /&gt;
                    &amp;quot;account. HTTP status {}, Response body: {}&amp;quot;)&lt;br /&gt;
             print(msg.format(res.status_code, res.text))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def update_txt_record(self, account, txt):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Updates the TXT challenge record to ACME-DNS subdomain.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         update = {&amp;quot;subdomain&amp;quot;: account['subdomain'], &amp;quot;txt&amp;quot;: txt}&lt;br /&gt;
         headers = {&amp;quot;X-Api-User&amp;quot;: account['username'],&lt;br /&gt;
                    &amp;quot;X-Api-Key&amp;quot;: account['password'],&lt;br /&gt;
                    &amp;quot;Content-Type&amp;quot;: &amp;quot;application/json&amp;quot;}&lt;br /&gt;
         res = requests.post(self.acmedns_url+&amp;quot;/update&amp;quot;,&lt;br /&gt;
                             headers=headers,&lt;br /&gt;
                             data=json.dumps(update))&lt;br /&gt;
         if res.status_code == 200:&lt;br /&gt;
             # Successful update&lt;br /&gt;
             return&lt;br /&gt;
         else:&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to update TXT record in &amp;quot;&lt;br /&gt;
                    &amp;quot;acme-dns. \n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request headers:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request body:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response HTTP status: {}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response body: {}&amp;quot;)&lt;br /&gt;
             s_headers = json.dumps(headers, indent=2, sort_keys=True)&lt;br /&gt;
             s_update = json.dumps(update, indent=2, sort_keys=True)&lt;br /&gt;
             s_body = json.dumps(res.json(), indent=2, sort_keys=True)&lt;br /&gt;
             print(msg.format(s_headers, s_update, res.status_code, s_body))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
 class Storage(object):&lt;br /&gt;
     def __init__(self, storagepath):&lt;br /&gt;
         self.storagepath = storagepath&lt;br /&gt;
         self._data = self.load()&lt;br /&gt;
 &lt;br /&gt;
     def load(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Reads the storage content from the disk to a dict structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         data = dict()&lt;br /&gt;
         filedata = &amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             with open(self.storagepath, 'r') as fh:&lt;br /&gt;
                 filedata = fh.read()&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             if os.path.isfile(self.storagepath):&lt;br /&gt;
                 # Only error out if file exists, but cannot be read&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage file exists but cannot be read&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         try:&lt;br /&gt;
             data = json.loads(filedata)&lt;br /&gt;
         except ValueError:&lt;br /&gt;
             if len(filedata) &amp;gt; 0:&lt;br /&gt;
                 # Storage file is corrupted&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage JSON is corrupted&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         return data&lt;br /&gt;
 &lt;br /&gt;
     def save(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Saves the storage content to disk&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         serialized = json.dumps(self._data)&lt;br /&gt;
         try:&lt;br /&gt;
             with os.fdopen(os.open(self.storagepath,&lt;br /&gt;
                                    os.O_WRONLY | os.O_CREAT, 0o600), 'w') as fh:&lt;br /&gt;
                 fh.truncate()&lt;br /&gt;
                 fh.write(serialized)&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             print(&amp;quot;ERROR: Could not write storage file.&amp;quot;)&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def put(self, key, value):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Puts the configuration value to storage and sanitize it&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         # If wildcard domain, remove the wildcard part as this will use the&lt;br /&gt;
         # same validation record name as the base domain&lt;br /&gt;
         if key.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
             key = key[2:]&lt;br /&gt;
         self._data[key] = value&lt;br /&gt;
 &lt;br /&gt;
     def fetch(self, key):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Gets configuration value from storage&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             return self._data[key]&lt;br /&gt;
         except KeyError:&lt;br /&gt;
             return None&lt;br /&gt;
 &lt;br /&gt;
 if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
     # Init&lt;br /&gt;
     client = AcmeDnsClient(ACMEDNS_URL)&lt;br /&gt;
     storage = Storage(STORAGE_PATH)&lt;br /&gt;
 &lt;br /&gt;
     # Check if an account already exists in storage&lt;br /&gt;
     account = storage.fetch(DOMAIN)&lt;br /&gt;
     if FORCE_REGISTER or not account:&lt;br /&gt;
         # Create and save the new account&lt;br /&gt;
         account = client.register_account(ALLOW_FROM)&lt;br /&gt;
         storage.put(DOMAIN, account)&lt;br /&gt;
         storage.save()&lt;br /&gt;
 &lt;br /&gt;
         # Display the notification for the user to update the main zone&lt;br /&gt;
         msg = &amp;quot;Please add the following CNAME record to your main DNS zone:\n{}&amp;quot;&lt;br /&gt;
         cname = &amp;quot;{} CNAME {}.&amp;quot;.format(VALIDATION_DOMAIN, account[&amp;quot;fulldomain&amp;quot;])&lt;br /&gt;
         print(msg.format(cname))&lt;br /&gt;
 &lt;br /&gt;
     # Update the TXT record in acme-dns instance&lt;br /&gt;
     client.update_txt_record(account, VALIDATION_TOKEN)&lt;br /&gt;
&lt;br /&gt;
 # chmod +x /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
Usaremos a seguinte instrução para criar nosso certificado:&lt;br /&gt;
 # certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d doh.brasilpeeringforum.org&lt;br /&gt;
 Saving debug log to /var/log/letsencrypt/letsencrypt.log&lt;br /&gt;
 Plugins selected: Authenticator manual, Installer None&lt;br /&gt;
 Cert is due for renewal, auto-renewing...&lt;br /&gt;
 Renewing an existing certificate for doh.brasilpeeringforum.org&lt;br /&gt;
 Performing the following challenges:&lt;br /&gt;
 dns-01 challenge for doh.brasilpeeringforum.org&lt;br /&gt;
 Running manual-auth-hook command: /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
 Output from manual-auth-hook command acme-dns-auth.py:&lt;br /&gt;
 Please add the following CNAME record to your main DNS zone:&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
 &lt;br /&gt;
 Waiting for verification...&lt;br /&gt;
 &lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Challenges loaded. Press continue to submit to CA. Pass &amp;quot;-v&amp;quot; for more info about&lt;br /&gt;
 challenges.&lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Press Enter to Continue&lt;br /&gt;
Nesse momento você cria o registro '''CNAME''' no seu DNS Autoritativo conforme ele solicitou: '''_acme-challenge.doh.brasilpeeringforum.org IN CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.''' e somente depois de criado e checado no DNS, você pressiona o '''Enter''' para continuar. Você pode checar dessa forma:&lt;br /&gt;
 # host -t cname _acme-challenge.doh.brasilpeeringforum.org&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org is an alias for b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
Para que nosso certificado seja automaticamente renovado colocaremos no '''/etc/crontab''' a seguinte linha abaixo:&lt;br /&gt;
 00 00   1 * *   root    /usr/bin/certbot -q renew --deploy-hook &amp;quot;/usr/sbin/unbound-control reload_keep_cache&amp;quot;&lt;br /&gt;
Acima temos a instrução para renovação automática do certificado. Repare que você vai precisar também copiar esse certificado para seus outros servidores, escolha um servidor para manter o certificado sempre atualizado e crie um script que faça a mesma cópia remotamente para os outros servidores. O '''scp''' e o '''rsync''' são seus aliados nisso.&lt;br /&gt;
&lt;br /&gt;
=== Configurando o Unbound ===&lt;br /&gt;
Em nosso '''/etc/unbound/unbound.conf.d/local.conf''', adicionaremos no bloco &amp;quot;'''server:'''&amp;quot; o seguinte:&lt;br /&gt;
 interface: 10.10.10.10@443 &lt;br /&gt;
 interface: 10.10.9.9@443&lt;br /&gt;
 interface: fd00::10:10:10:10@443&lt;br /&gt;
 interface: fd00::10:10:9:9@443&lt;br /&gt;
 tls-service-key: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/privkey.pem&amp;quot; &lt;br /&gt;
 tls-service-pem: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/fullchain.pem&amp;quot;&lt;br /&gt;
Para usar o recurso do '''DoH''' você precisará habilitar o recurso no seu navegador e informar a URL. Vou colocar o exemplo do '''Google Chrome''': Digite '''chrome://settings/security?search=dns''' no seu Chrome e ative '''Usar DNS seguro''', selecione '''Personalizado''' e adicione nossa URL:&lt;br /&gt;
[[Arquivo:Doh bpf2.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Finalizando ==&lt;br /&gt;
Aqui finalizamos nosso projeto para uma Rede de DNS(s) Recursivos Anycast com Hyperlocal. Esse projeto é escalável, seguro, resiliente e você entregará muito mais qualidade de Internet para o seu cliente. Pare de entregar o '''8.8.8.8''' para os seus clientes, você está contribuindo para uma Internet mais lenta, sem a qualidade que o seu cliente merece. Investi meu tempo, que é muito pouco, para deixar esse documento para a comunidade, para você melhorar o seu ISP, para dar um UP! nele, então vamos começar 2023 com o pé direito. O que acha?&lt;br /&gt;
&lt;br /&gt;
Como prova de conceito, uma imagem abaixo onde temos uma Rede em produção de DNS(s) Recursivos Anycast e apontando exatamente o momento em que houve alguma situação que fez com que as queries de DNS, convergissem de um node para outro, de forma transparente e automática para o cliente. Podemos notar também que ao ser resolvido o problema, o tráfego retornou para o seu node correto:&lt;br /&gt;
[[Arquivo:Convergencia.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== KINDNS (Stands for Knowledge-Sharing and Instantiating Norms for DNS and Naming Security) ==&lt;br /&gt;
Achou que havia terminado? Agora que você tem a capacidade de montar uma '''Rede de DNS Recursivo''' com todas essas features acima, com todas as ferramentas que foram comentadas, o que acha de certificar o que fez?&lt;br /&gt;
&lt;br /&gt;
Assim como o [https://www.manrs.org/ MANRS] veio para certificar nosso sistema de roteamento na Internet, agora temos o [https://kindns.org/ KINDNS] para certificar que nossos sistemas de DNS estão bem feitos e dentro dos padrões de segurança. Existem '''7 ações''' que podem ser certificadas para nossos DNS Recursivos e estão aqui em https://kindns.org/shared-private-resolvers/. Com essa nossa documentação, se bem aplicada, você pode se candidatar ao KINDNS e ter seu ASN listado aqui https://kindns.org/participants/&lt;br /&gt;
&lt;br /&gt;
Obter e manter o '''MANRS''' e '''KINDNS''' demonstra seu compromisso com as Boas Práticas, contribui para termos uma '''Internet''' mais segura e te abre portas para novos negócios que possam exigir essas conformidades.&lt;br /&gt;
&lt;br /&gt;
Autor: [[Usuário:Gondim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Infraestrutura]]&lt;br /&gt;
__FORCARTDC__&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3983</id>
		<title>DNS Recursivo Anycast Hyperlocal</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3983"/>
		<updated>2025-11-22T16:56:48Z</updated>

		<summary type="html">&lt;p&gt;Gondim: atualização&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
==Introdução==&lt;br /&gt;
Você sabe como funciona a Internet? Essa é uma pergunta que meu amigo '''Thiago Ayub''' sempre faz aos seus candidatos à vagas de emprego e não importa o quanto tenham de experiência em '''Engenharia de Redes''', todos sempre travam nesse momento. Todos estão sempre prontos e preparados para resolver os problemas mais cabeludos em '''BGP''', '''OSPF''', '''MPLS''', etc mas travam com essa simples pergunta. Para contextualizar e visualizarmos melhor vamos nos atentar à imagem abaixo e uma explicação simplificada de como funciona:&lt;br /&gt;
[[Arquivo:Dns hierarquia.png|esquerda|commoldura]]&lt;br /&gt;
Tudo começa com um usuário sentado confortavelmente e querendo acessar um conteúdo disponível na Internet. Ele digita em seu navegador preferido a URL: '''&amp;lt;nowiki&amp;gt;https://wiki.brasilpeeringforum.org&amp;lt;/nowiki&amp;gt;''',&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;1)&amp;lt;/big&amp;gt;''' &amp;lt;big&amp;gt;O&amp;lt;/big&amp;gt; &amp;lt;big&amp;gt;navegador irá requisitar do '''DNS Recursivo''' utilizado pelo usuário, o '''endereço IP''' que responde pelo nome '''wiki.'''&amp;lt;/big&amp;gt;'''brasilpeeringforum.org'''&amp;lt;big&amp;gt;. Isso porque todos os acessos se dão na Internet através do '''endereço''' '''IP''' e não através do '''nome'''. Imaginem se tivéssemos que decorar os endereços IPs de todos os sites e serviços que quiséssemos acessar na Internet?&amp;lt;/big&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;big&amp;gt;'''2)''' Nosso DNS Recursivo checa se a informação consta em seu cache.&amp;lt;/big&amp;gt; Se a informação existir ela é devolvida ao navegador do usuário e aí este consegue acessar o site.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Do contrário o DNS Recursivo pergunta ao '''Root Server''' quem é o '''TLD (Top Level Domain)''' responsável para atender a requisição. &lt;br /&gt;
&lt;br /&gt;
'''4)''' O '''Root Server''' informa ao DNS Recursivo o endereço do '''TLD responsável'''. No Brasil o '''TLD''' responsável pelo '''.br''' seria o '''Registro.br'''.&lt;br /&gt;
&lt;br /&gt;
'''5)''' O DNS Recursivo pergunta ao '''TLD''' sobre '''wiki.brasilpeeringforum.org''' e este responde com os endereços IP dos '''DNS Autoritativos''' responsáveis pelo domínio '''brasilpeeringforum.org.'''&lt;br /&gt;
&lt;br /&gt;
'''6)''' O DNS Recursivo pergunta aos '''DNS Autoritativos''' pelo '''wiki.brasilpeeringforum.org''' e este responde com o '''endereço IP'''.&lt;br /&gt;
&lt;br /&gt;
'''7)''' Por último o DNS Recursivo devolve a informação para o navegador do usuário.&lt;br /&gt;
&lt;br /&gt;
Como que se dá a comunicação entre os '''DNS(s) Recursivos, Root Servers, TLDs''' e '''Autoritativos'''? Como que o navegador do usuário, após receber o IP do site, consegue chegar no servidor que tem o conteúdo? Isso só é possível devido ao protocolo chamado '''BGP (Border Gateway Protocol)''', todos os caminhos que conhecemos como rotas de destino, são anunciadas por milhares de participantes na '''Internet''' conhecidos como '''AS (Autonomous System)''', esses participantes se interligam para disponibilizar conteúdos e acessos pelo mundo aos milhares de usuários. É uma imensa rede colaborativa formada por Empresas, Universidades, Governos e todos que queiram se interconectar. Percebam que sem o '''BGP''', que serve de caminho para chegarmos nos conteúdos e sem o '''DNS (Domain Name System)''' para traduzir o nome para o endereço IP, a '''Internet''' não funcionaria e por isso precisamos cuidar muito bem desses dois serviços.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Mas não acaba por aí. O '''DNS Recursivo''' tem um papel muito importante para o Provedor de Internet e que envolve segurança, qualidade de acesso à Internet e a disponibilidade do serviço entregue ao cliente. Quando bem configurado acelera as consultas dos acessos graças ao seu cache interno, mas para que isso seja percebido pelo assinante, é necessário que esteja o mais próximo possível do seu cliente.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Um erro que destrói a qualidade do nosso serviço ==&lt;br /&gt;
Um erro muito comum que muitas operadoras cometem é utilizar DNS Recursivo externo, como o '''8.8.8.8''', '''1.1.1.1''' e outros, para seus clientes. Quanto mais próximo dos seus clientes, mais qualidade de serviço estará entregando a eles. Conteúdos serão entregues mais rapidamente pois serão resolvidos e armazenados em caches locais e não consultados remotamente na Internet. Para falar mais sobre isso, te convido leitor desse documento, que assista essa palestra do '''Thiago Ayub''' no '''GTER 51/GTS 37''' (2022) '''8.888 MOTIVOS PARA NÃO USAR DNS RECURSIVO EXTERNO EM SEU AS''': https://www.youtube.com/watch?v=Rsvpu5uF2Io&lt;br /&gt;
&lt;br /&gt;
== Objetivo ==&lt;br /&gt;
O objetivo desta documentação não é te ensinar tudo sobre '''DNS''', '''BGP''', '''OSPF''' e nem tão pouco sobre GNU/Linux e sim te mostrar um exemplo de servidor DNS Recursivo implementado pensando em segurança, qualidade e resiliência. Usaremos em todas as nossas documentações o [https://www.debian.org/ Debian GNU/Linux], por ser uma distribuição que considero uma obra de arte criada por uma enorme comunidade séria, com vasta experiência de anos, qualidade no empacotamento dos programas, estável e com uma equipe de segurança excelente e ativa. Caso você leitor, utilize alguma outra distribuição GNU/Linux, todo conteúdo apresentado aqui pode ser aplicado em outras distros, desde que respeitando as particularidades de cada uma.&lt;br /&gt;
&lt;br /&gt;
Aqui construiremos um sistema do tipo '''Anycast''', ou seja, terás o serviço rodando em diversas localidades da sua Rede utilizando o mesmo endereçamento IP e que atenderá seu cliente mais próximo. Em caso de falhas, seus clientes automaticamente e de forma transparente continuarão consultando o DNS mais próximo deles. Para que ele funcione dessa forma você precisará ter uma '''Rede OSPF''' implementada no seu Provedor Internet ou algum outro protocolo como por exemplo o '''ISIS,''' mas esse documento não irá abordar o '''ISIS'''. Também utilizaremos o '''Hyperlocal''' como recurso adicional para gerar algumas proteções de segurança e velocidade na resposta relacionada aos servidores de DNS Raiz da Internet.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
Para exemplificar nosso servidor de DNS Recursivo, usaremos como base das explicações um diagrama demonstrando o uso do DNS Recursivo em uma Rede fictícia. Adotaremos IPs privados e reservados para demonstrar todo o ambiente do Provedor de Internet.&lt;br /&gt;
[[Arquivo:Recursivo99.png|esquerda|miniaturadaimagem|695x695px]]&lt;br /&gt;
Nesse diagrama podemos observar alguns detalhes técnicos como por exemplo: existem '''3 servidores de DNS Recursivo''' posicionados em locais diferentes, que poderiam estar em bairros diferentes e até em cidades diferentes. Em cada servidor teremos '''2 loopbacks''' com os IPs:&lt;br /&gt;
&lt;br /&gt;
'''10.10.10.10/32 - fd00::10:10:10:10/128'''&lt;br /&gt;
&lt;br /&gt;
'''10.10.9.9/32 - fd00::10:10:9:9/128'''&lt;br /&gt;
&lt;br /&gt;
Esses IPs serão entregues pelos concentradores '''PPPoE''' ou '''IPoE''' ('''BNG''') para seus clientes como '''DNS primário''' e '''secundário'''. Podemos usar IPs privados como DNS primário e secundário em um ambiente real? Sim podemos, desde que não sejam IPs que possam ter problemas com as redes privadas dos clientes. Ex.: rede do cliente usando '''192.168.0.0/24'''. Se entregarmos o DNS sendo '''192.168.0.10''' e '''192.168.0.20''' teremos problemas e o cliente ficará sem Internet, porque '''192.168.0.10''' e '''192.168.0.20''' fazem parte da rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
Agora entregando '''10.10.10.10,''' '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9''' não teríamos problemas com a rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
'''Motivos para usarmos IPs privados:'''&lt;br /&gt;
* O principal motivo está relacionado com a segurança, uma vez que sendo um IP privado, não pode sofrer ataques DDoS direcionados diretamente para ele, vindos da Internet.&lt;br /&gt;
* Nem mesmo o cliente da sua rede conhece os '''IPs públicos''' utilizados para recursividade na Internet.&lt;br /&gt;
* Memorizar os IPs '''10.10.10.10''' e '''10.10.9.9''' é tão fácil quanto memorizar o '''8.8.8.8''' e o '''1.1.1.1'''. Mais fácil para o seu técnico guardar essa informação e utilizar onde for necessário.&lt;br /&gt;
Cada servidor DNS Recursivo possui um '''IPv4 público''', aqui representado por '''198.18.x.x/27''' e um '''IPv6 global''' representado por um IP dentro do prefixo '''2001:db8::/32'''. Cada servidor precisa ter os seus próprios IPs e são através destes IPs que as consultas de DNS serão realizadas na Internet.&lt;br /&gt;
&lt;br /&gt;
Nessa topologia usando '''Anycast''', o cliente será sempre atendido pelo '''DNS Recursivo''' mais próximo, desde que os pesos no '''OSPF''' estejam ajustados corretamente.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
== Dados do servidor ==&lt;br /&gt;
Podemos utilizar um sistema virtualizado ou não. Sistemas virtualizados são bem vindos pois são mais simples quando precisamos fazer backups, levantar outros sistemas sem complicações e se precisarmos restaurar rapidamente algum sistema que ficou indisponível por algum motivo. A configuração abaixo tem capacidade para atender algo em torno a '''50.000 assinantes ou mais'''. O DNS Recursivo é um serviço que pode ser utilizado até mesmo em um '''Raspberry Pi''' e atender operações pequenas, nesse caso com o intuito de economizar energia e espaço. Nosso foco aqui é montar uma rede de '''DNS Recursivo Anycast com HyperLocal'''. Como comentei acima o servidor deve ficar o mais próximo dos clientes para termos a '''menor latência possível''' e '''sempre menor que 5ms''' entre o cliente e o servidor.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!CPU&lt;br /&gt;
!Memória&lt;br /&gt;
!Disco&lt;br /&gt;
!Sistema&lt;br /&gt;
|-&lt;br /&gt;
|2.4Ghz 8 cores&lt;br /&gt;
|16G DDR4&lt;br /&gt;
|30G&lt;br /&gt;
|Debian 13 amd64 (Trixie)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Softwares utilizados ==&lt;br /&gt;
* Debian 13 amd64 (Trixie) instalação mínima.&lt;br /&gt;
&lt;br /&gt;
* [https://frrouting.org/ FRRouting].&lt;br /&gt;
* Unbound.&lt;br /&gt;
* Chrony (NTP/NTS).&lt;br /&gt;
* Shell script em bash.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades que teremos ==&lt;br /&gt;
* Sistema em Anycast.&lt;br /&gt;
* Hyperlocal.&lt;br /&gt;
* Controle de acesso por &amp;lt;abbr&amp;gt;ACL&amp;lt;/abbr&amp;gt;.&lt;br /&gt;
* RPZ (Response Policy Zone).&lt;br /&gt;
* Bloqueio de consultas do tipo ANY.&lt;br /&gt;
* QNAME minimization habilitado. (habilitado por default no Unbound)&lt;br /&gt;
* Recursividade em IPv4 e IPv6.&lt;br /&gt;
* DNSSEC habilitado.&lt;br /&gt;
* &amp;lt;abbr&amp;gt;DoH (DNS&amp;lt;/abbr&amp;gt; over HTTPS) habilitado.&lt;br /&gt;
&lt;br /&gt;
== Monitoramento ==&lt;br /&gt;
O monitoramento é algo bem específico e não é o foco deste documento mas é extremamente importante que você monitore seus servidores de DNS por alguma ferramenta como o Zabbix. Aqui mostrarei apenas como enviar as informações para o Zabbix. Algumas coisas que você deveria monitorar nos servidores de DNS Recursivo:&lt;br /&gt;
* Serviço do unbound parou.&lt;br /&gt;
* Perda de pacotes.&lt;br /&gt;
* Latência alta de pacotes.&lt;br /&gt;
* Lentidão na resolução de queries.&lt;br /&gt;
* CPU alta.&lt;br /&gt;
* Load alto.&lt;br /&gt;
* Memória com uso alto.&lt;br /&gt;
* Disco com pouco espaço.&lt;br /&gt;
* Queda brusca nas queries.&lt;br /&gt;
* A recursividade parou de funcionar.&lt;br /&gt;
* A recursividade voltou a funcionar.&lt;br /&gt;
Este abaixo é um exemplo de monitoramento de um sistema de DNS Recursivo que atende 50.000 assinantes:&lt;br /&gt;
[[Arquivo:Grafana dns.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Configurando a Rede ==&lt;br /&gt;
Nossa documentação será baseada no diagrama apresentado acima e por isso configuraremos apenas um dos três servidores, porque os outros serão configurados da mesma forma, só que com dados diferentes. Para tanto assumirei que já temos um sistema Debian instalado com o mínimo de pacotes e somente com sshd, para que possamos acessar remotamente mais tarde. '''Não instale um ambiente gráfico no servidor''', você não deve querer fazer isso por diversos motivos e os principais: primeiro porque não é um Desktop e segundo porque o ambiente gráfico devoraria toda a memória com recursos que não seriam úteis aqui.&lt;br /&gt;
&lt;br /&gt;
Em '''/etc/network/interfaces''' deixaremos assim:&lt;br /&gt;
 # This file describes the network interfaces available on your system&lt;br /&gt;
 # and how to activate them. For more information, see interfaces(5).&lt;br /&gt;
  &lt;br /&gt;
 source /etc/network/interfaces.d/*&lt;br /&gt;
  &lt;br /&gt;
 # The loopback network interface&lt;br /&gt;
 auto lo&lt;br /&gt;
 iface lo inet loopback&lt;br /&gt;
  &lt;br /&gt;
 auto lo:0&lt;br /&gt;
 iface lo:0 inet static&lt;br /&gt;
       address 10.10.10.10/32&lt;br /&gt;
  &lt;br /&gt;
 auto lo:1&lt;br /&gt;
 iface lo:1 inet static&lt;br /&gt;
       address 10.10.9.9/32&lt;br /&gt;
 &lt;br /&gt;
 auto lo:2&lt;br /&gt;
 iface lo:2 inet6 static&lt;br /&gt;
       address fd00::10:10:10:10/128&lt;br /&gt;
 &lt;br /&gt;
 auto lo:3&lt;br /&gt;
 iface lo:3 inet6 static&lt;br /&gt;
       address fd00::10:10:9:9/128&lt;br /&gt;
  &lt;br /&gt;
 # The primary network interface&lt;br /&gt;
 auto ens18&lt;br /&gt;
 iface ens18 inet static&lt;br /&gt;
         address 198.18.1.10/27&lt;br /&gt;
         gateway 198.18.1.1&lt;br /&gt;
  &lt;br /&gt;
 iface ens18 inet6 static&lt;br /&gt;
         address 2001:db8::faca:198:18:1:10/64&lt;br /&gt;
         gateway 2001:db8::faca:198:18:1:1&lt;br /&gt;
  &lt;br /&gt;
 # The secondary network interface&lt;br /&gt;
 auto ens18:0&lt;br /&gt;
 iface ens18:0 inet static&lt;br /&gt;
         address 172.16.0.6/30&lt;br /&gt;
Nesse cenário temos as duas '''loopbacks''' com os IPs '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10''' e '''fd00::10:10:9:9''' que serão anunciados via OSPF para a rede e serem entregues aos clientes via BNG. Os IPs '''198.18.1.10''' e '''2001:db8::faca:198:18:1:10''' serão usados para fazerem a recursividade na Internet tanto em IPv4 quanto em IPv6. Esses IPs não devem ser divulgados para clientes; os IPs públicos são dedicados apenas para essa finalidade.&lt;br /&gt;
&lt;br /&gt;
== Configuração dos repositórios Debian ==&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://security.debian.org/debian-security/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-security&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
 &lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-updates&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list.d/debian-backports.sources''' conforme abaixo:&lt;br /&gt;
 Types: deb&lt;br /&gt;
 URIs: &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 Suites: trixie-backports&lt;br /&gt;
 Components: main contrib non-free non-free-firmware&lt;br /&gt;
 Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg&lt;br /&gt;
Após a configuração vamos instalar alguns pacotes necessários e outros úteis:&lt;br /&gt;
 # apt update &amp;amp;&amp;amp; apt full-upgrade&lt;br /&gt;
 # apt install net-tools nftables htop iotop sipcalc tcpdump curl gnupg rsync wget host dnsutils mtr-tiny bmon sudo tmux whois ethtool dnstop&lt;br /&gt;
&lt;br /&gt;
== Fazendo algum tuning no sistema ==&lt;br /&gt;
Em '''/etc/sysctl.d/100-tuning.conf''' adicionamos essas instruções:&lt;br /&gt;
 net.core.rmem_max = 2147483647&lt;br /&gt;
 net.core.wmem_max = 2147483647&lt;br /&gt;
 net.ipv4.tcp_rmem = 4096 87380 2147483647&lt;br /&gt;
 net.ipv4.tcp_wmem = 4096 65536 2147483647&lt;br /&gt;
 net.netfilter.nf_conntrack_buckets = 512000&lt;br /&gt;
 net.netfilter.nf_conntrack_max = 4096000&lt;br /&gt;
 vm.swappiness=10&lt;br /&gt;
Estamos fazendo algumas melhorias de memória, algumas relacionadas a '''conntrack''' porque se for usar um filtro de pacotes stateful, como o '''Netfilter/IPTables''' ou '''Netfilter/NFTables''', o valor default da tabela é pequeno e dependendo da situação, se estourar essa tabela, as consultas de DNS terão problemas também. O DNS Recursivo não deve ficar aberto para qualquer um na Internet, ele deve ser liberado apenas para seus clientes. Podemos fazer através das ACLs do Unbound e pelo filtro de pacotes. O último parâmetro diz respeito ao uso de swap, por padrão o Debian permite o uso de swap após 40% do uso da memória, nesse caso estamos dizendo para o sistema usar o swap com 90% de uso da memória.&lt;br /&gt;
&lt;br /&gt;
Precisamos adicionar o módulo '''nf_conntrack''' em '''/etc/modules''' para que seja carregado em tempo de boot, senão os parâmetros de '''conntrack''' que colocamos em '''/etc/sysctl.conf''' não serão carregados.&lt;br /&gt;
 # echo nf_conntrack &amp;gt;&amp;gt; /etc/modules&lt;br /&gt;
 # modprobe nf_conntrack&lt;br /&gt;
 # sysctl -p&lt;br /&gt;
&lt;br /&gt;
== Instalando o FRRouting ==&lt;br /&gt;
O FRRouting é o programa que usaremos para fazer os anúncios das nossas loopbacks via OSPF. Nesse documento usaremos a versão 10.x:&lt;br /&gt;
 # apt install frr frr-doc frr-pythontools&lt;br /&gt;
Aconselho depois de instalar os pacotes, marcá-los para não atualizar juntamente com os demais pacotes, isso é para evitar de ocorrer alguma atualização no FRRouting, que torne o serviço instável por algum motivo. Não que isso vá ocorrer, mas é melhor fazer essa atualização quando realmente for necessário.&lt;br /&gt;
 # apt-mark hold frr frr-doc frr-pythontools&lt;br /&gt;
Após esse comando acima, o sistema manterá a instalação original do pacote intacta. Para desbloquear basta executar o comando abaixo:&lt;br /&gt;
 # apt-mark unhold frr frr-doc frr-pythontools&lt;br /&gt;
&lt;br /&gt;
== Removendo o APPARMOR ==&lt;br /&gt;
O '''APPARMOR''' às vezes causa mais problemas que solução e se não for fazer uma completa configuração nele, é melhor desabilitá-lo. Para fazer isso efetivamente, o procedimento é esse abaixo:&lt;br /&gt;
 # mkdir -p /etc/default/grub.d&lt;br /&gt;
 # echo 'GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;$GRUB_CMDLINE_LINUX_DEFAULT apparmor=0&amp;quot;' | tee /etc/default/grub.d/apparmor.cfg&lt;br /&gt;
 # update-grub&lt;br /&gt;
 # reboot&lt;br /&gt;
&lt;br /&gt;
== Instalando o Unbound ==&lt;br /&gt;
Nesse momento ainda não iremos configurar o Unbound, apenas instalar o pacote e acertar o ambiente. Vamos instalar o unbound do backports porque este já possui suporte ao DoH que veremos mais à frente.&lt;br /&gt;
 # apt install unbound dns-root-data&lt;br /&gt;
 # mkdir -p /var/log/unbound&lt;br /&gt;
 # touch /var/log/unbound/unbound.log&lt;br /&gt;
 # chown -R unbound:unbound /var/log/unbound/&lt;br /&gt;
 # systemctl restart unbound&lt;br /&gt;
Configurando o logrotate:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/logrotate.d/unbound&lt;br /&gt;
 /var/log/unbound/unbound.log {&lt;br /&gt;
     rotate 5&lt;br /&gt;
     weekly&lt;br /&gt;
     postrotate&lt;br /&gt;
         unbound-control log_reopen&lt;br /&gt;
     endscript&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
Reiniciando o serviço:&lt;br /&gt;
 # systemctl restart logrotate.service&lt;br /&gt;
&lt;br /&gt;
== Desabilitando THP (Transparente Huge Pages) em arquitetura AMD64 ==&lt;br /&gt;
No Debian o '''THP''' vem habilitado como '''always''' e o '''unbound''' por trabalhar bastante com alterações do cache em memória, isso pode acabar causando um consumo crescente de uso de RAM sem necessidade. É uma boa prática desabilitá-lo com os passos abaixo:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/systemd/system/disable-thp.service&lt;br /&gt;
 [Unit]&lt;br /&gt;
 Description=Desativa Transparent Huge Pages (THP)&lt;br /&gt;
 After=network.target&lt;br /&gt;
 &lt;br /&gt;
 [Service]&lt;br /&gt;
 Type=oneshot&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled&amp;quot;&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/defrag&amp;quot;&lt;br /&gt;
 RemainAfterExit=yes&lt;br /&gt;
 &lt;br /&gt;
 [Install]&lt;br /&gt;
 WantedBy=multi-user.target&lt;br /&gt;
 EOF&lt;br /&gt;
Acima configuramos o serviço '''disable-thp.service''' para desabilitar o '''THP''' e abaixo habilitamos no '''systemd''' e iniciamos:&lt;br /&gt;
 # systemctl daemon-reload&lt;br /&gt;
 # systemctl enable --now disable-thp&lt;br /&gt;
&lt;br /&gt;
== Preparando o monitoramento do seu DNS Recursivo ==&lt;br /&gt;
O monitoramento do seu DNS Recursivo é muito importante e para isso vamos usar um '''template para Zabbix''', que modifiquei juntamente com o seu shell script e que enviará os dados para o seu Zabbix server via '''zabbix-sender'''. O projeto original está aqui '''https://github.com/jeftedelima/Unbound-DNS&amp;lt;nowiki/&amp;gt;.''' O xml alterado está aqui '''https://github.com/gondimcodes/template_zabbix_dns_unbound'''. Embora seja antigo é perfeitamente importável no Zabbix 6.0, por exemplo.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;nowiki/&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Teremos um shell script que você precisará colocar no seu '''/etc/crontab'''. No exemplo abaixo assumi que o shell script está em '''/root/scripts'''. De 5 em 5 minutos os dados serão enviados para o seu Zabbix server.&lt;br /&gt;
 */5 * * * *     root    /root/scripts/unboundSend.sh '''IP_zabbix_server''' '''nome_do_host''' 1&amp;gt; /dev/null&lt;br /&gt;
Na linha acima, troque o '''IP_zabbix_server''' pelo '''IP do seu servidor Zabbix''' e o '''nome_do_host''' pelo '''hostname''' '''do seu DNS Recursivo'''. Você precisará instalar o pacote '''zabbix-sender''' no seu DNS Recursivo pois ele será usado para enviar os dados para o Zabbix server.&lt;br /&gt;
&lt;br /&gt;
Abaixo o '''unboundSend.sh''' também alterado com inclusão de mais dados:&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 #       @Jefte de Lima Ferreira&lt;br /&gt;
 #       jeftedelima at gmail dot com&lt;br /&gt;
 #       CRON Example&lt;br /&gt;
 #       Contributor: Marcelo Gondim - gondim at gmail dot com&lt;br /&gt;
 #       */5   **** root sh /home/dir/unboundSend.sh 192.168.10.1 Unbound 1&amp;gt; /dev/null&lt;br /&gt;
  &lt;br /&gt;
 if [ -z ${1} ] || [ -z ${2} ] ; then&lt;br /&gt;
         echo &amp;quot;You need to specify the IP address of zabbix server and hostname of your DNS Unbound on zabbix&amp;quot;&lt;br /&gt;
         echo &amp;quot;Usage example: ./unboundSend.sh 192.168.10.1 UnboundServer&amp;quot;&lt;br /&gt;
         exit 1&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 # ZABBIX_SERVER IP&lt;br /&gt;
 IP_ZABBIX=$1&lt;br /&gt;
 # NAME Unbound on Zabbix&lt;br /&gt;
 NAME_HOST=$2&lt;br /&gt;
 DIR_TEMP=/var/tmp/&lt;br /&gt;
 FILE=&amp;quot;${DIR_TEMP}dump_unbound_control_stats.txt&amp;quot;&lt;br /&gt;
 unbound-control stats &amp;gt; ${FILE}&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_NUM_QUERIES=$(cat ${FILE} | grep -w 'total.num.queries' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEHITS=$(cat ${FILE} | grep -w 'total.num.cachehits' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEMISS=$(cat ${FILE} | grep -w 'total.num.cachemiss' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_PREFETCH=$(cat ${FILE} | grep -w 'total.num.prefetch' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_RECURSIVEREPLIES=$(cat ${FILE} | grep -w 'total.num.recursivereplies' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_REQ_MAX=$(cat ${FILE} | grep -w 'total.requestlist.max' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_AVG=$(cat ${FILE} | grep -w 'total.requestlist.avg' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_OVERWRITTEN=$(cat ${FILE} | grep -w 'total.requestlist.overwritten' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_EXCEEDED=$(cat ${FILE} | grep -w 'total.requestlist.exceeded' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_ALL=$(cat ${FILE} | grep -w 'total.requestlist.current.all' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_USER=$(cat ${FILE} | grep -w 'total.requestlist.current.user' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 TOTAL_TCPUSAGE=$(cat ${FILE} | grep -w 'total.tcpusage' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_QUERY_TYPE_A=$(cat ${FILE} | grep -w 'num.query.type.A' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NS=$(cat ${FILE} | grep -w 'num.query.type.NS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_MX=$(cat ${FILE} | grep -w 'num.query.type.MX' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TXT=$(cat ${FILE} | grep -w 'num.query.type.TXT' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_PTR=$(cat ${FILE} | grep -w 'num.query.type.PTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_AAAA=$(cat ${FILE} | grep -w 'num.query.type.AAAA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SRV=$(cat ${FILE} | grep -w 'num.query.type.SRV' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SOA=$(cat ${FILE} | grep -w 'num.query.type.SOA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HTTPS=$(cat ${FILE} | grep -w 'num.query.type.HTTPS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TYPE0=$(cat ${FILE} | grep -w 'num.query.type.TYPE0' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_CNAME=$(cat ${FILE} | grep -w 'num.query.type.CNAME' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_WKS=$(cat ${FILE} | grep -w 'num.query.type.WKS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HINFO=$(cat ${FILE} | grep -w 'num.query.type.HINFO' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_X25=$(cat ${FILE} | grep -w 'num.query.type.X25' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NAPTR=$(cat ${FILE} | grep -w 'num.query.type.NAPTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DS=$(cat ${FILE} | grep -w 'num.query.type.DS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DNSKEY=$(cat ${FILE} | grep -w 'num.query.type.DNSKEY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TLSA=$(cat ${FILE} | grep -w 'num.query.type.TLSA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SVCB=$(cat ${FILE} | grep -w 'num.query.type.SVCB' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SPF=$(cat ${FILE} | grep -w 'num.query.type.SPF' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_ANY=$(cat ${FILE} | grep -w 'num.query.type.ANY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_OTHER=$(cat ${FILE} | grep -w 'num.query.type.other' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 NUM_ANSWER_RCODE_NOERROR=$(cat ${FILE} | grep -w 'num.answer.rcode.NOERROR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_NXDOMAIN=$(cat ${FILE} | grep -w 'num.answer.rcode.NXDOMAIN' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_SERVFAIL=$(cat ${FILE} | grep -w 'num.answer.rcode.SERVFAIL' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_REFUSED=$(cat ${FILE} | grep -w 'num.answer.rcode.REFUSED' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_nodata=$(cat ${FILE} | grep -w 'num.answer.rcode.nodata' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_secure=$(cat ${FILE} | grep -w 'num.answer.secure' | cut -d '=' -f2)&lt;br /&gt;
  &lt;br /&gt;
 #       Sending info to zabbix_server.&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.queries -o $(( ${TOTAL_NUM_QUERIES:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachehits -o $(( ${TOTAL_NUM_CACHEHITS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachemiss -o $(( ${TOTAL_NUM_CACHEMISS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.prefetch -o $(( ${TOTAL_NUM_PREFETCH:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.recursivereplies -o $(( ${TOTAL_NUM_RECURSIVEREPLIES:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.max -o $(( ${TOTAL_REQ_MAX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.avg -o $(( ${TOTAL_REQ_AVG:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.overwritten -o $(( ${TOTAL_REQ_OVERWRITTEN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.exceeded -o $(( ${TOTAL_REQ_EXCEEDED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.all -o $(( ${TOTAL_REQ_CURRENT_ALL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.user -o $(( ${TOTAL_REQ_CURRENT_USER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.tcpusage -o $(( ${TOTAL_TCPUSAGE:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.a -o $(( ${NUM_QUERY_TYPE_A:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ns -o $(( ${NUM_QUERY_TYPE_NS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.mx -o $(( ${NUM_QUERY_TYPE_MX:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.txt -o $(( ${NUM_QUERY_TYPE_TXT:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ptr -o $(( ${NUM_QUERY_TYPE_PTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.aaaa -o $(( ${NUM_QUERY_TYPE_AAAA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.srv -o $(( ${NUM_QUERY_TYPE_SRV:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.soa -o $(( ${NUM_QUERY_TYPE_SOA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.https -o $(( ${NUM_QUERY_TYPE_HTTPS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.type0 -o $(( ${NUM_QUERY_TYPE_TYPE0:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.cname -o $(( ${NUM_QUERY_TYPE_CNAME:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.wks -o $(( ${NUM_QUERY_TYPE_WKS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.hinfo -o $(( ${NUM_QUERY_TYPE_HINFO:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.X25 -o $(( ${NUM_QUERY_TYPE_X25:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.naptr -o $(( ${NUM_QUERY_TYPE_NAPTR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ds -o $(( ${NUM_QUERY_TYPE_DS:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.dnskey -o $(( ${NUM_QUERY_TYPE_DNSKEY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.tlsa -o $(( ${NUM_QUERY_TYPE_TLSA:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.svcb -o $(( ${NUM_QUERY_TYPE_SVCB:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.spf -o $(( ${NUM_QUERY_TYPE_SPF:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.any -o $(( ${NUM_QUERY_TYPE_ANY:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.other -o $(( ${NUM_QUERY_TYPE_OTHER:-0} / 300 ))&lt;br /&gt;
  &lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NOERROR -o $(( ${NUM_ANSWER_RCODE_NOERROR:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NXDOMAIN -o $(( ${NUM_ANSWER_RCODE_NXDOMAIN:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.SERVFAIL -o $(( ${NUM_ANSWER_RCODE_SERVFAIL:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.REFUSED -o $(( ${NUM_ANSWER_RCODE_REFUSED:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.nodata -o $(( ${NUM_ANSWER_RCODE_nodata:-0} / 300 ))&lt;br /&gt;
 zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.secure -o $(( ${NUM_ANSWER_secure:-0} / 300 ))&lt;br /&gt;
No Zabbix será registrado dados como esses abaixo e posteriormente pode ser montado um Grafana com eles:&lt;br /&gt;
[[Arquivo:Zabbix dns01.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns02.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns03.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns04.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Mantendo a hora certa ==&lt;br /&gt;
Vamos instalar agora o Chrony para manter a data e hora certas no sistema:&lt;br /&gt;
 # apt install chrony&lt;br /&gt;
Após a instalação do Chrony edite o arquivo /etc/chrony/chrony.conf, comente e a linha abaixo e adicione seus servidores NTP. Caso não tenha servidores NTP, estou colocando os do NIC.br aqui.&lt;br /&gt;
 #pool 2.debian.pool.ntp.org iburst&lt;br /&gt;
 server a.st1.ntp.br iburst nts&lt;br /&gt;
 server b.st1.ntp.br iburst nts&lt;br /&gt;
 server c.st1.ntp.br iburst nts&lt;br /&gt;
 server d.st1.ntp.br iburst nts&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart chronyd.service&lt;br /&gt;
Cheque com o '''chronyc''' se os servidores estão OK:&lt;br /&gt;
 # chronyc sourcestats&lt;br /&gt;
 Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev&lt;br /&gt;
 ==============================================================================&lt;br /&gt;
 a.st1.ntp.br               10   5  155m     -0.027      0.030    -71us    51us&lt;br /&gt;
 b.st1.ntp.br               11   7  344m     +0.068      0.079    +23ms   382us&lt;br /&gt;
 c.st1.ntp.br                6   3  344m     +0.026      0.037   -124us    92us&lt;br /&gt;
 200.20.186.76               9   3  138m     -0.022      0.031   +172us    42us&lt;br /&gt;
&lt;br /&gt;
 # chronyc sources&lt;br /&gt;
 MS Name/IP address         Stratum Poll Reach LastRx Last sample&lt;br /&gt;
 ===============================================================================&lt;br /&gt;
 ^* a.st1.ntp.br                  1  10   377   588   +487us[ +397us] +/-   12ms&lt;br /&gt;
 ^- b.st1.ntp.br                  2  10   377   830    +23ms[  +23ms] +/-   49ms&lt;br /&gt;
 ^+ c.st1.ntp.br                  2  10    21  1038   -147us[ -242us] +/-   17ms&lt;br /&gt;
 ^+ 200.20.186.76                 1  10   377  1032   +381us[ +285us] +/-   15ms&lt;br /&gt;
&lt;br /&gt;
== Configurando o FRRouting ==&lt;br /&gt;
Nesse ponto iremos configurar o '''FRRouting''' para enviar os IPs das '''loopbacks''' e o '''/30''' para o nosso PE do diagrama. Em '''/etc/frr/daemons''' habilite o parâmetro conforme abaixo:&lt;br /&gt;
 ospfd=yes&lt;br /&gt;
 ospf6d=yes&lt;br /&gt;
Edite o arquivo '''/etc/frr/frr.conf''' e deixe com o conteúdo abaixo, para ficar conforme nosso diagrama do projeto. Apenas troque '''&amp;lt;SENHA&amp;gt;''' por uma senha para fechar o OSPF com mais segurança. Essa senha deve ser usada dos dois lados.&lt;br /&gt;
 frr version 10.3&lt;br /&gt;
 frr defaults traditional&lt;br /&gt;
 hostname dns-recursivo-01&lt;br /&gt;
 log syslog informational&lt;br /&gt;
 no ip forwarding&lt;br /&gt;
 no ipv6 forwarding&lt;br /&gt;
 service integrated-vtysh-config&lt;br /&gt;
 !&lt;br /&gt;
 interface ens18&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf message-digest-key 5 md5 &amp;lt;SENHA&amp;gt;&lt;br /&gt;
  ip ospf network point-to-point&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 network point-to-point&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 interface lo&lt;br /&gt;
  description LOOPBACKS&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf passive&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 passive&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf&lt;br /&gt;
  ospf router-id 172.16.0.6&lt;br /&gt;
  area 0.0.0.0 authentication message-digest&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf6&lt;br /&gt;
  ospf6 router-id 172.16.0.6&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart frr.service&lt;br /&gt;
Cheque se está tudo OK com o OSPF e verifique no PE se está recebendo os prefixos anunciados.&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL&lt;br /&gt;
 172.16.0.5     1 Full/-          10m49s            35.310s 172.16.0.5   ens18:172.16.0.6                  0     0     0&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri    DeadTime    State/IfState         Duration I/F[State]&lt;br /&gt;
 172.16.0.5       1    00:00:30     Full/PointToPoint 25d22:53:47 ens18[PointToPoint]&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor detail'&lt;br /&gt;
 &lt;br /&gt;
  Neighbor 172.16.0.5, interface address 172.16.0.5&lt;br /&gt;
     In the area 0.0.0.0 via interface ens18&lt;br /&gt;
     Neighbor priority is 1, State is Full/-, 5 state changes&lt;br /&gt;
     Most recent state change statistics:&lt;br /&gt;
       Progressive change 21w3d15h ago&lt;br /&gt;
     DR is 0.0.0.0, BDR is 0.0.0.0&lt;br /&gt;
     Options 18 *|-|-|EA|-|-|E|-&lt;br /&gt;
     Dead timer due in 34.685s&lt;br /&gt;
     Database Summary List 0&lt;br /&gt;
     Link State Request List 0&lt;br /&gt;
     Link State Retransmission List 0&lt;br /&gt;
     Thread Inactivity Timer on&lt;br /&gt;
     Thread Database Description Retransmision off&lt;br /&gt;
     Thread Link State Request Retransmission on&lt;br /&gt;
     Thread Link State Update Retransmission on&lt;br /&gt;
 &lt;br /&gt;
     Graceful restart Helper info:&lt;br /&gt;
       Graceful Restart HELPER Status : None&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor detail'&lt;br /&gt;
  Neighbor 172.16.0.5%ens18&lt;br /&gt;
     Area 0.0.0.0 via interface ens18 (ifindex 4)&lt;br /&gt;
     His IfIndex: 60 Link-local address: fe80::469b:c1ff:fed6:43ee&lt;br /&gt;
     State Full for a duration of 25d22:57:14&lt;br /&gt;
     His choice of DR/BDR 0.0.0.0/0.0.0.0, Priority 1&lt;br /&gt;
     DbDesc status: Master SeqNum: 0xb94b0000&lt;br /&gt;
     Summary-List: 0 LSAs&lt;br /&gt;
     Request-List: 0 LSAs&lt;br /&gt;
     Retrans-List: 0 LSAs&lt;br /&gt;
     0 Pending LSAs for DbDesc in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSReq in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSAck in Time 00:00:00 [thread off]&lt;br /&gt;
     Authentication header not present&lt;br /&gt;
&lt;br /&gt;
== Configurando o Unbound ==&lt;br /&gt;
Abaixo a configuração que usaremos nos servidores atentando para o detalhe do '''num-threads''', esse deve ter o valor igual ao número de CPUs do servidor.&lt;br /&gt;
&lt;br /&gt;
Também os IPs utilizados em '''outgoing-interface''' que serão diferentes em cada servidor, esses serão os IPs usados para '''recursividade'''. Consulte o manual do Unbound para obter mais informações sobre cada parâmetro listado na configuração.&lt;br /&gt;
&lt;br /&gt;
O tuning no Unbound pode ser alterado conforme abaixo:&lt;br /&gt;
 num-threads = nº CPUs&lt;br /&gt;
 so-reuseport = yes&lt;br /&gt;
 *-slabs = potência de 2 próximo ao num-threads&lt;br /&gt;
 msg-cache-size = 1g (quantidade de memória pra usar de cache)&lt;br /&gt;
 rrset-cache-size = 2 * msg-cache-size&lt;br /&gt;
 outgoing-range = 8192&lt;br /&gt;
 num-queries-per-thread = 4096&lt;br /&gt;
 so-rcvbuf e so-sndbuf = 4m ou 8m para servidores com muita requisição&lt;br /&gt;
Agora vamos criar nosso arquivo de configuração base em '''/etc/unbound/unbound.conf.d/local.conf''':&lt;br /&gt;
 server:&lt;br /&gt;
         verbosity: 1&lt;br /&gt;
         statistics-interval: 0&lt;br /&gt;
         statistics-cumulative: no&lt;br /&gt;
         extended-statistics: yes&lt;br /&gt;
         num-threads: 8&lt;br /&gt;
         serve-expired: yes&lt;br /&gt;
         interface: 127.0.0.1&lt;br /&gt;
         interface: 10.10.10.10&lt;br /&gt;
         interface: 10.10.9.9&lt;br /&gt;
         interface: 172.16.0.6&lt;br /&gt;
         interface: fd00::10:10:10:10&lt;br /&gt;
         interface: fd00::10:10:9:9&lt;br /&gt;
         interface: ::1&lt;br /&gt;
         interface-automatic: no&lt;br /&gt;
         outgoing-interface: 198.18.1.10&lt;br /&gt;
         outgoing-interface: 2001:db8::faca:198:18:1:10&lt;br /&gt;
         outgoing-range: 8192&lt;br /&gt;
         outgoing-num-tcp: 1024&lt;br /&gt;
         incoming-num-tcp: 2048&lt;br /&gt;
         so-rcvbuf: 4m&lt;br /&gt;
         so-sndbuf: 4m&lt;br /&gt;
         so-reuseport: yes&lt;br /&gt;
         edns-buffer-size: 1232&lt;br /&gt;
         msg-cache-size: 512m&lt;br /&gt;
         msg-cache-slabs: 4&lt;br /&gt;
         num-queries-per-thread: 4096&lt;br /&gt;
         rrset-cache-size: 1g&lt;br /&gt;
         rrset-cache-slabs: 4&lt;br /&gt;
         infra-cache-slabs: 4&lt;br /&gt;
         do-ip4: yes&lt;br /&gt;
         do-ip6: yes&lt;br /&gt;
         do-udp: yes&lt;br /&gt;
         do-tcp: yes&lt;br /&gt;
         chroot: &amp;quot;&amp;quot;&lt;br /&gt;
         username: &amp;quot;unbound&amp;quot;&lt;br /&gt;
         directory: &amp;quot;/etc/unbound&amp;quot;&lt;br /&gt;
         logfile: &amp;quot;/var/log/unbound/unbound.log&amp;quot;&lt;br /&gt;
         use-syslog: no&lt;br /&gt;
         log-time-ascii: yes&lt;br /&gt;
         log-queries: no&lt;br /&gt;
         pidfile: &amp;quot;/var/run/unbound.pid&amp;quot;&lt;br /&gt;
         root-hints: &amp;quot;/usr/share/dns/root.hints&amp;quot;&lt;br /&gt;
         hide-identity: yes&lt;br /&gt;
         hide-version: yes&lt;br /&gt;
         unwanted-reply-threshold: 10000000&lt;br /&gt;
         prefetch: yes&lt;br /&gt;
         prefetch-key: yes&lt;br /&gt;
         rrset-roundrobin: yes&lt;br /&gt;
         minimal-responses: yes&lt;br /&gt;
         module-config: &amp;quot;respip validator iterator&amp;quot;&lt;br /&gt;
         val-clean-additional: yes&lt;br /&gt;
         val-log-level: 1&lt;br /&gt;
         key-cache-slabs: 4&lt;br /&gt;
         deny-any: yes&lt;br /&gt;
         cache-min-ttl: 60&lt;br /&gt;
         key-cache-size: 128m&lt;br /&gt;
         neg-cache-size: 64m&lt;br /&gt;
         cache-max-ttl: 86400&lt;br /&gt;
         infra-cache-numhosts: 100000&lt;br /&gt;
         access-control: 198.18.0.0/22 allow&lt;br /&gt;
         access-control: 2001:db8::/32 allow&lt;br /&gt;
  &lt;br /&gt;
 rpz:&lt;br /&gt;
   name: rpz.block.host.local.zone&lt;br /&gt;
   zonefile: /etc/unbound/rpz.block.hosts.zone&lt;br /&gt;
   rpz-action-override: nxdomain&lt;br /&gt;
  &lt;br /&gt;
 python:&lt;br /&gt;
  &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;.&amp;quot;&lt;br /&gt;
     master: &amp;quot;b.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;c.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;d.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;f.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;g.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;k.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/root.zone&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;arpa.&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/arpa.zone&amp;quot;&lt;br /&gt;
No parâmetro '''interface''' colocamos os IPs que serão usados para consulta dos clientes como o '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9'''. Ali repare que coloquei também o IP privado '''172.16.0.6''', isso porque cada servidor terá o seu IP privado e este deve ser usado pelo seu sistema de monitoramento para checar cada servidor. No '''outgoing-interface''' teremos os IPs, tanto '''IPv4''' quanto '''IPv6''', para que seja feita a recursividade na Internet utilizando eles. Não tem '''IPv6''' ainda na sua rede? Dê uma olhada nesse artigo. Outro parâmetro importante é o '''access-control''' e é através dele que liberamos os prefixos IP para consultarem no nosso DNS Recursivo. No exemplo estou liberando todo o prefixo '''198.18.0.0/22''' e o prefixo '''2001:db8::/32'''. Além da ACL no Unbound, recomendo que crie um filtro de pacotes com iptables ou nftables protegendo seu sistema e liberando as portas '''53/UDP''', '''53/TCP,'''  '''443/TCP e 853/TCP''' apenas para seus clientes. Falarei sobre a '''443/TCP e 853/TCP''' mais para frente nessa mesma documentação.&lt;br /&gt;
&lt;br /&gt;
Agora criaremos o arquivo '''RPZ''' ('''Response Policy Zones'''). Esse arquivo contém os sites que serão bloqueados via '''&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; Recursivo'''. São aqueles sites que às vezes você recebe um Ofício da Justiça solicitando o bloqueio deles. Não entrarei no mérito da efetividade desses bloqueios, porque muitos de vocês sabem que tecnicamente, existem formas de se fazer um bypass através desses bloqueios. Contudo vamos deixar nosso ambiente preparado para esses bloqueios e por isso crie o arquivo '''/etc/unbound/rpz.block.hosts.zone''' com esse conteúdo de exemplo:&lt;br /&gt;
 $TTL 2h&lt;br /&gt;
 @ IN SOA localhost. root.localhost. (2 6h 1h 1w 2h)&lt;br /&gt;
   IN NS  localhost.&lt;br /&gt;
 ; RPZ manual block hosts&lt;br /&gt;
 *.josedascoves.com CNAME .&lt;br /&gt;
 josedascoves.com CNAME .&lt;br /&gt;
No exemplo acima estamos bloqueando qualquer consulta de DNS para '''josedascoves.com''' ou qualquer coisa '''.josedascoves.com'''.&lt;br /&gt;
&lt;br /&gt;
Para testar podemos fazer assim do próprio servidor:&lt;br /&gt;
 # host josedascoves.com ::1&lt;br /&gt;
 Using domain server:&lt;br /&gt;
 Name: ::1&lt;br /&gt;
 Address: ::1#53&lt;br /&gt;
 Aliases:&lt;br /&gt;
 &lt;br /&gt;
 Host josedascoves.com not found: 3(NXDOMAIN)&lt;br /&gt;
Se a resposta for '''NXDOMAIN''' então está funcionando o bloqueio. Para incluir novos bloqueios basta adicionar os domínios, um abaixo do outro, conforme o exemplo que coloquei no arquivo RPZ.&lt;br /&gt;
&lt;br /&gt;
== Acertando o resolv.conf ==&lt;br /&gt;
Vamos modificar nosso /etc/resolv.conf para utilizar DNS externo. Sim você deve estar se perguntando em qual situação isso seria utilizado. Primeiro entenda que o Unbound não irá utilizar o DNS externo para fazer as consultas na Internet e sim, qualquer teste que você faça do servidor precisará apontar para o Unbound usando os IPs '''127.0.0.1''' ou '''::1'''. Faremos isso pela seguinte situação: imagine que o daemon unbound morreu mas você ainda continua com conectividade na Internet. Você conseguiria acessar qualquer local na Internet através do IP mas não através do hostname porque não conseguiria resolver nomes, seu unbound estaria fora do ar. Imagine ainda que você gostaria que seu servidor te avisasse do problema via Telegram ou e-mail. Por isso estamos utilizando um DNS externo no '''/etc/resolv.conf''', apenas para essas situações. Se você não quiser utilizar desse recurso, pode usar o '''127.0.0.1''' e '''::1''' no lugar.&lt;br /&gt;
 nameserver 8.8.8.8&lt;br /&gt;
 nameserver 8.8.4.4&lt;br /&gt;
 nameserver 2001:4860:4860::8888&lt;br /&gt;
&lt;br /&gt;
== Script de teste de recursividade ==&lt;br /&gt;
Estamos montando uma '''Rede de DNS Recursivo Anycast''', então é muito importante que você monitore essa rede para saber se algum node morreu e iniciar o troubleshooting, resolver o problema e levantar o sistema novamente. Tudo isso é importante mas o cliente não deve ficar esperando até você resolver o problema, seu sistema precisa ser inteligente o suficiente para se remover da Rede quando tiver um problema e se inserir novamente, quando o problema estiver sido solucionado. Se você montar uma Rede de DNS e um dos nodes apresentar algum problema, todos os clientes atendidos por aquele node migrarão automaticamente e transparentemente para outro '''DNS Recursivo Anycast''' mais próximo. Isso se chama '''disponibilidade'''.&lt;br /&gt;
&lt;br /&gt;
O script '''/root/scripts/checa_dns.sh''' abaixo tem a função de fazer os testes de recursividade e checar se o daemon do unbound continua rodando. Se algo acontecer, ele para o anúncio do '''10.10.10.10''' e '''10.10.9.9''' e retorna eles quando tudo estiver resolvido.&lt;br /&gt;
 # mkdir /root/scripts&lt;br /&gt;
&lt;br /&gt;
 #!/usr/bin/env bash&lt;br /&gt;
 #Script para teste de DNS v2.1&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 #Informe um domínio por linha:&lt;br /&gt;
 dominios_testar=(&lt;br /&gt;
 www.google.com&lt;br /&gt;
 www.terra.com.br&lt;br /&gt;
 www.uol.com.br&lt;br /&gt;
 www.globo.com&lt;br /&gt;
 www.facebook.com&lt;br /&gt;
 www.youtube.com&lt;br /&gt;
 www.twitch.com&lt;br /&gt;
 www.discord.com&lt;br /&gt;
 www.debian.org&lt;br /&gt;
 www.redhat.com&lt;br /&gt;
 )&lt;br /&gt;
 corte_taxa_falha=100 #Porcentagem de falha para executar uma ação&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 remove_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; != &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no description' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME morreu!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 adiciona_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; == &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'description LOOPBACKS' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME retornou do inferno!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
 if [ $? -ne 0 ]; then&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME morreu DNS mas tentando levantar!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    systemctl restart unbound&lt;br /&gt;
    systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
    if [ $? -ne 0 ]; then&lt;br /&gt;
       remove_ospf&lt;br /&gt;
       exit&lt;br /&gt;
    fi&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME servico DNS voltou mas tinha morrido!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 qt_falhas=0&lt;br /&gt;
 qt_total=&amp;quot;${#dominios_testar[@]}&amp;quot;&lt;br /&gt;
 echo &amp;quot;total_dominios: $qt_total&amp;quot;&lt;br /&gt;
 for site in &amp;quot;${dominios_testar[@]}&amp;quot;&lt;br /&gt;
 do&lt;br /&gt;
   unbound-control flush $site &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   resolver=&amp;quot;127.0.0.1&amp;quot;&lt;br /&gt;
   echo -e &amp;quot; - dominio $site - $resolver - \c&amp;quot;&lt;br /&gt;
   host $site $resolver &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   if [ $? -ne 0 ]; then&lt;br /&gt;
      ((qt_falhas++))&lt;br /&gt;
      echo -e &amp;quot;[Falhou]&amp;quot;&lt;br /&gt;
   else&lt;br /&gt;
      echo -e &amp;quot;[OK]&amp;quot;&lt;br /&gt;
   fi&lt;br /&gt;
 done&lt;br /&gt;
  &lt;br /&gt;
 taxa_falha=$((qt_falhas*100/qt_total))&lt;br /&gt;
 echo &amp;quot;Falhas $qt_falhas/$qt_total ($taxa_falha%)&amp;quot;&lt;br /&gt;
  &lt;br /&gt;
 if [ &amp;quot;$taxa_falha&amp;quot; -ge &amp;quot;$corte_taxa_falha&amp;quot; ]; then&lt;br /&gt;
    remove_ospf&lt;br /&gt;
    exit&lt;br /&gt;
 fi&lt;br /&gt;
 adiciona_ospf&lt;br /&gt;
Se rodarmos o script manualmente veremos isto:&lt;br /&gt;
 # /root/scripts/checa_dns.sh&lt;br /&gt;
 total_dominios: 10&lt;br /&gt;
  - dominio www.google.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.terra.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.uol.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.globo.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.facebook.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.youtube.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.twitch.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.discord.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.debian.org - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.redhat.com - 127.0.0.1 - [OK]&lt;br /&gt;
 Falhas 0/10 (0%)&lt;br /&gt;
Se acontecer 100% de falhas o script irá remover os anúncios do OSPF. Se o daemon do unbound morrer, ele tentará reiniciá-lo. Se tudo normalizar o script irá retornar os anúncios para o OSPF. Deixei comentado no script as partes que enviariam uma notificação para o Telegram. Existem diversas documentações sobre isso na Internet, eu mesmo tenho uma. Assim que eu publicar aqui, atualizo essa documentação e sinta-se à vontade de modificar como desejar.&lt;br /&gt;
 # chmod 700 /root/scripts/checa_dns.sh&lt;br /&gt;
Adicione a linha abaixo em seu '''/etc/crontab''':&lt;br /&gt;
 */1 *   * * *   root    /root/scripts/checa_dns.sh&lt;br /&gt;
&lt;br /&gt;
== Habilitando o DoH (&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; over HTTPS) - opcional ==&lt;br /&gt;
Para habilitar o '''DoH''' no Unbound é bem simples. O recurso do '''DoH''' vem para trazer mais segurança e privacidade para o usuário. É um recurso muito pouco utilizado ainda mas que seu cliente pode vir a pedir algum dia.&lt;br /&gt;
&lt;br /&gt;
Você precisará gerar certificados SSL legítimos e para isso você poderá usar o '''Let's Encrypt''' só que de uma forma não tão convencional.&lt;br /&gt;
&lt;br /&gt;
Na sequência vamos instalar o Let's Encrypt para gerarmos nosso certificado SSL:&lt;br /&gt;
 # apt install letsencrypt&lt;br /&gt;
Escolha um '''hostname''' para ser usado no nosso '''DoH''' e aponte ele no seu DNS Autoritativo para seus IPs 10.10.10.10 e 10.10.9.9. Aqui vamos usar o seguinte como exemplo: '''doh.brasilpeeringforum.org'''. Para gerarmos nosso certificado iremos usar o tipo '''DNS-01''', ele não necessita que tenhamos um servidor web rodando no servidor e nem tão pouco levanta um serviço na porta 80 para checar o hostname. Ele utiliza o DNS como validador e vai te solicitar que crie um registro '''CNAME''' no seu '''DNS Autoritativo''' para provar que você tem o controle sobre aquele hostname. Antes disso vamos instalar um programa em Python para podermos automatizar nossa renovação de certificado no futuro. Esse programa se encontra '''[https://github.com/joohoi/acme-dns-certbot-joohoi/raw/master/acme-dns-auth.py aqui]''' mas vou deixá-lo abaixo já modificado o interpretador.&lt;br /&gt;
&lt;br /&gt;
Crie o arquivo '''/etc/letsencrypt/acme-dns-auth.py''' com o conteúdo abaixo:&lt;br /&gt;
 #!/usr/bin/env python3&lt;br /&gt;
 import json&lt;br /&gt;
 import os&lt;br /&gt;
 import requests&lt;br /&gt;
 import sys&lt;br /&gt;
 &lt;br /&gt;
 ### EDIT THESE: Configuration values ###&lt;br /&gt;
 &lt;br /&gt;
 # URL to acme-dns instance&lt;br /&gt;
 ACMEDNS_URL = &amp;quot;&amp;lt;nowiki&amp;gt;https://auth.acme-dns.io&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
 # Path for acme-dns credential storage&lt;br /&gt;
 STORAGE_PATH = &amp;quot;/etc/letsencrypt/acmedns.json&amp;quot;&lt;br /&gt;
 # Whitelist for address ranges to allow the updates from&lt;br /&gt;
 # Example: ALLOW_FROM = [&amp;quot;192.168.10.0/24&amp;quot;, &amp;quot;::1/128&amp;quot;]&lt;br /&gt;
 ALLOW_FROM = []&lt;br /&gt;
 # Force re-registration. Overwrites the already existing acme-dns accounts.&lt;br /&gt;
 FORCE_REGISTER = False&lt;br /&gt;
 &lt;br /&gt;
 ###   DO NOT EDIT BELOW THIS POINT   ###&lt;br /&gt;
 ###         HERE BE DRAGONS          ###&lt;br /&gt;
 &lt;br /&gt;
 DOMAIN = os.environ[&amp;quot;CERTBOT_DOMAIN&amp;quot;]&lt;br /&gt;
 if DOMAIN.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
     DOMAIN = DOMAIN[2:]&lt;br /&gt;
 VALIDATION_DOMAIN = &amp;quot;_acme-challenge.&amp;quot;+DOMAIN&lt;br /&gt;
 VALIDATION_TOKEN = os.environ[&amp;quot;CERTBOT_VALIDATION&amp;quot;]&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 class AcmeDnsClient(object):&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
     Handles the communication with ACME-DNS API&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
     def __init__(self, acmedns_url):&lt;br /&gt;
         self.acmedns_url = acmedns_url&lt;br /&gt;
 &lt;br /&gt;
     def register_account(self, allowfrom):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Registers a new ACME-DNS account&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
         if allowfrom:&lt;br /&gt;
             # Include whitelisted networks to the registration call&lt;br /&gt;
             reg_data = {&amp;quot;allowfrom&amp;quot;: allowfrom}&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;,&lt;br /&gt;
                                 data=json.dumps(reg_data))&lt;br /&gt;
         else:&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;)&lt;br /&gt;
         if res.status_code == 201:&lt;br /&gt;
             # The request was successful&lt;br /&gt;
             return res.json()&lt;br /&gt;
         else:&lt;br /&gt;
             # Encountered an error&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to register a new acme-dns &amp;quot;&lt;br /&gt;
                    &amp;quot;account. HTTP status {}, Response body: {}&amp;quot;)&lt;br /&gt;
             print(msg.format(res.status_code, res.text))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def update_txt_record(self, account, txt):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Updates the TXT challenge record to ACME-DNS subdomain.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         update = {&amp;quot;subdomain&amp;quot;: account['subdomain'], &amp;quot;txt&amp;quot;: txt}&lt;br /&gt;
         headers = {&amp;quot;X-Api-User&amp;quot;: account['username'],&lt;br /&gt;
                    &amp;quot;X-Api-Key&amp;quot;: account['password'],&lt;br /&gt;
                    &amp;quot;Content-Type&amp;quot;: &amp;quot;application/json&amp;quot;}&lt;br /&gt;
         res = requests.post(self.acmedns_url+&amp;quot;/update&amp;quot;,&lt;br /&gt;
                             headers=headers,&lt;br /&gt;
                             data=json.dumps(update))&lt;br /&gt;
         if res.status_code == 200:&lt;br /&gt;
             # Successful update&lt;br /&gt;
             return&lt;br /&gt;
         else:&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to update TXT record in &amp;quot;&lt;br /&gt;
                    &amp;quot;acme-dns. \n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request headers:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request body:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response HTTP status: {}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response body: {}&amp;quot;)&lt;br /&gt;
             s_headers = json.dumps(headers, indent=2, sort_keys=True)&lt;br /&gt;
             s_update = json.dumps(update, indent=2, sort_keys=True)&lt;br /&gt;
             s_body = json.dumps(res.json(), indent=2, sort_keys=True)&lt;br /&gt;
             print(msg.format(s_headers, s_update, res.status_code, s_body))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
 class Storage(object):&lt;br /&gt;
     def __init__(self, storagepath):&lt;br /&gt;
         self.storagepath = storagepath&lt;br /&gt;
         self._data = self.load()&lt;br /&gt;
 &lt;br /&gt;
     def load(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Reads the storage content from the disk to a dict structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         data = dict()&lt;br /&gt;
         filedata = &amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             with open(self.storagepath, 'r') as fh:&lt;br /&gt;
                 filedata = fh.read()&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             if os.path.isfile(self.storagepath):&lt;br /&gt;
                 # Only error out if file exists, but cannot be read&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage file exists but cannot be read&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         try:&lt;br /&gt;
             data = json.loads(filedata)&lt;br /&gt;
         except ValueError:&lt;br /&gt;
             if len(filedata) &amp;gt; 0:&lt;br /&gt;
                 # Storage file is corrupted&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage JSON is corrupted&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         return data&lt;br /&gt;
 &lt;br /&gt;
     def save(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Saves the storage content to disk&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         serialized = json.dumps(self._data)&lt;br /&gt;
         try:&lt;br /&gt;
             with os.fdopen(os.open(self.storagepath,&lt;br /&gt;
                                    os.O_WRONLY | os.O_CREAT, 0o600), 'w') as fh:&lt;br /&gt;
                 fh.truncate()&lt;br /&gt;
                 fh.write(serialized)&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             print(&amp;quot;ERROR: Could not write storage file.&amp;quot;)&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def put(self, key, value):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Puts the configuration value to storage and sanitize it&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         # If wildcard domain, remove the wildcard part as this will use the&lt;br /&gt;
         # same validation record name as the base domain&lt;br /&gt;
         if key.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
             key = key[2:]&lt;br /&gt;
         self._data[key] = value&lt;br /&gt;
 &lt;br /&gt;
     def fetch(self, key):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Gets configuration value from storage&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             return self._data[key]&lt;br /&gt;
         except KeyError:&lt;br /&gt;
             return None&lt;br /&gt;
 &lt;br /&gt;
 if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
     # Init&lt;br /&gt;
     client = AcmeDnsClient(ACMEDNS_URL)&lt;br /&gt;
     storage = Storage(STORAGE_PATH)&lt;br /&gt;
 &lt;br /&gt;
     # Check if an account already exists in storage&lt;br /&gt;
     account = storage.fetch(DOMAIN)&lt;br /&gt;
     if FORCE_REGISTER or not account:&lt;br /&gt;
         # Create and save the new account&lt;br /&gt;
         account = client.register_account(ALLOW_FROM)&lt;br /&gt;
         storage.put(DOMAIN, account)&lt;br /&gt;
         storage.save()&lt;br /&gt;
 &lt;br /&gt;
         # Display the notification for the user to update the main zone&lt;br /&gt;
         msg = &amp;quot;Please add the following CNAME record to your main DNS zone:\n{}&amp;quot;&lt;br /&gt;
         cname = &amp;quot;{} CNAME {}.&amp;quot;.format(VALIDATION_DOMAIN, account[&amp;quot;fulldomain&amp;quot;])&lt;br /&gt;
         print(msg.format(cname))&lt;br /&gt;
 &lt;br /&gt;
     # Update the TXT record in acme-dns instance&lt;br /&gt;
     client.update_txt_record(account, VALIDATION_TOKEN)&lt;br /&gt;
&lt;br /&gt;
 # chmod +x /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
Usaremos a seguinte instrução para criar nosso certificado:&lt;br /&gt;
 # certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d doh.brasilpeeringforum.org&lt;br /&gt;
 Saving debug log to /var/log/letsencrypt/letsencrypt.log&lt;br /&gt;
 Plugins selected: Authenticator manual, Installer None&lt;br /&gt;
 Cert is due for renewal, auto-renewing...&lt;br /&gt;
 Renewing an existing certificate for doh.brasilpeeringforum.org&lt;br /&gt;
 Performing the following challenges:&lt;br /&gt;
 dns-01 challenge for doh.brasilpeeringforum.org&lt;br /&gt;
 Running manual-auth-hook command: /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
 Output from manual-auth-hook command acme-dns-auth.py:&lt;br /&gt;
 Please add the following CNAME record to your main DNS zone:&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
 &lt;br /&gt;
 Waiting for verification...&lt;br /&gt;
 &lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Challenges loaded. Press continue to submit to CA. Pass &amp;quot;-v&amp;quot; for more info about&lt;br /&gt;
 challenges.&lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Press Enter to Continue&lt;br /&gt;
Nesse momento você cria o registro '''CNAME''' no seu DNS Autoritativo conforme ele solicitou: '''_acme-challenge.doh.brasilpeeringforum.org IN CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.''' e somente depois de criado e checado no DNS, você pressiona o '''Enter''' para continuar. Você pode checar dessa forma:&lt;br /&gt;
 # host -t cname _acme-challenge.doh.brasilpeeringforum.org&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org is an alias for b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
Para que nosso certificado seja automaticamente renovado colocaremos no '''/etc/crontab''' a seguinte linha abaixo:&lt;br /&gt;
 00 00   1 * *   root    /usr/bin/certbot -q renew --deploy-hook &amp;quot;/usr/sbin/unbound-control reload_keep_cache&amp;quot;&lt;br /&gt;
Acima temos a instrução para renovação automática do certificado. Repare que você vai precisar também copiar esse certificado para seus outros servidores, escolha um servidor para manter o certificado sempre atualizado e crie um script que faça a mesma cópia remotamente para os outros servidores. O '''scp''' e o '''rsync''' são seus aliados nisso.&lt;br /&gt;
&lt;br /&gt;
=== Configurando o Unbound ===&lt;br /&gt;
Em nosso '''/etc/unbound/unbound.conf.d/local.conf''', adicionaremos no bloco &amp;quot;'''server:'''&amp;quot; o seguinte:&lt;br /&gt;
 interface: 10.10.10.10@443 &lt;br /&gt;
 interface: 10.10.9.9@443&lt;br /&gt;
 interface: fd00::10:10:10:10@443&lt;br /&gt;
 interface: fd00::10:10:9:9@443&lt;br /&gt;
 tls-service-key: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/privkey.pem&amp;quot; &lt;br /&gt;
 tls-service-pem: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/fullchain.pem&amp;quot;&lt;br /&gt;
Para usar o recurso do '''DoH''' você precisará habilitar o recurso no seu navegador e informar a URL. Vou colocar o exemplo do '''Google Chrome''': Digite '''chrome://settings/security?search=dns''' no seu Chrome e ative '''Usar DNS seguro''', selecione '''Personalizado''' e adicione nossa URL:&lt;br /&gt;
[[Arquivo:Doh bpf2.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Finalizando ==&lt;br /&gt;
Aqui finalizamos nosso projeto para uma Rede de DNS(s) Recursivos Anycast com Hyperlocal. Esse projeto é escalável, seguro, resiliente e você entregará muito mais qualidade de Internet para o seu cliente. Pare de entregar o '''8.8.8.8''' para os seus clientes, você está contribuindo para uma Internet mais lenta, sem a qualidade que o seu cliente merece. Investi meu tempo, que é muito pouco, para deixar esse documento para a comunidade, para você melhorar o seu ISP, para dar um UP! nele, então vamos começar 2023 com o pé direito. O que acha?&lt;br /&gt;
&lt;br /&gt;
Como prova de conceito, uma imagem abaixo onde temos uma Rede em produção de DNS(s) Recursivos Anycast e apontando exatamente o momento em que houve alguma situação que fez com que as queries de DNS, convergissem de um node para outro, de forma transparente e automática para o cliente. Podemos notar também que ao ser resolvido o problema, o tráfego retornou para o seu node correto:&lt;br /&gt;
[[Arquivo:Convergencia.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== KINDNS (Stands for Knowledge-Sharing and Instantiating Norms for DNS and Naming Security) ==&lt;br /&gt;
Achou que havia terminado? Agora que você tem a capacidade de montar uma '''Rede de DNS Recursivo''' com todas essas features acima, com todas as ferramentas que foram comentadas, o que acha de certificar o que fez?&lt;br /&gt;
&lt;br /&gt;
Assim como o [https://www.manrs.org/ MANRS] veio para certificar nosso sistema de roteamento na Internet, agora temos o [https://kindns.org/ KINDNS] para certificar que nossos sistemas de DNS estão bem feitos e dentro dos padrões de segurança. Existem '''7 ações''' que podem ser certificadas para nossos DNS Recursivos e estão aqui em https://kindns.org/shared-private-resolvers/. Com essa nossa documentação, se bem aplicada, você pode se candidatar ao KINDNS e ter seu ASN listado aqui https://kindns.org/participants/&lt;br /&gt;
&lt;br /&gt;
Obter e manter o '''MANRS''' e '''KINDNS''' demonstra seu compromisso com as Boas Práticas, contribui para termos uma '''Internet''' mais segura e te abre portas para novos negócios que possam exigir essas conformidades.&lt;br /&gt;
&lt;br /&gt;
Autor: [[Usuário:Gondim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Infraestrutura]]&lt;br /&gt;
__FORCARTDC__&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=3961</id>
		<title>Usuário:Gondim</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Usu%C3%A1rio:Gondim&amp;diff=3961"/>
		<updated>2025-10-28T11:49:18Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Marcelo Gondim da Cunha'''&lt;br /&gt;
[[Arquivo:Gondim paisagem.jpg|esquerda|commoldura]]&lt;br /&gt;
&lt;br /&gt;
'''Contribuições e trabalhos:'''&lt;br /&gt;
&lt;br /&gt;
* Administração de Sistemas Unix-Like desde 1996.&lt;br /&gt;
* Consultor na Conectiva S/A - Unidade Rio em 2000.&lt;br /&gt;
** Autor do projeto TuxFrw - https://github.com/gondimcodes/tuxfrw e https://github.com/gondimcodes/tuxfrw-nft&lt;br /&gt;
* Administração de sistemas BSD pela FreeBSD Brasil em 2010.&lt;br /&gt;
* Direção do AS53135 - Nettel Telecomunicações entre 2003 e 2021 atingindo a marca de 41.000 assinantes. Gerando qualidade na entrega de serviços e implantando boas práticas como: &lt;br /&gt;
&lt;br /&gt;
a) IPv6.&lt;br /&gt;
&lt;br /&gt;
b) MANRS.&lt;br /&gt;
&lt;br /&gt;
c) RPKI.&lt;br /&gt;
&lt;br /&gt;
d) CPEs com firmware baseada na BCOP &amp;lt;nowiki&amp;gt;https://www.m3aawg.org/sites/default/files/lac-bcop-1-m3aawg-v1-portuguese-final.pdf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** SOC Specialist na Brasil TecPar (AS262907) de 2022 a 2025. Um milhão de clientes. Responsável pelas estratégias de mitigação anti-DDoS atendendo as Operações de RJ, SP, RS, SC, MT e MS.&lt;br /&gt;
'''Palestras ministradas:'''&lt;br /&gt;
&lt;br /&gt;
* Semana da Informática UERJ 2002 - TuxFrw.&lt;br /&gt;
* CONISLI 2003 - TuxFrw.&lt;br /&gt;
* CONISLI 2004 - Fazendo compras com Gentoo Linux - Palestra sobre a distribuição Linux e suas ferramentas fantásticas.&lt;br /&gt;
* CONISLI 2004 - OpenVPN - Palestra sobre como criar VPNs seguras com OpenVPN e diferenças entre ele e o IPSec.&lt;br /&gt;
* CONISLI 2005 - SPoP (Security Point of Presence) com OpenVPN - Como utilizar túneis encriptados do OpenVPN para acessar a Internet de forma segura, onde quer que esteja.&lt;br /&gt;
* SECOMP 2005 UNIFEI - TuxFrw.&lt;br /&gt;
&lt;br /&gt;
* Debconf19 2019 - [https://debconf19.debconf.org/talks/4-debian-na-vida-de-uma-operadora-de-telecom/ Debian na vida de uma operadora de Telecom], [https://www.youtube.com/watch?v=vQSTslUZy8k&amp;amp;list=PLYUtdmpYPTTJDtwgD8AtxzFJ9t_URhFMK&amp;amp;index=35 vídeo] e [https://salsa.debian.org/debconf-team/public/share/debconf19/raw/master/slides/4-debian-na-vida-de-uma-operadora-de-telecom.pdf?inline=false pdf].&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=5uOFtkplDts FiqueEmCasaUseDebian - CGNAT com NFTables] e [https://www.youtube.com/watch?v=Wz2IAg6MMlU SysAdmin apps].&lt;br /&gt;
&lt;br /&gt;
'''Artigos desenvolvidos para a comunidade do Brasil Peering Fórum:'''&lt;br /&gt;
&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_na_pratica CGNAT na pratica].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Acesso_via_IPv6_Link-Local Acesso via IPv6 Link-Local].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/MANRS MANRS].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/CGNAT_Bulk_Port_Allocation_com_DPDK CGNAT Bulk Port Allocation com DPDK].&lt;br /&gt;
* [https://wiki.brasilpeeringforum.org/w/Servidor_de_Logs Servidor de Logs].&lt;br /&gt;
* [[DNS Recursivo Anycast Hyperlocal|DNS Anycast com Hyperlocal]].&lt;br /&gt;
* [[Recomendações sobre Mitigação DDoS]]&lt;br /&gt;
* [[Portas de Amplificação DDoS e Botnets]]&lt;br /&gt;
* [[Static Loop - um erro que pode matar seu ISP/ITP]]&lt;br /&gt;
* [[Identificando e neutralizando uma Botnet]]&lt;br /&gt;
&lt;br /&gt;
'''Tutorial:'''&lt;br /&gt;
&lt;br /&gt;
* [https://bit.ly/2saumHK Segurança de roteamento: MANRS (Mutually Agreed Norms for Routing Security) - Tutoriais NIC.br em 09/12/2019].&lt;br /&gt;
&lt;br /&gt;
'''[https://www.manrs.org/about/advisory-group/members/ MANRS Advisory Group Member (2020-2021)]'''.&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/watch?v=oahQkGx8urY '''Live sobre MANRS com Leonardo Furtado'''].&lt;br /&gt;
&lt;br /&gt;
Criação da Wiki ISPUP! em 24/12/2022.&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 6 do NIC.br 28/04/2023''' - &amp;quot;'''CONCEITOS E IMPLEMENTAÇÃO DE CGNAT'''&amp;quot;. Material [https://semanacap.bcp.nic.br/6-online/ aqui] e vídeo aula [https://www.youtube.com/watch?v=1q7J3NkQVSc aqui].&lt;br /&gt;
&lt;br /&gt;
'''Semana de Capacitação 10 do NIC.br 01/07/2025''' - &amp;quot;'''Teste para padrões técnicos modernos de Internet e segurança: IPv6, DNSSEC, TLS, HTTPS e HSTS'''&amp;quot;'''.''' Material [https://semanacap.bcp.nic.br/semana-de-capacitacao-online-edicao-10-2025/ aqui] e vídeo aula [https://www.youtube.com/watch?v=55RBnGQhi2o aqui].&lt;br /&gt;
&lt;br /&gt;
'''IX Fórum Regional Sudeste (Rio de Janeiro) 24/10/2025''' com a palestra &amp;quot;'''Segurança com o pé direito'''&amp;quot; pode ser baixada [https://regional.forum.ix.br/files/apresentacao/arquivo/2307/gondim.pdf aqui].&lt;br /&gt;
&lt;br /&gt;
'''Webinar:'''&lt;br /&gt;
&lt;br /&gt;
Proteção e Mitigação de ataques DDoS em 10/09/2024 às 20:00 UTC -3. Site da chamada [https://gdg.community.dev/events/details/google-gdg-sinop-presents-webinar-ao-vivo-protecao-e-mitigacao-de-ataques-ddos/ aqui] e o vídeo da live no Youtube [https://www.youtube.com/live/7VIaoDQaLQE aqui].&lt;br /&gt;
&lt;br /&gt;
'''Podcast:'''&lt;br /&gt;
&lt;br /&gt;
[https://www.youtube.com/live/x4fxtma4eyQ Segurança de Rede e Infraestrutura para 2025: Preparando os ISPs para o futuro!]&lt;br /&gt;
&lt;br /&gt;
'''Contatos:'''&lt;br /&gt;
&lt;br /&gt;
Telegram: '''@Marcelo_Gondim'''&lt;br /&gt;
&lt;br /&gt;
WhatsApp: +55 (22) 99743-9060&lt;br /&gt;
&lt;br /&gt;
E-mail: '''gondim at ispup.com.br'''&lt;br /&gt;
&lt;br /&gt;
Linkedin: https://www.linkedin.com/in/marcelo-gondim-sysadmin/&lt;br /&gt;
&lt;br /&gt;
Meu Github: https://github.com/gondimcodes&lt;br /&gt;
&lt;br /&gt;
== Mini-CV ==&lt;br /&gt;
'''Marcelo Gondim''' começou sua carreira como desenvolvedor de software em COBOL e Clipper entre 1992 e 1995. Em 1996 foi responsável por desenvolver um sistema concorrente com o RENPAC da Embratel para acesso ao SISCOMEX e implantou a Internet para fins comerciais na empresa DATABRAS. Trabalhou como consultor e instrutor de GNU/Linux na Conectiva S/A em 2000. Em 2003 se tornou consultor de diversos Provedores de Internet na Região dos Lagos - RJ e onde acabou se tornando CTO da Nettel Telecomunicações (AS53135) com 42.000 assinantes. Implantou IPv6 iniciando em 2013 e se tornou participante do MANRS com diversas contribuições com artigos e palestras. Trabalhou como Especialista em Redes e SOC (Security Operations Center) na Brasil TecPar AS262907 entre 2022 e 2025, onde implementou boas práticas, tratamentos de incidentes relacionados ao ASN, desenvolveu as estratégias de Mitigação DDoS e uma Rede de DNS Recursivo Anycast espalhada pelo RS, RJ, SP, SC MT e MS, também certificada KINDNS. Fundador da empresa ISPFocus especializada em Tecnologia da Informação e boas práticas para ISPs.&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3951</id>
		<title>DNS Recursivo Anycast Hyperlocal</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3951"/>
		<updated>2025-09-16T02:24:25Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
==Introdução==&lt;br /&gt;
Você sabe como funciona a Internet? Essa é uma pergunta que meu amigo '''Thiago Ayub''' sempre faz aos seus candidatos à vagas de emprego e não importa o quanto tenham de experiência em '''Engenharia de Redes''', todos sempre travam nesse momento. Todos estão sempre prontos e preparados para resolver os problemas mais cabeludos em '''BGP''', '''OSPF''', '''MPLS''', etc mas travam com essa simples pergunta. Para contextualizar e visualizarmos melhor vamos nos atentar à imagem abaixo e uma explicação simplificada de como funciona:&lt;br /&gt;
[[Arquivo:Dns hierarquia.png|esquerda|commoldura]]&lt;br /&gt;
Tudo começa com um usuário sentado confortavelmente e querendo acessar um conteúdo disponível na Internet. Ele digita em seu navegador preferido a URL: '''&amp;lt;nowiki&amp;gt;https://wiki.brasilpeeringforum.org&amp;lt;/nowiki&amp;gt;''',&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;1)&amp;lt;/big&amp;gt;''' &amp;lt;big&amp;gt;O&amp;lt;/big&amp;gt; &amp;lt;big&amp;gt;navegador irá requisitar do '''DNS Recursivo''' utilizado pelo usuário, o '''endereço IP''' que responde pelo nome '''wiki.'''&amp;lt;/big&amp;gt;'''brasilpeeringforum.org'''&amp;lt;big&amp;gt;. Isso porque todos os acessos se dão na Internet através do '''endereço''' '''IP''' e não através do '''nome'''. Imaginem se tivéssemos que decorar os endereços IPs de todos os sites e serviços que quiséssemos acessar na Internet?&amp;lt;/big&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;big&amp;gt;'''2)''' Nosso DNS Recursivo checa se a informação consta em seu cache.&amp;lt;/big&amp;gt; Se a informação existir ela é devolvida ao navegador do usuário e aí este consegue acessar o site.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Do contrário o DNS Recursivo pergunta ao '''Root Server''' quem é o '''TLD (Top Level Domain)''' responsável para atender a requisição. &lt;br /&gt;
&lt;br /&gt;
'''4)''' O '''Root Server''' informa ao DNS Recursivo o endereço do '''TLD responsável'''. No Brasil o '''TLD''' responsável pelo '''.br''' seria o '''Registro.br'''.&lt;br /&gt;
&lt;br /&gt;
'''5)''' O DNS Recursivo pergunta ao '''TLD''' sobre '''wiki.brasilpeeringforum.org''' e este responde com os endereços IP dos '''DNS Autoritativos''' responsáveis pelo domínio '''brasilpeeringforum.org.'''&lt;br /&gt;
&lt;br /&gt;
'''6)''' O DNS Recursivo pergunta aos '''DNS Autoritativos''' pelo '''wiki.brasilpeeringforum.org''' e este responde com o '''endereço IP'''.&lt;br /&gt;
&lt;br /&gt;
'''7)''' Por último o DNS Recursivo devolve a informação para o navegador do usuário.&lt;br /&gt;
&lt;br /&gt;
Como que se dá a comunicação entre os '''DNS(s) Recursivos, Root Servers, TLDs''' e '''Autoritativos'''? Como que o navegador do usuário, após receber o IP do site, consegue chegar no servidor que tem o conteúdo? Isso só é possível devido ao protocolo chamado '''BGP (Border Gateway Protocol)''', todos os caminhos que conhecemos como rotas de destino, são anunciadas por milhares de participantes na '''Internet''' conhecidos como '''AS (Autonomous System)''', esses participantes se interligam para disponibilizar conteúdos e acessos pelo mundo aos milhares de usuários. É uma imensa rede colaborativa formada por Empresas, Universidades, Governos e todos que queiram se interconectar. Percebam que sem o '''BGP''', que serve de caminho para chegarmos nos conteúdos e sem o '''DNS (Domain Name System)''' para traduzir o nome para o endereço IP, a '''Internet''' não funcionaria e por isso precisamos cuidar muito bem desses dois serviços.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Mas não acaba por aí. O '''DNS Recursivo''' tem um papel muito importante para o Provedor de Internet e que envolve segurança, qualidade de acesso à Internet e a disponibilidade do serviço entregue ao cliente. Quando bem configurado acelera as consultas dos acessos graças ao seu cache interno, mas para que isso seja percebido pelo assinante, é necessário que esteja o mais próximo possível do seu cliente.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Um erro que destrói a qualidade do nosso serviço ==&lt;br /&gt;
Um erro muito comum que muitas operadoras cometem é utilizar DNS Recursivo externo, como o '''8.8.8.8''', '''1.1.1.1''' e outros, para seus clientes. Quanto mais próximo dos seus clientes, mais qualidade de serviço estará entregando a eles. Conteúdos serão entregues mais rapidamente pois serão resolvidos e armazenados em caches locais e não consultados remotamente na Internet. Para falar mais sobre isso, te convido leitor desse documento, que assista essa palestra do '''Thiago Ayub''' no '''GTER 51/GTS 37''' (2022) '''8.888 MOTIVOS PARA NÃO USAR DNS RECURSIVO EXTERNO EM SEU AS''': https://www.youtube.com/watch?v=Rsvpu5uF2Io&lt;br /&gt;
&lt;br /&gt;
== Objetivo ==&lt;br /&gt;
O objetivo desta documentação não é te ensinar tudo sobre '''DNS''', '''BGP''', '''OSPF''' e nem tão pouco sobre GNU/Linux e sim te mostrar um exemplo de servidor DNS Recursivo implementado pensando em segurança, qualidade e resiliência. Usaremos em todas as nossas documentações o [https://www.debian.org/ Debian GNU/Linux], por ser uma distribuição que considero uma obra de arte criada por uma enorme comunidade séria, com vasta experiência de anos, qualidade no empacotamento dos programas, estável e com uma equipe de segurança excelente e ativa. Caso você leitor, utilize alguma outra distribuição GNU/Linux, todo conteúdo apresentado aqui pode ser aplicado em outras distros, desde que respeitando as particularidades de cada uma.&lt;br /&gt;
&lt;br /&gt;
Aqui construiremos um sistema do tipo '''Anycast''', ou seja, terás o serviço rodando em diversas localidades da sua Rede utilizando o mesmo endereçamento IP e que atenderá seu cliente mais próximo. Em caso de falhas, seus clientes automaticamente e de forma transparente continuarão consultando o DNS mais próximo deles. Para que ele funcione dessa forma você precisará ter uma '''Rede OSPF''' implementada no seu Provedor Internet ou algum outro protocolo como por exemplo o '''ISIS,''' mas esse documento não irá abordar o '''ISIS'''. Também utilizaremos o '''Hyperlocal''' como recurso adicional para gerar algumas proteções de segurança e velocidade na resposta relacionada aos servidores de DNS Raiz da Internet.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
Para exemplificar nosso servidor de DNS Recursivo, usaremos como base das explicações um diagrama demonstrando o uso do DNS Recursivo em uma Rede fictícia. Adotaremos IPs privados e reservados para demonstrar todo o ambiente do Provedor de Internet.&lt;br /&gt;
[[Arquivo:Recursivo99.png|esquerda|miniaturadaimagem|695x695px]]&lt;br /&gt;
Nesse diagrama podemos observar alguns detalhes técnicos como por exemplo: existem '''3 servidores de DNS Recursivo''' posicionados em locais diferentes, que poderiam estar em bairros diferentes e até em cidades diferentes. Em cada servidor teremos '''2 loopbacks''' com os IPs:&lt;br /&gt;
&lt;br /&gt;
'''10.10.10.10/32 - fd00::10:10:10:10/128'''&lt;br /&gt;
&lt;br /&gt;
'''10.10.9.9/32 - fd00::10:10:9:9/128'''&lt;br /&gt;
&lt;br /&gt;
Esses IPs serão entregues pelos concentradores '''PPPoE''' ou '''IPoE''' ('''BNG''') para seus clientes como '''DNS primário''' e '''secundário'''. Podemos usar IPs privados como DNS primário e secundário em um ambiente real? Sim podemos, desde que não sejam IPs que possam ter problemas com as redes privadas dos clientes. Ex.: rede do cliente usando '''192.168.0.0/24'''. Se entregarmos o DNS sendo '''192.168.0.10''' e '''192.168.0.20''' teremos problemas e o cliente ficará sem Internet, porque '''192.168.0.10''' e '''192.168.0.20''' fazem parte da rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
Agora entregando '''10.10.10.10,''' '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9''' não teríamos problemas com a rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
'''Motivos para usarmos IPs privados:'''&lt;br /&gt;
* O principal motivo está relacionado com a segurança, uma vez que sendo um IP privado, não pode sofrer ataques DDoS direcionados diretamente para ele, vindos da Internet.&lt;br /&gt;
* Nem mesmo o cliente da sua rede conhece os '''IPs públicos''' utilizados para recursividade na Internet.&lt;br /&gt;
* Memorizar os IPs '''10.10.10.10''' e '''10.10.9.9''' é tão fácil quanto memorizar o '''8.8.8.8''' e o '''1.1.1.1'''. Mais fácil para o seu técnico guardar essa informação e utilizar onde for necessário.&lt;br /&gt;
Cada servidor DNS Recursivo possui um '''IPv4 público''', aqui representado por '''198.18.x.x/27''' e um '''IPv6 global''' representado por um IP dentro do prefixo '''2001:db8::/32'''. Cada servidor precisa ter os seus próprios IPs e são através destes IPs que as consultas de DNS serão realizadas na Internet.&lt;br /&gt;
&lt;br /&gt;
Nessa topologia usando '''Anycast''', o cliente será sempre atendido pelo '''DNS Recursivo''' mais próximo, desde que os pesos no '''OSPF''' estejam ajustados corretamente.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
== Dados do servidor ==&lt;br /&gt;
Podemos utilizar um sistema virtualizado ou não. Sistemas virtualizados são bem vindos pois são mais simples quando precisamos fazer backups, levantar outros sistemas sem complicações e se precisarmos restaurar rapidamente algum sistema que ficou indisponível por algum motivo. A configuração abaixo tem capacidade para atender algo em torno a '''50.000 assinantes ou mais'''. O DNS Recursivo é um serviço que pode ser utilizado até mesmo em um '''Raspberry Pi''' e atender operações pequenas, nesse caso com o intuito de economizar energia e espaço. Nosso foco aqui é montar uma rede de '''DNS Recursivo Anycast com HyperLocal'''. Como comentei acima o servidor deve ficar o mais próximo dos clientes para termos a '''menor latência possível''' e '''sempre menor que 5ms''' entre o cliente e o servidor.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!CPU&lt;br /&gt;
!Memória&lt;br /&gt;
!Disco&lt;br /&gt;
!Sistema&lt;br /&gt;
|-&lt;br /&gt;
|2.4Ghz 4 cores&lt;br /&gt;
|16G DDR4&lt;br /&gt;
|30G&lt;br /&gt;
|Debian 12 amd64 (Bookworm)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Softwares utilizados ==&lt;br /&gt;
* Debian 12 amd64 (Bookworm) instalação mínima.&lt;br /&gt;
&lt;br /&gt;
* [https://frrouting.org/ FRRouting].&lt;br /&gt;
* Unbound.&lt;br /&gt;
* Chrony (NTP/NTS).&lt;br /&gt;
* Shell script em bash.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades que teremos ==&lt;br /&gt;
* Sistema em Anycast.&lt;br /&gt;
* Hyperlocal.&lt;br /&gt;
* Controle de acesso por &amp;lt;abbr&amp;gt;ACL&amp;lt;/abbr&amp;gt;.&lt;br /&gt;
* RPZ (Response Policy Zone).&lt;br /&gt;
* Bloqueio de consultas do tipo ANY.&lt;br /&gt;
* QNAME minimization habilitado. (habilitado por default no Unbound)&lt;br /&gt;
* Recursividade em IPv4 e IPv6.&lt;br /&gt;
* DNSSEC habilitado.&lt;br /&gt;
* &amp;lt;abbr&amp;gt;DoH (DNS&amp;lt;/abbr&amp;gt; over HTTPS) habilitado.&lt;br /&gt;
&lt;br /&gt;
== Monitoramento ==&lt;br /&gt;
O monitoramento é algo bem específico e não é o foco deste documento mas é extremamente importante que você monitore seus servidores de DNS por alguma ferramenta como o Zabbix. Aqui mostrarei apenas como enviar as informações para o Zabbix. Algumas coisas que você deveria monitorar nos servidores de DNS Recursivo:&lt;br /&gt;
* Serviço do unbound parou.&lt;br /&gt;
* Perda de pacotes.&lt;br /&gt;
* Latência alta de pacotes.&lt;br /&gt;
* Lentidão na resolução de queries.&lt;br /&gt;
* CPU alta.&lt;br /&gt;
* Load alto.&lt;br /&gt;
* Memória com uso alto.&lt;br /&gt;
* Disco com pouco espaço.&lt;br /&gt;
* Queda brusca nas queries.&lt;br /&gt;
* A recursividade parou de funcionar.&lt;br /&gt;
* A recursividade voltou a funcionar.&lt;br /&gt;
Este abaixo é um exemplo de monitoramento de um sistema de DNS Recursivo que atende 50.000 assinantes:&lt;br /&gt;
[[Arquivo:Grafana dns.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Configurando a Rede ==&lt;br /&gt;
Nossa documentação será baseada no diagrama apresentado acima e por isso configuraremos apenas um dos três servidores, porque os outros serão configurados da mesma forma, só que com dados diferentes. Para tanto assumirei que já temos um sistema Debian instalado com o mínimo de pacotes e somente com sshd, para que possamos acessar remotamente mais tarde. '''Não instale um ambiente gráfico no servidor''', você não deve querer fazer isso por diversos motivos e os principais: primeiro porque não é um Desktop e segundo porque o ambiente gráfico devoraria toda a memória com recursos que não seriam úteis aqui.&lt;br /&gt;
&lt;br /&gt;
Em '''/etc/network/interfaces''' deixaremos assim:&lt;br /&gt;
 # This file describes the network interfaces available on your system&lt;br /&gt;
 # and how to activate them. For more information, see interfaces(5).&lt;br /&gt;
  &lt;br /&gt;
 source /etc/network/interfaces.d/*&lt;br /&gt;
  &lt;br /&gt;
 # The loopback network interface&lt;br /&gt;
 auto lo&lt;br /&gt;
 iface lo inet loopback&lt;br /&gt;
  &lt;br /&gt;
 auto lo:0&lt;br /&gt;
 iface lo:0 inet static&lt;br /&gt;
       address 10.10.10.10/32&lt;br /&gt;
  &lt;br /&gt;
 auto lo:1&lt;br /&gt;
 iface lo:1 inet static&lt;br /&gt;
       address 10.10.9.9/32&lt;br /&gt;
 &lt;br /&gt;
 auto lo:2&lt;br /&gt;
 iface lo:2 inet6 static&lt;br /&gt;
       address fd00::10:10:10:10/128&lt;br /&gt;
 &lt;br /&gt;
 auto lo:3&lt;br /&gt;
 iface lo:3 inet6 static&lt;br /&gt;
       address fd00::10:10:9:9/128&lt;br /&gt;
  &lt;br /&gt;
 # The primary network interface&lt;br /&gt;
 auto ens18&lt;br /&gt;
 iface ens18 inet static&lt;br /&gt;
         address 198.18.1.10/27&lt;br /&gt;
         gateway 198.18.1.1&lt;br /&gt;
  &lt;br /&gt;
 iface ens18 inet6 static&lt;br /&gt;
         address 2001:db8::faca:198:18:1:10/64&lt;br /&gt;
         gateway 2001:db8::faca:198:18:1:1&lt;br /&gt;
  &lt;br /&gt;
 # The secondary network interface&lt;br /&gt;
 auto ens18:0&lt;br /&gt;
 iface ens18:0 inet static&lt;br /&gt;
         address 172.16.0.6/30&lt;br /&gt;
Nesse cenário temos as duas '''loopbacks''' com os IPs '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10''' e '''fd00::10:10:9:9''' que serão anunciados via OSPF para a rede e serem entregues aos clientes via BNG. Os IPs '''198.18.1.10''' e '''2001:db8::faca:198:18:1:10''' serão usados para fazerem a recursividade na Internet tanto em IPv4 quanto em IPv6. Esses IPs não devem ser divulgados para clientes; os IPs públicos são dedicados apenas para essa finalidade.&lt;br /&gt;
&lt;br /&gt;
== Configuração dos repositórios Debian ==&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list''' conforme abaixo:&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://security.debian.org/debian-security&amp;lt;/nowiki&amp;gt; bookworm-security main contrib non-free non-free-firmware&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian&amp;lt;/nowiki&amp;gt; bookworm main contrib non-free non-free-firmware&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian&amp;lt;/nowiki&amp;gt; bookworm-updates main contrib non-free non-free-firmware&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian&amp;lt;/nowiki&amp;gt; bookworm-backports main contrib non-free non-free-firmware&lt;br /&gt;
Após a configuração vamos instalar alguns pacotes necessários e outros úteis:&lt;br /&gt;
 # apt update &amp;amp;&amp;amp; apt full-upgrade&lt;br /&gt;
 # apt install net-tools nftables htop iotop sipcalc tcpdump curl gnupg rsync wget host dnsutils mtr-tiny bmon sudo tmux whois ethtool dnstop&lt;br /&gt;
&lt;br /&gt;
== Fazendo algum tuning no sistema ==&lt;br /&gt;
Em '''/etc/sysctl.conf''' adicionamos no final do arquivo essas instruções:&lt;br /&gt;
 net.core.rmem_max = 2147483647&lt;br /&gt;
 net.core.wmem_max = 2147483647&lt;br /&gt;
 net.ipv4.tcp_rmem = 4096 87380 2147483647&lt;br /&gt;
 net.ipv4.tcp_wmem = 4096 65536 2147483647&lt;br /&gt;
 net.netfilter.nf_conntrack_buckets = 512000&lt;br /&gt;
 net.netfilter.nf_conntrack_max = 4096000&lt;br /&gt;
 vm.swappiness=10&lt;br /&gt;
Estamos fazendo algumas melhorias de memória, algumas relacionadas a '''conntrack''' porque se for usar um filtro de pacotes stateful, como o '''Netfilter/IPTables''' ou '''Netfilter/NFTables''', o valor default da tabela é pequeno e dependendo da situação, se estourar essa tabela, as consultas de DNS terão problemas também. O DNS Recursivo não deve ficar aberto para qualquer um na Internet, ele deve ser liberado apenas para seus clientes. Podemos fazer através das ACLs do Unbound e pelo filtro de pacotes. O último parâmetro diz respeito ao uso de swap, por padrão o Debian permite o uso de swap após 40% do uso da memória, nesse caso estamos dizendo para o sistema usar o swap com 90% de uso da memória.&lt;br /&gt;
&lt;br /&gt;
Precisamos adicionar o módulo '''nf_conntrack''' em '''/etc/modules''' para que seja carregado em tempo de boot, senão os parâmetros de '''conntrack''' que colocamos em '''/etc/sysctl.conf''' não serão carregados.&lt;br /&gt;
 # echo nf_conntrack &amp;gt;&amp;gt; /etc/modules&lt;br /&gt;
 # modprobe nf_conntrack&lt;br /&gt;
 # sysctl -p&lt;br /&gt;
&lt;br /&gt;
== Instalando o FRRouting ==&lt;br /&gt;
O FRRouting é o programa que usaremos para fazer os anúncios das nossas loopbacks via OSPF. Nesse documento usaremos a versão 10.x e para isso precisaremos configurar o repositório oficial do FRRouting e instalar os pacotes:&lt;br /&gt;
 # curl -s &amp;lt;nowiki&amp;gt;https://deb.frrouting.org/frr/keys.gpg&amp;lt;/nowiki&amp;gt; | tee /usr/share/keyrings/frrouting.gpg &amp;gt; /dev/null&lt;br /&gt;
 # echo &amp;quot;deb [signed-by=/usr/share/keyrings/frrouting.gpg] &amp;lt;nowiki&amp;gt;https://deb.frrouting.org/frr&amp;lt;/nowiki&amp;gt; bookworm frr-10&amp;quot; &amp;gt; /etc/apt/sources.list.d/frr.list&lt;br /&gt;
 # apt update&lt;br /&gt;
 # apt install frr frr-doc frr-pythontools&lt;br /&gt;
Aconselho depois de instalar os pacotes, marcá-los para não atualizar juntamente com os demais pacotes, isso é para evitar de ocorrer alguma atualização no FRRouting, que torne o serviço instável por algum motivo. Não que isso vá ocorrer, mas é melhor fazer essa atualização quando realmente for necessário.&lt;br /&gt;
 # apt-mark hold frr frr-doc frr-pythontools&lt;br /&gt;
Após esse comando acima, o sistema manterá a instalação original do pacote intacta. Para desbloquear basta executar o comando abaixo:&lt;br /&gt;
 # apt-mark unhold frr frr-doc frr-pythontools&lt;br /&gt;
&lt;br /&gt;
== Removendo o APPARMOR ==&lt;br /&gt;
O '''APPARMOR''' às vezes causa mais problemas que solução e se não for fazer uma completa configuração nele, é melhor desabilitá-lo. Para fazer isso efetivamente, o procedimento é esse abaixo:&lt;br /&gt;
 # mkdir -p /etc/default/grub.d&lt;br /&gt;
 # echo 'GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;$GRUB_CMDLINE_LINUX_DEFAULT apparmor=0&amp;quot;' | tee /etc/default/grub.d/apparmor.cfg&lt;br /&gt;
 # update-grub&lt;br /&gt;
 # reboot&lt;br /&gt;
&lt;br /&gt;
== Instalando o Unbound ==&lt;br /&gt;
Nesse momento ainda não iremos configurar o Unbound, apenas instalar o pacote e acertar o ambiente. Vamos instalar o unbound do backports porque este já possui suporte ao DoH que veremos mais à frente.&lt;br /&gt;
 # apt install unbound dns-root-data&lt;br /&gt;
 # mkdir -p /var/log/unbound&lt;br /&gt;
 # touch /var/log/unbound/unbound.log&lt;br /&gt;
 # chown -R unbound:unbound /var/log/unbound/&lt;br /&gt;
 # systemctl restart unbound&lt;br /&gt;
Configurando o logrotate:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/logrotate.d/unbound&lt;br /&gt;
 /var/log/unbound/unbound.log {&lt;br /&gt;
     rotate 5&lt;br /&gt;
     weekly&lt;br /&gt;
     postrotate&lt;br /&gt;
         unbound-control log_reopen&lt;br /&gt;
     endscript&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
Reiniciando o serviço:&lt;br /&gt;
 # systemctl restart logrotate.service&lt;br /&gt;
&lt;br /&gt;
== Desabilitando THP (Transparente Huge Pages) em arquitetura AMD64 ==&lt;br /&gt;
No Debian o '''THP''' vem habilitado como '''always''' e o '''unbound''' por trabalhar bastante com alterações do cache em memória, isso pode acabar causando um consumo crescente de uso de RAM sem necessidade. É uma boa prática desabilitá-lo com os passos abaixo:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/systemd/system/disable-thp.service&lt;br /&gt;
 [Unit]&lt;br /&gt;
 Description=Desativa Transparent Huge Pages (THP)&lt;br /&gt;
 After=network.target&lt;br /&gt;
 &lt;br /&gt;
 [Service]&lt;br /&gt;
 Type=oneshot&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled&amp;quot;&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/defrag&amp;quot;&lt;br /&gt;
 RemainAfterExit=yes&lt;br /&gt;
 &lt;br /&gt;
 [Install]&lt;br /&gt;
 WantedBy=multi-user.target&lt;br /&gt;
 EOF&lt;br /&gt;
Acima configuramos o serviço '''disable-thp.service''' para desabilitar o '''THP''' e abaixo habilitamos no '''systemd''' e iniciamos:&lt;br /&gt;
 # systemctl daemon-reload&lt;br /&gt;
 # systemctl enable --now disable-thp&lt;br /&gt;
&lt;br /&gt;
== Preparando o monitoramento do seu DNS Recursivo ==&lt;br /&gt;
O monitoramento do seu DNS Recursivo é muito importante e para isso vamos usar um '''template para Zabbix''', que modifiquei juntamente com o seu shell script e que enviará os dados para o seu Zabbix server via '''zabbix-sender'''. O projeto original está aqui '''https://github.com/jeftedelima/Unbound-DNS&amp;lt;nowiki/&amp;gt;.''' O xml alterado está aqui '''https://github.com/gondimcodes/template_zabbix_dns_unbound'''. Embora seja antigo é perfeitamente importável no Zabbix 6.0, por exemplo.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;nowiki/&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Teremos um shell script que você precisará colocar no seu '''/etc/crontab'''. No exemplo abaixo assumi que o shell script está em '''/root/scripts'''. De 5 em 5 minutos os dados serão enviados para o seu Zabbix server.&lt;br /&gt;
 */5 * * * *     root    /root/scripts/unboundSend.sh '''IP_zabbix_server''' '''nome_do_host''' 1&amp;gt; /dev/null&lt;br /&gt;
Na linha acima, troque o '''IP_zabbix_server''' pelo '''IP do seu servidor Zabbix''' e o '''nome_do_host''' pelo '''hostname''' '''do seu DNS Recursivo'''. Você precisará instalar o pacote '''zabbix-sender''' no seu DNS Recursivo pois ele será usado para enviar os dados para o Zabbix server.&lt;br /&gt;
&lt;br /&gt;
Abaixo o '''unboundSend.sh''' também alterado com inclusão de mais dados:&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 #       @Jefte de Lima Ferreira&lt;br /&gt;
 #       jeftedelima at gmail dot com&lt;br /&gt;
 #       CRON Example&lt;br /&gt;
 #       Contributor: Marcelo Gondim - gondim at gmail dot com&lt;br /&gt;
 #       */5   **** root sh /home/dir/unboundSend.sh 192.168.10.1 Unbound 1&amp;gt; /dev/null&lt;br /&gt;
 &lt;br /&gt;
 if [ -z ${1} ] || [ -z ${2} ] ; then&lt;br /&gt;
         echo &amp;quot;You need to specify the IP address of zabbix server and hostname of your DNS Unbound on zabbix&amp;quot;&lt;br /&gt;
         echo &amp;quot;Usage example: ./unboundSend.sh 192.168.10.1 UnboundServer&amp;quot;&lt;br /&gt;
         exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
 # ZABBIX_SERVER IP&lt;br /&gt;
 IP_ZABBIX=$1&lt;br /&gt;
 # NAME Unbound on Zabbix&lt;br /&gt;
 NAME_HOST=$2&lt;br /&gt;
 DIR_TEMP=/var/tmp/&lt;br /&gt;
 FILE=&amp;quot;${DIR_TEMP}dump_unbound_control_stats.txt&amp;quot;&lt;br /&gt;
 unbound-control stats &amp;gt; ${FILE}&lt;br /&gt;
 &lt;br /&gt;
 TOTAL_NUM_QUERIES=$(cat ${FILE} | grep -w 'total.num.queries' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEHITS=$(cat ${FILE} | grep -w 'total.num.cachehits' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEMISS=$(cat ${FILE} | grep -w 'total.num.cachemiss' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_PREFETCH=$(cat ${FILE} | grep -w 'total.num.prefetch' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_RECURSIVEREPLIES=$(cat ${FILE} | grep -w 'total.num.recursivereplies' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 TOTAL_REQ_MAX=$(cat ${FILE} | grep -w 'total.requestlist.max' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_AVG=$(cat ${FILE} | grep -w 'total.requestlist.avg' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_OVERWRITTEN=$(cat ${FILE} | grep -w 'total.requestlist.overwritten' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_EXCEEDED=$(cat ${FILE} | grep -w 'total.requestlist.exceeded' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_ALL=$(cat ${FILE} | grep -w 'total.requestlist.current.all' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_USER=$(cat ${FILE} | grep -w 'total.requestlist.current.user' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 TOTAL_TCPUSAGE=$(cat ${FILE} | grep -w 'total.tcpusage' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 NUM_QUERY_TYPE_A=$(cat ${FILE} | grep -w 'num.query.type.A' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NS=$(cat ${FILE} | grep -w 'num.query.type.NS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_MX=$(cat ${FILE} | grep -w 'num.query.type.MX' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TXT=$(cat ${FILE} | grep -w 'num.query.type.TXT' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_PTR=$(cat ${FILE} | grep -w 'num.query.type.PTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_AAAA=$(cat ${FILE} | grep -w 'num.query.type.AAAA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SRV=$(cat ${FILE} | grep -w 'num.query.type.SRV' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SOA=$(cat ${FILE} | grep -w 'num.query.type.SOA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HTTPS=$(cat ${FILE} | grep -w 'num.query.type.HTTPS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TYPE0=$(cat ${FILE} | grep -w 'num.query.type.TYPE0' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_CNAME=$(cat ${FILE} | grep -w 'num.query.type.CNAME' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_WKS=$(cat ${FILE} | grep -w 'num.query.type.WKS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HINFO=$(cat ${FILE} | grep -w 'num.query.type.HINFO' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_X25=$(cat ${FILE} | grep -w 'num.query.type.X25' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NAPTR=$(cat ${FILE} | grep -w 'num.query.type.NAPTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DS=$(cat ${FILE} | grep -w 'num.query.type.DS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DNSKEY=$(cat ${FILE} | grep -w 'num.query.type.DNSKEY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TLSA=$(cat ${FILE} | grep -w 'num.query.type.TLSA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SVCB=$(cat ${FILE} | grep -w 'num.query.type.SVCB' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SPF=$(cat ${FILE} | grep -w 'num.query.type.SPF' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_ANY=$(cat ${FILE} | grep -w 'num.query.type.ANY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_OTHER=$(cat ${FILE} | grep -w 'num.query.type.other' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 NUM_ANSWER_RCODE_NOERROR=$(cat ${FILE} | grep -w 'num.answer.rcode.NOERROR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_NXDOMAIN=$(cat ${FILE} | grep -w 'num.answer.rcode.NXDOMAIN' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_SERVFAIL=$(cat ${FILE} | grep -w 'num.answer.rcode.SERVFAIL' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_REFUSED=$(cat ${FILE} | grep -w 'num.answer.rcode.REFUSED' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_nodata=$(cat ${FILE} | grep -w 'num.answer.rcode.nodata' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_secure=$(cat ${FILE} | grep -w 'num.answer.secure' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 #       Sending info to zabbix_server, if variables is not empty!&lt;br /&gt;
 [ -z ${TOTAL_NUM_QUERIES} ] ||  zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.queries -o $((TOTAL_NUM_QUERIES/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_CACHEHITS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachehits -o $((TOTAL_NUM_CACHEHITS/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_CACHEMISS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachemiss -o $((TOTAL_NUM_CACHEMISS/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_PREFETCH} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.prefetch -o $((TOTAL_NUM_PREFETCH/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_RECURSIVEREPLIES} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.recursivereplies -o $((TOTAL_NUM_RECURSIVEREPLIES/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${TOTAL_REQ_MAX} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.max -o $((TOTAL_REQ_MAX/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_AVG} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.avg -o $((TOTAL_REQ_AVG/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_OVERWRITTEN} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.overwritten -o $((TOTAL_REQ_OVERWRITTEN/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_EXCEEDED} ] ||  zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.exceeded -o $((TOTAL_REQ_EXCEEDED/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_CURRENT_ALL} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.all -o $((TOTAL_REQ_CURRENT_ALL/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_CURRENT_USER} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.user -o $((TOTAL_REQ_CURRENT_USER/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${TOTAL_TCPUSAGE} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.tcpusage -o $((TOTAL_TCPUSAGE/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_A} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.a -o $((NUM_QUERY_TYPE_A/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_NS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ns -o $((NUM_QUERY_TYPE_NS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_MX} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.mx -o $((NUM_QUERY_TYPE_MX/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_TXT} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.txt -o $((NUM_QUERY_TYPE_TXT/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_PTR} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ptr -o $((NUM_QUERY_TYPE_PTR/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_AAAA} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.aaaa -o $((NUM_QUERY_TYPE_AAAA/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SRV} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.srv -o $((NUM_QUERY_TYPE_SRV/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SOA} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.soa -o $((NUM_QUERY_TYPE_SOA/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_HTTPS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.https -o $((NUM_QUERY_TYPE_HTTPS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_TYPE0} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.type0 -o $((NUM_QUERY_TYPE_TYPE0/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_CNAME} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.cname -o $((NUM_QUERY_TYPE_CNAME/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_WKS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.wks -o $((NUM_QUERY_TYPE_WKS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_HINFO} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.hinfo -o $((NUM_QUERY_TYPE_HINFO/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_X25} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.X25 -o $((NUM_QUERY_TYPE_X25/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_NAPTR} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.naptr -o $((NUM_QUERY_TYPE_NAPTR/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_DS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ds -o $((NUM_QUERY_TYPE_DS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_DNSKEY} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.dnskey -o $((NUM_QUERY_TYPE_DNSKEY/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_TLSA} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.tlsa -o $((NUM_QUERY_TYPE_TLSA/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SVCB} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.svcb -o $((NUM_QUERY_TYPE_SVCB/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SPF} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.spf -o $((NUM_QUERY_TYPE_SPF/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_ANY} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.any -o $((NUM_QUERY_TYPE_ANY/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_OTHER} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.other -o $((NUM_QUERY_TYPE_OTHER/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_NOERROR} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NOERROR -o $((NUM_ANSWER_RCODE_NOERROR/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_NXDOMAIN} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NXDOMAIN -o $((NUM_ANSWER_RCODE_NXDOMAIN/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_SERVFAIL} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.SERVFAIL -o $((NUM_ANSWER_RCODE_SERVFAIL/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_REFUSED} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.REFUSED -o $((NUM_ANSWER_RCODE_REFUSED/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_nodata} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.nodata -o $((NUM_ANSWER_RCODE_nodata/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_secure} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.secure -o $((NUM_ANSWER_secure/300))&lt;br /&gt;
No Zabbix será registrado dados como esses abaixo e posteriormente pode ser montado um Grafana com eles:&lt;br /&gt;
[[Arquivo:Zabbix dns01.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns02.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns03.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns04.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Mantendo a hora certa ==&lt;br /&gt;
Vamos instalar agora o Chrony para manter a data e hora certas no sistema:&lt;br /&gt;
 # apt install chrony&lt;br /&gt;
Após a instalação do Chrony edite o arquivo /etc/chrony/chrony.conf, comente e a linha abaixo e adicione seus servidores NTP. Caso não tenha servidores NTP, estou colocando os do NIC.br aqui.&lt;br /&gt;
 #pool 2.debian.pool.ntp.org iburst&lt;br /&gt;
 server a.st1.ntp.br iburst nts&lt;br /&gt;
 server b.st1.ntp.br iburst nts&lt;br /&gt;
 server c.st1.ntp.br iburst nts&lt;br /&gt;
 server d.st1.ntp.br iburst nts&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart chronyd.service&lt;br /&gt;
Cheque com o '''chronyc''' se os servidores estão OK:&lt;br /&gt;
 # chronyc sourcestats&lt;br /&gt;
 Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev&lt;br /&gt;
 ==============================================================================&lt;br /&gt;
 a.st1.ntp.br               10   5  155m     -0.027      0.030    -71us    51us&lt;br /&gt;
 b.st1.ntp.br               11   7  344m     +0.068      0.079    +23ms   382us&lt;br /&gt;
 c.st1.ntp.br                6   3  344m     +0.026      0.037   -124us    92us&lt;br /&gt;
 200.20.186.76               9   3  138m     -0.022      0.031   +172us    42us&lt;br /&gt;
&lt;br /&gt;
 # chronyc sources&lt;br /&gt;
 MS Name/IP address         Stratum Poll Reach LastRx Last sample&lt;br /&gt;
 ===============================================================================&lt;br /&gt;
 ^* a.st1.ntp.br                  1  10   377   588   +487us[ +397us] +/-   12ms&lt;br /&gt;
 ^- b.st1.ntp.br                  2  10   377   830    +23ms[  +23ms] +/-   49ms&lt;br /&gt;
 ^+ c.st1.ntp.br                  2  10    21  1038   -147us[ -242us] +/-   17ms&lt;br /&gt;
 ^+ 200.20.186.76                 1  10   377  1032   +381us[ +285us] +/-   15ms&lt;br /&gt;
&lt;br /&gt;
== Configurando o FRRouting ==&lt;br /&gt;
Nesse ponto iremos configurar o '''FRRouting''' para enviar os IPs das '''loopbacks''' e o '''/30''' para o nosso PE do diagrama. Em '''/etc/frr/daemons''' habilite o parâmetro conforme abaixo:&lt;br /&gt;
 ospfd=yes&lt;br /&gt;
Edite o arquivo '''/etc/frr/frr.conf''' e deixe com o conteúdo abaixo, para ficar conforme nosso diagrama do projeto. Apenas troque '''&amp;lt;SENHA&amp;gt;''' por uma senha para fechar o OSPF com mais segurança. Essa senha deve ser usada dos dois lados.&lt;br /&gt;
 frr version 10.2.1&lt;br /&gt;
 frr defaults traditional&lt;br /&gt;
 hostname dns-recursivo-01&lt;br /&gt;
 log syslog informational&lt;br /&gt;
 no ip forwarding&lt;br /&gt;
 no ipv6 forwarding&lt;br /&gt;
 service integrated-vtysh-config&lt;br /&gt;
 !&lt;br /&gt;
 interface ens18&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf message-digest-key 5 md5 &amp;lt;SENHA&amp;gt;&lt;br /&gt;
  ip ospf network point-to-point&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 network point-to-point&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 interface lo&lt;br /&gt;
  description LOOPBACKS&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf passive&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 passive&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf&lt;br /&gt;
  ospf router-id 172.16.0.6&lt;br /&gt;
  area 0.0.0.0 authentication message-digest&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf6&lt;br /&gt;
  ospf6 router-id 172.16.0.6&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart frr.service&lt;br /&gt;
Cheque se está tudo OK com o OSPF e verifique no PE se está recebendo os prefixos anunciados.&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL&lt;br /&gt;
 172.16.0.5     1 Full/-          10m49s            35.310s 172.16.0.5   ens18:172.16.0.6                  0     0     0&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri    DeadTime    State/IfState         Duration I/F[State]&lt;br /&gt;
 172.16.0.5       1    00:00:30     Full/PointToPoint 25d22:53:47 ens18[PointToPoint]&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor detail'&lt;br /&gt;
 &lt;br /&gt;
  Neighbor 172.16.0.5, interface address 172.16.0.5&lt;br /&gt;
     In the area 0.0.0.0 via interface ens18&lt;br /&gt;
     Neighbor priority is 1, State is Full/-, 5 state changes&lt;br /&gt;
     Most recent state change statistics:&lt;br /&gt;
       Progressive change 21w3d15h ago&lt;br /&gt;
     DR is 0.0.0.0, BDR is 0.0.0.0&lt;br /&gt;
     Options 18 *|-|-|EA|-|-|E|-&lt;br /&gt;
     Dead timer due in 34.685s&lt;br /&gt;
     Database Summary List 0&lt;br /&gt;
     Link State Request List 0&lt;br /&gt;
     Link State Retransmission List 0&lt;br /&gt;
     Thread Inactivity Timer on&lt;br /&gt;
     Thread Database Description Retransmision off&lt;br /&gt;
     Thread Link State Request Retransmission on&lt;br /&gt;
     Thread Link State Update Retransmission on&lt;br /&gt;
 &lt;br /&gt;
     Graceful restart Helper info:&lt;br /&gt;
       Graceful Restart HELPER Status : None&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor detail'&lt;br /&gt;
  Neighbor 172.16.0.5%ens18&lt;br /&gt;
     Area 0.0.0.0 via interface ens18 (ifindex 4)&lt;br /&gt;
     His IfIndex: 60 Link-local address: fe80::469b:c1ff:fed6:43ee&lt;br /&gt;
     State Full for a duration of 25d22:57:14&lt;br /&gt;
     His choice of DR/BDR 0.0.0.0/0.0.0.0, Priority 1&lt;br /&gt;
     DbDesc status: Master SeqNum: 0xb94b0000&lt;br /&gt;
     Summary-List: 0 LSAs&lt;br /&gt;
     Request-List: 0 LSAs&lt;br /&gt;
     Retrans-List: 0 LSAs&lt;br /&gt;
     0 Pending LSAs for DbDesc in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSReq in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSAck in Time 00:00:00 [thread off]&lt;br /&gt;
     Authentication header not present&lt;br /&gt;
&lt;br /&gt;
== Configurando o Unbound ==&lt;br /&gt;
Abaixo a configuração que usaremos nos servidores atentando para o detalhe do '''num-threads''', esse deve ter o valor igual ao número de CPUs do servidor.&lt;br /&gt;
&lt;br /&gt;
Também os IPs utilizados em '''outgoing-interface''' que serão diferentes em cada servidor, esses serão os IPs usados para '''recursividade'''. Consulte o manual do Unbound para obter mais informações sobre cada parâmetro listado na configuração.&lt;br /&gt;
&lt;br /&gt;
O tuning no Unbound pode ser alterado conforme abaixo:&lt;br /&gt;
 num-threads = nº CPUs&lt;br /&gt;
 so-reuseport = yes&lt;br /&gt;
 *-slabs = potência de 2 próximo ao num-threads&lt;br /&gt;
 msg-cache-size = 1g (quantidade de memória pra usar de cache)&lt;br /&gt;
 rrset-cache-size = 2 * msg-cache-size&lt;br /&gt;
 outgoing-range = 8192&lt;br /&gt;
 num-queries-per-thread = 4096&lt;br /&gt;
 so-rcvbuf e so-sndbuf = 4m ou 8m para servidores com muita requisição&lt;br /&gt;
Agora vamos criar nosso arquivo de configuração base em '''/etc/unbound/unbound.conf.d/local.conf''':&lt;br /&gt;
 server:&lt;br /&gt;
         verbosity: 1&lt;br /&gt;
         statistics-interval: 0&lt;br /&gt;
         statistics-cumulative: no&lt;br /&gt;
         extended-statistics: yes&lt;br /&gt;
         num-threads: 4&lt;br /&gt;
         serve-expired: yes&lt;br /&gt;
         interface: 127.0.0.1&lt;br /&gt;
         interface: 10.10.10.10&lt;br /&gt;
         interface: 10.10.9.9&lt;br /&gt;
         interface: 172.16.0.6&lt;br /&gt;
         interface: fd00::10:10:10:10&lt;br /&gt;
         interface: fd00::10:10:9:9&lt;br /&gt;
         interface: ::1&lt;br /&gt;
         interface-automatic: no&lt;br /&gt;
         outgoing-interface: 198.18.1.10&lt;br /&gt;
         outgoing-interface: 2001:db8::faca:198:18:1:10&lt;br /&gt;
         outgoing-range: 8192&lt;br /&gt;
         outgoing-num-tcp: 1024&lt;br /&gt;
         incoming-num-tcp: 2048&lt;br /&gt;
         so-rcvbuf: 4m&lt;br /&gt;
         so-sndbuf: 4m&lt;br /&gt;
         so-reuseport: yes&lt;br /&gt;
         edns-buffer-size: 1232&lt;br /&gt;
         msg-cache-size: 1g&lt;br /&gt;
         msg-cache-slabs: 4&lt;br /&gt;
         num-queries-per-thread: 4096&lt;br /&gt;
         rrset-cache-size: 2g&lt;br /&gt;
         rrset-cache-slabs: 4&lt;br /&gt;
         infra-cache-slabs: 4&lt;br /&gt;
         do-ip4: yes&lt;br /&gt;
         do-ip6: yes&lt;br /&gt;
         do-udp: yes&lt;br /&gt;
         do-tcp: yes&lt;br /&gt;
         chroot: &amp;quot;&amp;quot;&lt;br /&gt;
         username: &amp;quot;unbound&amp;quot;&lt;br /&gt;
         directory: &amp;quot;/etc/unbound&amp;quot;&lt;br /&gt;
         logfile: &amp;quot;/var/log/unbound/unbound.log&amp;quot;&lt;br /&gt;
         use-syslog: no&lt;br /&gt;
         log-time-ascii: yes&lt;br /&gt;
         log-queries: no&lt;br /&gt;
         pidfile: &amp;quot;/var/run/unbound.pid&amp;quot;&lt;br /&gt;
         root-hints: &amp;quot;/usr/share/dns/root.hints&amp;quot;&lt;br /&gt;
         hide-identity: yes&lt;br /&gt;
         hide-version: yes&lt;br /&gt;
         unwanted-reply-threshold: 10000000&lt;br /&gt;
         prefetch: yes&lt;br /&gt;
         prefetch-key: yes&lt;br /&gt;
         rrset-roundrobin: yes&lt;br /&gt;
         minimal-responses: yes&lt;br /&gt;
         module-config: &amp;quot;respip validator iterator&amp;quot;&lt;br /&gt;
         val-clean-additional: yes&lt;br /&gt;
         val-log-level: 1&lt;br /&gt;
         key-cache-slabs: 4&lt;br /&gt;
         deny-any: yes&lt;br /&gt;
         cache-min-ttl: 60&lt;br /&gt;
         key-cache-size: 128m&lt;br /&gt;
         neg-cache-size: 64m&lt;br /&gt;
         cache-max-ttl: 86400&lt;br /&gt;
         infra-cache-numhosts: 100000&lt;br /&gt;
         access-control: 198.18.0.0/22 allow&lt;br /&gt;
         access-control: 2001:db8::/32 allow&lt;br /&gt;
  &lt;br /&gt;
 rpz:&lt;br /&gt;
   name: rpz.block.host.local.zone&lt;br /&gt;
   zonefile: /etc/unbound/rpz.block.hosts.zone&lt;br /&gt;
   rpz-action-override: nxdomain&lt;br /&gt;
  &lt;br /&gt;
 python:&lt;br /&gt;
  &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;.&amp;quot;&lt;br /&gt;
     master: &amp;quot;b.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;c.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;d.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;f.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;g.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;k.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/root.zone&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;arpa.&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/arpa.zone&amp;quot;&lt;br /&gt;
No parâmetro '''interface''' colocamos os IPs que serão usados para consulta dos clientes como o '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10 e fd00::10:10:9:9'''. Ali repare que coloquei também o IP privado '''172.16.0.6''', isso porque cada servidor terá o seu IP privado e este deve ser usado pelo seu sistema de monitoramento para checar cada servidor. No '''outgoing-interface''' teremos os IPs, tanto '''IPv4''' quanto '''IPv6''', para que seja feita a recursividade na Internet utilizando eles. Não tem '''IPv6''' ainda na sua rede? Dê uma olhada nesse artigo. Outro parâmetro importante é o '''access-control''' e é através dele que liberamos os prefixos IP para consultarem no nosso DNS Recursivo. No exemplo estou liberando todo o prefixo '''198.18.0.0/22''' e o prefixo '''2001:db8::/32'''. Além da ACL no Unbound, recomendo que crie um filtro de pacotes com iptables ou nftables protegendo seu sistema e liberando as portas '''53/UDP''', '''53/TCP,'''  '''443/TCP e 853/TCP''' apenas para seus clientes. Falarei sobre a '''443/TCP e 853/TCP''' mais para frente nessa mesma documentação.&lt;br /&gt;
&lt;br /&gt;
Agora criaremos o arquivo '''RPZ''' ('''Response Policy Zones'''). Esse arquivo contém os sites que serão bloqueados via '''&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; Recursivo'''. São aqueles sites que às vezes você recebe um Ofício da Justiça solicitando o bloqueio deles. Não entrarei no mérito da efetividade desses bloqueios, porque muitos de vocês sabem que tecnicamente, existem formas de se fazer um bypass através desses bloqueios. Contudo vamos deixar nosso ambiente preparado para esses bloqueios e por isso crie o arquivo '''/etc/unbound/rpz.block.hosts.zone''' com esse conteúdo de exemplo:&lt;br /&gt;
 $TTL 2h&lt;br /&gt;
 @ IN SOA localhost. root.localhost. (2 6h 1h 1w 2h)&lt;br /&gt;
   IN NS  localhost.&lt;br /&gt;
 ; RPZ manual block hosts&lt;br /&gt;
 *.josedascoves.com CNAME .&lt;br /&gt;
 josedascoves.com CNAME .&lt;br /&gt;
No exemplo acima estamos bloqueando qualquer consulta de DNS para '''josedascoves.com''' ou qualquer coisa '''.josedascoves.com'''.&lt;br /&gt;
&lt;br /&gt;
Para testar podemos fazer assim do próprio servidor:&lt;br /&gt;
 # host josedascoves.com ::1&lt;br /&gt;
 Using domain server:&lt;br /&gt;
 Name: ::1&lt;br /&gt;
 Address: ::1#53&lt;br /&gt;
 Aliases:&lt;br /&gt;
 &lt;br /&gt;
 Host josedascoves.com not found: 3(NXDOMAIN)&lt;br /&gt;
Se a resposta for '''NXDOMAIN''' então está funcionando o bloqueio. Para incluir novos bloqueios basta adicionar os domínios, um abaixo do outro, conforme o exemplo que coloquei no arquivo RPZ.&lt;br /&gt;
&lt;br /&gt;
== Acertando o resolv.conf ==&lt;br /&gt;
Vamos modificar nosso /etc/resolv.conf para utilizar DNS externo. Sim você deve estar se perguntando em qual situação isso seria utilizado. Primeiro entenda que o Unbound não irá utilizar o DNS externo para fazer as consultas na Internet e sim, qualquer teste que você faça do servidor precisará apontar para o Unbound usando os IPs '''127.0.0.1''' ou '''::1'''. Faremos isso pela seguinte situação: imagine que o daemon unbound morreu mas você ainda continua com conectividade na Internet. Você conseguiria acessar qualquer local na Internet através do IP mas não através do hostname porque não conseguiria resolver nomes, seu unbound estaria fora do ar. Imagine ainda que você gostaria que seu servidor te avisasse do problema via Telegram ou e-mail. Por isso estamos utilizando um DNS externo no '''/etc/resolv.conf''', apenas para essas situações. Se você não quiser utilizar desse recurso, pode usar o '''127.0.0.1''' e '''::1''' no lugar.&lt;br /&gt;
 nameserver 8.8.8.8&lt;br /&gt;
 nameserver 8.8.4.4&lt;br /&gt;
 nameserver 2001:4860:4860::8888&lt;br /&gt;
&lt;br /&gt;
== Script de teste de recursividade ==&lt;br /&gt;
Estamos montando uma '''Rede de DNS Recursivo Anycast''', então é muito importante que você monitore essa rede para saber se algum node morreu e iniciar o troubleshooting, resolver o problema e levantar o sistema novamente. Tudo isso é importante mas o cliente não deve ficar esperando até você resolver o problema, seu sistema precisa ser inteligente o suficiente para se remover da Rede quando tiver um problema e se inserir novamente, quando o problema estiver sido solucionado. Se você montar uma Rede de DNS e um dos nodes apresentar algum problema, todos os clientes atendidos por aquele node migrarão automaticamente e transparentemente para outro '''DNS Recursivo Anycast''' mais próximo. Isso se chama '''disponibilidade'''.&lt;br /&gt;
&lt;br /&gt;
O script '''/root/scripts/checa_dns.sh''' abaixo tem a função de fazer os testes de recursividade e checar se o daemon do unbound continua rodando. Se algo acontecer, ele para o anúncio do '''10.10.10.10''' e '''10.10.9.9''' e retorna eles quando tudo estiver resolvido.&lt;br /&gt;
 # mkdir /root/scripts&lt;br /&gt;
&lt;br /&gt;
 #!/usr/bin/env bash&lt;br /&gt;
 #Script para teste de DNS v2.1&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 #Informe um domínio por linha:&lt;br /&gt;
 dominios_testar=(&lt;br /&gt;
 www.google.com&lt;br /&gt;
 www.terra.com.br&lt;br /&gt;
 www.uol.com.br&lt;br /&gt;
 www.globo.com&lt;br /&gt;
 www.facebook.com&lt;br /&gt;
 www.youtube.com&lt;br /&gt;
 www.twitch.com&lt;br /&gt;
 www.discord.com&lt;br /&gt;
 www.debian.org&lt;br /&gt;
 www.redhat.com&lt;br /&gt;
 )&lt;br /&gt;
 corte_taxa_falha=100 #Porcentagem de falha para executar uma ação&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 remove_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; != &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no description' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME morreu!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 adiciona_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; == &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'description LOOPBACKS' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME retornou do inferno!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
 if [ $? -ne 0 ]; then&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME morreu DNS mas tentando levantar!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    systemctl restart unbound&lt;br /&gt;
    systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
    if [ $? -ne 0 ]; then&lt;br /&gt;
       remove_ospf&lt;br /&gt;
       exit&lt;br /&gt;
    fi&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME servico DNS voltou mas tinha morrido!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 qt_falhas=0&lt;br /&gt;
 qt_total=&amp;quot;${#dominios_testar[@]}&amp;quot;&lt;br /&gt;
 echo &amp;quot;total_dominios: $qt_total&amp;quot;&lt;br /&gt;
 for site in &amp;quot;${dominios_testar[@]}&amp;quot;&lt;br /&gt;
 do&lt;br /&gt;
   unbound-control flush $site &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   resolver=&amp;quot;127.0.0.1&amp;quot;&lt;br /&gt;
   echo -e &amp;quot; - dominio $site - $resolver - \c&amp;quot;&lt;br /&gt;
   host $site $resolver &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   if [ $? -ne 0 ]; then&lt;br /&gt;
      ((qt_falhas++))&lt;br /&gt;
      echo -e &amp;quot;[Falhou]&amp;quot;&lt;br /&gt;
   else&lt;br /&gt;
      echo -e &amp;quot;[OK]&amp;quot;&lt;br /&gt;
   fi&lt;br /&gt;
 done&lt;br /&gt;
  &lt;br /&gt;
 taxa_falha=$((qt_falhas*100/qt_total))&lt;br /&gt;
 echo &amp;quot;Falhas $qt_falhas/$qt_total ($taxa_falha%)&amp;quot;&lt;br /&gt;
  &lt;br /&gt;
 if [ &amp;quot;$taxa_falha&amp;quot; -ge &amp;quot;$corte_taxa_falha&amp;quot; ]; then&lt;br /&gt;
    remove_ospf&lt;br /&gt;
    exit&lt;br /&gt;
 fi&lt;br /&gt;
 adiciona_ospf&lt;br /&gt;
Se rodarmos o script manualmente veremos isto:&lt;br /&gt;
 # /root/scripts/checa_dns.sh&lt;br /&gt;
 total_dominios: 10&lt;br /&gt;
  - dominio www.google.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.terra.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.uol.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.globo.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.facebook.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.youtube.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.twitch.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.discord.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.debian.org - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.redhat.com - 127.0.0.1 - [OK]&lt;br /&gt;
 Falhas 0/10 (0%)&lt;br /&gt;
Se acontecer 100% de falhas o script irá remover os anúncios do OSPF. Se o daemon do unbound morrer, ele tentará reiniciá-lo. Se tudo normalizar o script irá retornar os anúncios para o OSPF. Deixei comentado no script as partes que enviariam uma notificação para o Telegram. Existem diversas documentações sobre isso na Internet, eu mesmo tenho uma. Assim que eu publicar aqui, atualizo essa documentação e sinta-se à vontade de modificar como desejar.&lt;br /&gt;
 # chmod 700 /root/scripts/checa_dns.sh&lt;br /&gt;
Adicione a linha abaixo em seu '''/etc/crontab''':&lt;br /&gt;
 */1 *   * * *   root    /root/scripts/checa_dns.sh&lt;br /&gt;
&lt;br /&gt;
== Habilitando o DoH (&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; over HTTPS) - opcional ==&lt;br /&gt;
Para habilitar o '''DoH''' no Unbound é bem simples. O recurso do '''DoH''' vem para trazer mais segurança e privacidade para o usuário. É um recurso muito pouco utilizado ainda mas que seu cliente pode vir a pedir algum dia.&lt;br /&gt;
&lt;br /&gt;
Você precisará gerar certificados SSL legítimos e para isso você poderá usar o '''Let's Encrypt''' só que de uma forma não tão convencional.&lt;br /&gt;
&lt;br /&gt;
Na sequência vamos instalar o Let's Encrypt para gerarmos nosso certificado SSL:&lt;br /&gt;
 # apt install letsencrypt&lt;br /&gt;
Escolha um '''hostname''' para ser usado no nosso '''DoH''' e aponte ele no seu DNS Autoritativo para seus IPs 10.10.10.10 e 10.10.9.9. Aqui vamos usar o seguinte como exemplo: '''doh.brasilpeeringforum.org'''. Para gerarmos nosso certificado iremos usar o tipo '''DNS-01''', ele não necessita que tenhamos um servidor web rodando no servidor e nem tão pouco levanta um serviço na porta 80 para checar o hostname. Ele utiliza o DNS como validador e vai te solicitar que crie um registro '''CNAME''' no seu '''DNS Autoritativo''' para provar que você tem o controle sobre aquele hostname. Antes disso vamos instalar um programa em Python para podermos automatizar nossa renovação de certificado no futuro. Esse programa se encontra '''[https://github.com/joohoi/acme-dns-certbot-joohoi/raw/master/acme-dns-auth.py aqui]''' mas vou deixá-lo abaixo já modificado o interpretador.&lt;br /&gt;
&lt;br /&gt;
Crie o arquivo '''/etc/letsencrypt/acme-dns-auth.py''' com o conteúdo abaixo:&lt;br /&gt;
 #!/usr/bin/env python3&lt;br /&gt;
 import json&lt;br /&gt;
 import os&lt;br /&gt;
 import requests&lt;br /&gt;
 import sys&lt;br /&gt;
 &lt;br /&gt;
 ### EDIT THESE: Configuration values ###&lt;br /&gt;
 &lt;br /&gt;
 # URL to acme-dns instance&lt;br /&gt;
 ACMEDNS_URL = &amp;quot;&amp;lt;nowiki&amp;gt;https://auth.acme-dns.io&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
 # Path for acme-dns credential storage&lt;br /&gt;
 STORAGE_PATH = &amp;quot;/etc/letsencrypt/acmedns.json&amp;quot;&lt;br /&gt;
 # Whitelist for address ranges to allow the updates from&lt;br /&gt;
 # Example: ALLOW_FROM = [&amp;quot;192.168.10.0/24&amp;quot;, &amp;quot;::1/128&amp;quot;]&lt;br /&gt;
 ALLOW_FROM = []&lt;br /&gt;
 # Force re-registration. Overwrites the already existing acme-dns accounts.&lt;br /&gt;
 FORCE_REGISTER = False&lt;br /&gt;
 &lt;br /&gt;
 ###   DO NOT EDIT BELOW THIS POINT   ###&lt;br /&gt;
 ###         HERE BE DRAGONS          ###&lt;br /&gt;
 &lt;br /&gt;
 DOMAIN = os.environ[&amp;quot;CERTBOT_DOMAIN&amp;quot;]&lt;br /&gt;
 if DOMAIN.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
     DOMAIN = DOMAIN[2:]&lt;br /&gt;
 VALIDATION_DOMAIN = &amp;quot;_acme-challenge.&amp;quot;+DOMAIN&lt;br /&gt;
 VALIDATION_TOKEN = os.environ[&amp;quot;CERTBOT_VALIDATION&amp;quot;]&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 class AcmeDnsClient(object):&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
     Handles the communication with ACME-DNS API&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
     def __init__(self, acmedns_url):&lt;br /&gt;
         self.acmedns_url = acmedns_url&lt;br /&gt;
 &lt;br /&gt;
     def register_account(self, allowfrom):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Registers a new ACME-DNS account&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
         if allowfrom:&lt;br /&gt;
             # Include whitelisted networks to the registration call&lt;br /&gt;
             reg_data = {&amp;quot;allowfrom&amp;quot;: allowfrom}&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;,&lt;br /&gt;
                                 data=json.dumps(reg_data))&lt;br /&gt;
         else:&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;)&lt;br /&gt;
         if res.status_code == 201:&lt;br /&gt;
             # The request was successful&lt;br /&gt;
             return res.json()&lt;br /&gt;
         else:&lt;br /&gt;
             # Encountered an error&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to register a new acme-dns &amp;quot;&lt;br /&gt;
                    &amp;quot;account. HTTP status {}, Response body: {}&amp;quot;)&lt;br /&gt;
             print(msg.format(res.status_code, res.text))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def update_txt_record(self, account, txt):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Updates the TXT challenge record to ACME-DNS subdomain.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         update = {&amp;quot;subdomain&amp;quot;: account['subdomain'], &amp;quot;txt&amp;quot;: txt}&lt;br /&gt;
         headers = {&amp;quot;X-Api-User&amp;quot;: account['username'],&lt;br /&gt;
                    &amp;quot;X-Api-Key&amp;quot;: account['password'],&lt;br /&gt;
                    &amp;quot;Content-Type&amp;quot;: &amp;quot;application/json&amp;quot;}&lt;br /&gt;
         res = requests.post(self.acmedns_url+&amp;quot;/update&amp;quot;,&lt;br /&gt;
                             headers=headers,&lt;br /&gt;
                             data=json.dumps(update))&lt;br /&gt;
         if res.status_code == 200:&lt;br /&gt;
             # Successful update&lt;br /&gt;
             return&lt;br /&gt;
         else:&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to update TXT record in &amp;quot;&lt;br /&gt;
                    &amp;quot;acme-dns. \n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request headers:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request body:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response HTTP status: {}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response body: {}&amp;quot;)&lt;br /&gt;
             s_headers = json.dumps(headers, indent=2, sort_keys=True)&lt;br /&gt;
             s_update = json.dumps(update, indent=2, sort_keys=True)&lt;br /&gt;
             s_body = json.dumps(res.json(), indent=2, sort_keys=True)&lt;br /&gt;
             print(msg.format(s_headers, s_update, res.status_code, s_body))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
 class Storage(object):&lt;br /&gt;
     def __init__(self, storagepath):&lt;br /&gt;
         self.storagepath = storagepath&lt;br /&gt;
         self._data = self.load()&lt;br /&gt;
 &lt;br /&gt;
     def load(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Reads the storage content from the disk to a dict structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         data = dict()&lt;br /&gt;
         filedata = &amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             with open(self.storagepath, 'r') as fh:&lt;br /&gt;
                 filedata = fh.read()&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             if os.path.isfile(self.storagepath):&lt;br /&gt;
                 # Only error out if file exists, but cannot be read&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage file exists but cannot be read&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         try:&lt;br /&gt;
             data = json.loads(filedata)&lt;br /&gt;
         except ValueError:&lt;br /&gt;
             if len(filedata) &amp;gt; 0:&lt;br /&gt;
                 # Storage file is corrupted&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage JSON is corrupted&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         return data&lt;br /&gt;
 &lt;br /&gt;
     def save(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Saves the storage content to disk&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         serialized = json.dumps(self._data)&lt;br /&gt;
         try:&lt;br /&gt;
             with os.fdopen(os.open(self.storagepath,&lt;br /&gt;
                                    os.O_WRONLY | os.O_CREAT, 0o600), 'w') as fh:&lt;br /&gt;
                 fh.truncate()&lt;br /&gt;
                 fh.write(serialized)&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             print(&amp;quot;ERROR: Could not write storage file.&amp;quot;)&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def put(self, key, value):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Puts the configuration value to storage and sanitize it&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         # If wildcard domain, remove the wildcard part as this will use the&lt;br /&gt;
         # same validation record name as the base domain&lt;br /&gt;
         if key.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
             key = key[2:]&lt;br /&gt;
         self._data[key] = value&lt;br /&gt;
 &lt;br /&gt;
     def fetch(self, key):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Gets configuration value from storage&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             return self._data[key]&lt;br /&gt;
         except KeyError:&lt;br /&gt;
             return None&lt;br /&gt;
 &lt;br /&gt;
 if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
     # Init&lt;br /&gt;
     client = AcmeDnsClient(ACMEDNS_URL)&lt;br /&gt;
     storage = Storage(STORAGE_PATH)&lt;br /&gt;
 &lt;br /&gt;
     # Check if an account already exists in storage&lt;br /&gt;
     account = storage.fetch(DOMAIN)&lt;br /&gt;
     if FORCE_REGISTER or not account:&lt;br /&gt;
         # Create and save the new account&lt;br /&gt;
         account = client.register_account(ALLOW_FROM)&lt;br /&gt;
         storage.put(DOMAIN, account)&lt;br /&gt;
         storage.save()&lt;br /&gt;
 &lt;br /&gt;
         # Display the notification for the user to update the main zone&lt;br /&gt;
         msg = &amp;quot;Please add the following CNAME record to your main DNS zone:\n{}&amp;quot;&lt;br /&gt;
         cname = &amp;quot;{} CNAME {}.&amp;quot;.format(VALIDATION_DOMAIN, account[&amp;quot;fulldomain&amp;quot;])&lt;br /&gt;
         print(msg.format(cname))&lt;br /&gt;
 &lt;br /&gt;
     # Update the TXT record in acme-dns instance&lt;br /&gt;
     client.update_txt_record(account, VALIDATION_TOKEN)&lt;br /&gt;
&lt;br /&gt;
 # chmod +x /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
Usaremos a seguinte instrução para criar nosso certificado:&lt;br /&gt;
 # certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d doh.brasilpeeringforum.org&lt;br /&gt;
 Saving debug log to /var/log/letsencrypt/letsencrypt.log&lt;br /&gt;
 Plugins selected: Authenticator manual, Installer None&lt;br /&gt;
 Cert is due for renewal, auto-renewing...&lt;br /&gt;
 Renewing an existing certificate for doh.brasilpeeringforum.org&lt;br /&gt;
 Performing the following challenges:&lt;br /&gt;
 dns-01 challenge for doh.brasilpeeringforum.org&lt;br /&gt;
 Running manual-auth-hook command: /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
 Output from manual-auth-hook command acme-dns-auth.py:&lt;br /&gt;
 Please add the following CNAME record to your main DNS zone:&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
 &lt;br /&gt;
 Waiting for verification...&lt;br /&gt;
 &lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Challenges loaded. Press continue to submit to CA. Pass &amp;quot;-v&amp;quot; for more info about&lt;br /&gt;
 challenges.&lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Press Enter to Continue&lt;br /&gt;
Nesse momento você cria o registro '''CNAME''' no seu DNS Autoritativo conforme ele solicitou: '''_acme-challenge.doh.brasilpeeringforum.org IN CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.''' e somente depois de criado e checado no DNS, você pressiona o '''Enter''' para continuar. Você pode checar dessa forma:&lt;br /&gt;
 # host -t cname _acme-challenge.doh.brasilpeeringforum.org&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org is an alias for b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
Para que nosso certificado seja automaticamente renovado colocaremos no '''/etc/crontab''' a seguinte linha abaixo:&lt;br /&gt;
 00 00   1 * *   root    /usr/bin/certbot -q renew&lt;br /&gt;
Acima temos a instrução para renovação automática do certificado. Repare que você vai precisar também copiar esse certificado para seus outros servidores, escolha um servidor para manter o certificado sempre atualizado e crie um script que faça a mesma cópia remotamente para os outros servidores. O '''scp''' e o '''rsync''' são seus aliados nisso.&lt;br /&gt;
&lt;br /&gt;
=== Configurando o Unbound ===&lt;br /&gt;
Em nosso '''/etc/unbound/unbound.conf.d/local.conf''', adicionaremos no bloco &amp;quot;'''server:'''&amp;quot; o seguinte:&lt;br /&gt;
 interface: 10.10.10.10@443 &lt;br /&gt;
 interface: 10.10.9.9@443&lt;br /&gt;
 interface: fd00::10:10:10:10@443&lt;br /&gt;
 interface: fd00::10:10:9:9@443&lt;br /&gt;
 tls-service-key: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/privkey.pem&amp;quot; &lt;br /&gt;
 tls-service-pem: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/fullchain.pem&amp;quot;&lt;br /&gt;
Para usar o recurso do '''DoH''' você precisará habilitar o recurso no seu navegador e informar a URL. Vou colocar o exemplo do '''Google Chrome''': Digite '''chrome://settings/security?search=dns''' no seu Chrome e ative '''Usar DNS seguro''', selecione '''Personalizado''' e adicione nossa URL:&lt;br /&gt;
[[Arquivo:Doh bpf2.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Finalizando ==&lt;br /&gt;
Aqui finalizamos nosso projeto para uma Rede de DNS(s) Recursivos Anycast com Hyperlocal. Esse projeto é escalável, seguro, resiliente e você entregará muito mais qualidade de Internet para o seu cliente. Pare de entregar o '''8.8.8.8''' para os seus clientes, você está contribuindo para uma Internet mais lenta, sem a qualidade que o seu cliente merece. Investi meu tempo, que é muito pouco, para deixar esse documento para a comunidade, para você melhorar o seu ISP, para dar um UP! nele, então vamos começar 2023 com o pé direito. O que acha?&lt;br /&gt;
&lt;br /&gt;
Como prova de conceito, uma imagem abaixo onde temos uma Rede em produção de DNS(s) Recursivos Anycast e apontando exatamente o momento em que houve alguma situação que fez com que as queries de DNS, convergissem de um node para outro, de forma transparente e automática para o cliente. Podemos notar também que ao ser resolvido o problema, o tráfego retornou para o seu node correto:&lt;br /&gt;
[[Arquivo:Convergencia.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== KINDNS (Stands for Knowledge-Sharing and Instantiating Norms for DNS and Naming Security) ==&lt;br /&gt;
Achou que havia terminado? Agora que você tem a capacidade de montar uma '''Rede de DNS Recursivo''' com todas essas features acima, com todas as ferramentas que foram comentadas, o que acha de certificar o que fez?&lt;br /&gt;
&lt;br /&gt;
Assim como o [https://www.manrs.org/ MANRS] veio para certificar nosso sistema de roteamento na Internet, agora temos o [https://kindns.org/ KINDNS] para certificar que nossos sistemas de DNS estão bem feitos e dentro dos padrões de segurança. Existem '''7 ações''' que podem ser certificadas para nossos DNS Recursivos e estão aqui em https://kindns.org/shared-private-resolvers/. Com essa nossa documentação, se bem aplicada, você pode se candidatar ao KINDNS e ter seu ASN listado aqui https://kindns.org/participants/&lt;br /&gt;
&lt;br /&gt;
Obter e manter o '''MANRS''' e '''KINDNS''' demonstra seu compromisso com as Boas Práticas, contribui para termos uma '''Internet''' mais segura e te abre portas para novos negócios que possam exigir essas conformidades.&lt;br /&gt;
&lt;br /&gt;
Autor: [[Usuário:Gondim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Infraestrutura]]&lt;br /&gt;
__FORCARTDC__&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3950</id>
		<title>DNS Recursivo Anycast Hyperlocal</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3950"/>
		<updated>2025-09-16T02:22:45Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
==Introdução==&lt;br /&gt;
Você sabe como funciona a Internet? Essa é uma pergunta que meu amigo '''Thiago Ayub''' sempre faz aos seus candidatos à vagas de emprego e não importa o quanto tenham de experiência em '''Engenharia de Redes''', todos sempre travam nesse momento. Todos estão sempre prontos e preparados para resolver os problemas mais cabeludos em '''BGP''', '''OSPF''', '''MPLS''', etc mas travam com essa simples pergunta. Para contextualizar e visualizarmos melhor vamos nos atentar à imagem abaixo e uma explicação simplificada de como funciona:&lt;br /&gt;
[[Arquivo:Dns hierarquia.png|esquerda|commoldura]]&lt;br /&gt;
Tudo começa com um usuário sentado confortavelmente e querendo acessar um conteúdo disponível na Internet. Ele digita em seu navegador preferido a URL: '''&amp;lt;nowiki&amp;gt;https://wiki.brasilpeeringforum.org&amp;lt;/nowiki&amp;gt;''',&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;1)&amp;lt;/big&amp;gt;''' &amp;lt;big&amp;gt;O&amp;lt;/big&amp;gt; &amp;lt;big&amp;gt;navegador irá requisitar do '''DNS Recursivo''' utilizado pelo usuário, o '''endereço IP''' que responde pelo nome '''wiki.'''&amp;lt;/big&amp;gt;'''brasilpeeringforum.org'''&amp;lt;big&amp;gt;. Isso porque todos os acessos se dão na Internet através do '''endereço''' '''IP''' e não através do '''nome'''. Imaginem se tivéssemos que decorar os endereços IPs de todos os sites e serviços que quiséssemos acessar na Internet?&amp;lt;/big&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;big&amp;gt;'''2)''' Nosso DNS Recursivo checa se a informação consta em seu cache.&amp;lt;/big&amp;gt; Se a informação existir ela é devolvida ao navegador do usuário e aí este consegue acessar o site.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Do contrário o DNS Recursivo pergunta ao '''Root Server''' quem é o '''TLD (Top Level Domain)''' responsável para atender a requisição. &lt;br /&gt;
&lt;br /&gt;
'''4)''' O '''Root Server''' informa ao DNS Recursivo o endereço do '''TLD responsável'''. No Brasil o '''TLD''' responsável pelo '''.br''' seria o '''Registro.br'''.&lt;br /&gt;
&lt;br /&gt;
'''5)''' O DNS Recursivo pergunta ao '''TLD''' sobre '''wiki.brasilpeeringforum.org''' e este responde com os endereços IP dos '''DNS Autoritativos''' responsáveis pelo domínio '''brasilpeeringforum.org.'''&lt;br /&gt;
&lt;br /&gt;
'''6)''' O DNS Recursivo pergunta aos '''DNS Autoritativos''' pelo '''wiki.brasilpeeringforum.org''' e este responde com o '''endereço IP'''.&lt;br /&gt;
&lt;br /&gt;
'''7)''' Por último o DNS Recursivo devolve a informação para o navegador do usuário.&lt;br /&gt;
&lt;br /&gt;
Como que se dá a comunicação entre os '''DNS(s) Recursivos, Root Servers, TLDs''' e '''Autoritativos'''? Como que o navegador do usuário, após receber o IP do site, consegue chegar no servidor que tem o conteúdo? Isso só é possível devido ao protocolo chamado '''BGP (Border Gateway Protocol)''', todos os caminhos que conhecemos como rotas de destino, são anunciadas por milhares de participantes na '''Internet''' conhecidos como '''AS (Autonomous System)''', esses participantes se interligam para disponibilizar conteúdos e acessos pelo mundo aos milhares de usuários. É uma imensa rede colaborativa formada por Empresas, Universidades, Governos e todos que queiram se interconectar. Percebam que sem o '''BGP''', que serve de caminho para chegarmos nos conteúdos e sem o '''DNS (Domain Name System)''' para traduzir o nome para o endereço IP, a '''Internet''' não funcionaria e por isso precisamos cuidar muito bem desses dois serviços.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Mas não acaba por aí. O '''DNS Recursivo''' tem um papel muito importante para o Provedor de Internet e que envolve segurança, qualidade de acesso à Internet e a disponibilidade do serviço entregue ao cliente. Quando bem configurado acelera as consultas dos acessos graças ao seu cache interno, mas para que isso seja percebido pelo assinante, é necessário que esteja o mais próximo possível do seu cliente.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Um erro que destrói a qualidade do nosso serviço ==&lt;br /&gt;
Um erro muito comum que muitas operadoras cometem é utilizar DNS Recursivo externo, como o '''8.8.8.8''', '''1.1.1.1''' e outros, para seus clientes. Quanto mais próximo dos seus clientes, mais qualidade de serviço estará entregando a eles. Conteúdos serão entregues mais rapidamente pois serão resolvidos e armazenados em caches locais e não consultados remotamente na Internet. Para falar mais sobre isso, te convido leitor desse documento, que assista essa palestra do '''Thiago Ayub''' no '''GTER 51/GTS 37''' (2022) '''8.888 MOTIVOS PARA NÃO USAR DNS RECURSIVO EXTERNO EM SEU AS''': https://www.youtube.com/watch?v=Rsvpu5uF2Io&lt;br /&gt;
&lt;br /&gt;
== Objetivo ==&lt;br /&gt;
O objetivo desta documentação não é te ensinar tudo sobre '''DNS''', '''BGP''', '''OSPF''' e nem tão pouco sobre GNU/Linux e sim te mostrar um exemplo de servidor DNS Recursivo implementado pensando em segurança, qualidade e resiliência. Usaremos em todas as nossas documentações o [https://www.debian.org/ Debian GNU/Linux], por ser uma distribuição que considero uma obra de arte criada por uma enorme comunidade séria, com vasta experiência de anos, qualidade no empacotamento dos programas, estável e com uma equipe de segurança excelente e ativa. Caso você leitor, utilize alguma outra distribuição GNU/Linux, todo conteúdo apresentado aqui pode ser aplicado em outras distros, desde que respeitando as particularidades de cada uma.&lt;br /&gt;
&lt;br /&gt;
Aqui construiremos um sistema do tipo '''Anycast''', ou seja, terás o serviço rodando em diversas localidades da sua Rede utilizando o mesmo endereçamento IP e que atenderá seu cliente mais próximo. Em caso de falhas, seus clientes automaticamente e de forma transparente continuarão consultando o DNS mais próximo deles. Para que ele funcione dessa forma você precisará ter uma '''Rede OSPF''' implementada no seu Provedor Internet ou algum outro protocolo como por exemplo o '''ISIS,''' mas esse documento não irá abordar o '''ISIS'''. Também utilizaremos o '''Hyperlocal''' como recurso adicional para gerar algumas proteções de segurança e velocidade na resposta relacionada aos servidores de DNS Raiz da Internet.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
Para exemplificar nosso servidor de DNS Recursivo, usaremos como base das explicações um diagrama demonstrando o uso do DNS Recursivo em uma Rede fictícia. Adotaremos IPs privados e reservados para demonstrar todo o ambiente do Provedor de Internet.&lt;br /&gt;
[[Arquivo:Recursivo99.png|esquerda|miniaturadaimagem|695x695px]]&lt;br /&gt;
Nesse diagrama podemos observar alguns detalhes técnicos como por exemplo: existem '''3 servidores de DNS Recursivo''' posicionados em locais diferentes, que poderiam estar em bairros diferentes e até em cidades diferentes. Em cada servidor teremos '''2 loopbacks''' com os IPs:&lt;br /&gt;
&lt;br /&gt;
'''10.10.10.10/32 - fc00::10:10:10:10/128'''&lt;br /&gt;
&lt;br /&gt;
'''10.10.9.9/32 - fc00::10:10:9:9/128'''&lt;br /&gt;
&lt;br /&gt;
Esses IPs serão entregues pelos concentradores '''PPPoE''' ou '''IPoE''' ('''BNG''') para seus clientes como '''DNS primário''' e '''secundário'''. Podemos usar IPs privados como DNS primário e secundário em um ambiente real? Sim podemos, desde que não sejam IPs que possam ter problemas com as redes privadas dos clientes. Ex.: rede do cliente usando '''192.168.0.0/24'''. Se entregarmos o DNS sendo '''192.168.0.10''' e '''192.168.0.20''' teremos problemas e o cliente ficará sem Internet, porque '''192.168.0.10''' e '''192.168.0.20''' fazem parte da rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
Agora entregando '''10.10.10.10,''' '''10.10.9.9, fc00::10:10:10:10 e fc00::10:10:9:9''' não teríamos problemas com a rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
'''Motivos para usarmos IPs privados:'''&lt;br /&gt;
* O principal motivo está relacionado com a segurança, uma vez que sendo um IP privado, não pode sofrer ataques DDoS direcionados diretamente para ele, vindos da Internet.&lt;br /&gt;
* Nem mesmo o cliente da sua rede conhece os '''IPs públicos''' utilizados para recursividade na Internet.&lt;br /&gt;
* Memorizar os IPs '''10.10.10.10''' e '''10.10.9.9''' é tão fácil quanto memorizar o '''8.8.8.8''' e o '''1.1.1.1'''. Mais fácil para o seu técnico guardar essa informação e utilizar onde for necessário.&lt;br /&gt;
Cada servidor DNS Recursivo possui um '''IPv4 público''', aqui representado por '''198.18.x.x/27''' e um '''IPv6 global''' representado por um IP dentro do prefixo '''2001:db8::/32'''. Cada servidor precisa ter os seus próprios IPs e são através destes IPs que as consultas de DNS serão realizadas na Internet.&lt;br /&gt;
&lt;br /&gt;
Nessa topologia usando '''Anycast''', o cliente será sempre atendido pelo '''DNS Recursivo''' mais próximo, desde que os pesos no '''OSPF''' estejam ajustados corretamente.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
== Dados do servidor ==&lt;br /&gt;
Podemos utilizar um sistema virtualizado ou não. Sistemas virtualizados são bem vindos pois são mais simples quando precisamos fazer backups, levantar outros sistemas sem complicações e se precisarmos restaurar rapidamente algum sistema que ficou indisponível por algum motivo. A configuração abaixo tem capacidade para atender algo em torno a '''50.000 assinantes ou mais'''. O DNS Recursivo é um serviço que pode ser utilizado até mesmo em um '''Raspberry Pi''' e atender operações pequenas, nesse caso com o intuito de economizar energia e espaço. Nosso foco aqui é montar uma rede de '''DNS Recursivo Anycast com HyperLocal'''. Como comentei acima o servidor deve ficar o mais próximo dos clientes para termos a '''menor latência possível''' e '''sempre menor que 5ms''' entre o cliente e o servidor.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!CPU&lt;br /&gt;
!Memória&lt;br /&gt;
!Disco&lt;br /&gt;
!Sistema&lt;br /&gt;
|-&lt;br /&gt;
|2.4Ghz 4 cores&lt;br /&gt;
|16G DDR4&lt;br /&gt;
|30G&lt;br /&gt;
|Debian 12 amd64 (Bookworm)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Softwares utilizados ==&lt;br /&gt;
* Debian 12 amd64 (Bookworm) instalação mínima.&lt;br /&gt;
&lt;br /&gt;
* [https://frrouting.org/ FRRouting].&lt;br /&gt;
* Unbound.&lt;br /&gt;
* Chrony (NTP/NTS).&lt;br /&gt;
* Shell script em bash.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades que teremos ==&lt;br /&gt;
* Sistema em Anycast.&lt;br /&gt;
* Hyperlocal.&lt;br /&gt;
* Controle de acesso por &amp;lt;abbr&amp;gt;ACL&amp;lt;/abbr&amp;gt;.&lt;br /&gt;
* RPZ (Response Policy Zone).&lt;br /&gt;
* Bloqueio de consultas do tipo ANY.&lt;br /&gt;
* QNAME minimization habilitado. (habilitado por default no Unbound)&lt;br /&gt;
* Recursividade em IPv4 e IPv6.&lt;br /&gt;
* DNSSEC habilitado.&lt;br /&gt;
* &amp;lt;abbr&amp;gt;DoH (DNS&amp;lt;/abbr&amp;gt; over HTTPS) habilitado.&lt;br /&gt;
&lt;br /&gt;
== Monitoramento ==&lt;br /&gt;
O monitoramento é algo bem específico e não é o foco deste documento mas é extremamente importante que você monitore seus servidores de DNS por alguma ferramenta como o Zabbix. Aqui mostrarei apenas como enviar as informações para o Zabbix. Algumas coisas que você deveria monitorar nos servidores de DNS Recursivo:&lt;br /&gt;
* Serviço do unbound parou.&lt;br /&gt;
* Perda de pacotes.&lt;br /&gt;
* Latência alta de pacotes.&lt;br /&gt;
* Lentidão na resolução de queries.&lt;br /&gt;
* CPU alta.&lt;br /&gt;
* Load alto.&lt;br /&gt;
* Memória com uso alto.&lt;br /&gt;
* Disco com pouco espaço.&lt;br /&gt;
* Queda brusca nas queries.&lt;br /&gt;
* A recursividade parou de funcionar.&lt;br /&gt;
* A recursividade voltou a funcionar.&lt;br /&gt;
Este abaixo é um exemplo de monitoramento de um sistema de DNS Recursivo que atende 50.000 assinantes:&lt;br /&gt;
[[Arquivo:Grafana dns.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Configurando a Rede ==&lt;br /&gt;
Nossa documentação será baseada no diagrama apresentado acima e por isso configuraremos apenas um dos três servidores, porque os outros serão configurados da mesma forma, só que com dados diferentes. Para tanto assumirei que já temos um sistema Debian instalado com o mínimo de pacotes e somente com sshd, para que possamos acessar remotamente mais tarde. '''Não instale um ambiente gráfico no servidor''', você não deve querer fazer isso por diversos motivos e os principais: primeiro porque não é um Desktop e segundo porque o ambiente gráfico devoraria toda a memória com recursos que não seriam úteis aqui.&lt;br /&gt;
&lt;br /&gt;
Em '''/etc/network/interfaces''' deixaremos assim:&lt;br /&gt;
 # This file describes the network interfaces available on your system&lt;br /&gt;
 # and how to activate them. For more information, see interfaces(5).&lt;br /&gt;
  &lt;br /&gt;
 source /etc/network/interfaces.d/*&lt;br /&gt;
  &lt;br /&gt;
 # The loopback network interface&lt;br /&gt;
 auto lo&lt;br /&gt;
 iface lo inet loopback&lt;br /&gt;
  &lt;br /&gt;
 auto lo:0&lt;br /&gt;
 iface lo:0 inet static&lt;br /&gt;
       address 10.10.10.10/32&lt;br /&gt;
  &lt;br /&gt;
 auto lo:1&lt;br /&gt;
 iface lo:1 inet static&lt;br /&gt;
       address 10.10.9.9/32&lt;br /&gt;
 &lt;br /&gt;
 auto lo:2&lt;br /&gt;
 iface lo:2 inet6 static&lt;br /&gt;
       address fd00::10:10:10:10/128&lt;br /&gt;
 &lt;br /&gt;
 auto lo:3&lt;br /&gt;
 iface lo:3 inet6 static&lt;br /&gt;
       address fd00::10:10:9:9/128&lt;br /&gt;
  &lt;br /&gt;
 # The primary network interface&lt;br /&gt;
 auto ens18&lt;br /&gt;
 iface ens18 inet static&lt;br /&gt;
         address 198.18.1.10/27&lt;br /&gt;
         gateway 198.18.1.1&lt;br /&gt;
  &lt;br /&gt;
 iface ens18 inet6 static&lt;br /&gt;
         address 2001:db8::faca:198:18:1:10/64&lt;br /&gt;
         gateway 2001:db8::faca:198:18:1:1&lt;br /&gt;
  &lt;br /&gt;
 # The secondary network interface&lt;br /&gt;
 auto ens18:0&lt;br /&gt;
 iface ens18:0 inet static&lt;br /&gt;
         address 172.16.0.6/30&lt;br /&gt;
Nesse cenário temos as duas '''loopbacks''' com os IPs '''10.10.10.10''', '''10.10.9.9, fd00::10:10:10:10''' e '''fd00::10:10:9:9''' que serão anunciados via OSPF para a rede e serem entregues aos clientes via BNG. Os IPs '''198.18.1.10''' e '''2001:db8::faca:198:18:1:10''' serão usados para fazerem a recursividade na Internet tanto em IPv4 quanto em IPv6. Esses IPs não devem ser divulgados para clientes; os IPs públicos são dedicados apenas para essa finalidade.&lt;br /&gt;
&lt;br /&gt;
== Configuração dos repositórios Debian ==&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list''' conforme abaixo:&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://security.debian.org/debian-security&amp;lt;/nowiki&amp;gt; bookworm-security main contrib non-free non-free-firmware&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian&amp;lt;/nowiki&amp;gt; bookworm main contrib non-free non-free-firmware&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian&amp;lt;/nowiki&amp;gt; bookworm-updates main contrib non-free non-free-firmware&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian&amp;lt;/nowiki&amp;gt; bookworm-backports main contrib non-free non-free-firmware&lt;br /&gt;
Após a configuração vamos instalar alguns pacotes necessários e outros úteis:&lt;br /&gt;
 # apt update &amp;amp;&amp;amp; apt full-upgrade&lt;br /&gt;
 # apt install net-tools nftables htop iotop sipcalc tcpdump curl gnupg rsync wget host dnsutils mtr-tiny bmon sudo tmux whois ethtool dnstop&lt;br /&gt;
&lt;br /&gt;
== Fazendo algum tuning no sistema ==&lt;br /&gt;
Em '''/etc/sysctl.conf''' adicionamos no final do arquivo essas instruções:&lt;br /&gt;
 net.core.rmem_max = 2147483647&lt;br /&gt;
 net.core.wmem_max = 2147483647&lt;br /&gt;
 net.ipv4.tcp_rmem = 4096 87380 2147483647&lt;br /&gt;
 net.ipv4.tcp_wmem = 4096 65536 2147483647&lt;br /&gt;
 net.netfilter.nf_conntrack_buckets = 512000&lt;br /&gt;
 net.netfilter.nf_conntrack_max = 4096000&lt;br /&gt;
 vm.swappiness=10&lt;br /&gt;
Estamos fazendo algumas melhorias de memória, algumas relacionadas a '''conntrack''' porque se for usar um filtro de pacotes stateful, como o '''Netfilter/IPTables''' ou '''Netfilter/NFTables''', o valor default da tabela é pequeno e dependendo da situação, se estourar essa tabela, as consultas de DNS terão problemas também. O DNS Recursivo não deve ficar aberto para qualquer um na Internet, ele deve ser liberado apenas para seus clientes. Podemos fazer através das ACLs do Unbound e pelo filtro de pacotes. O último parâmetro diz respeito ao uso de swap, por padrão o Debian permite o uso de swap após 40% do uso da memória, nesse caso estamos dizendo para o sistema usar o swap com 90% de uso da memória.&lt;br /&gt;
&lt;br /&gt;
Precisamos adicionar o módulo '''nf_conntrack''' em '''/etc/modules''' para que seja carregado em tempo de boot, senão os parâmetros de '''conntrack''' que colocamos em '''/etc/sysctl.conf''' não serão carregados.&lt;br /&gt;
 # echo nf_conntrack &amp;gt;&amp;gt; /etc/modules&lt;br /&gt;
 # modprobe nf_conntrack&lt;br /&gt;
 # sysctl -p&lt;br /&gt;
&lt;br /&gt;
== Instalando o FRRouting ==&lt;br /&gt;
O FRRouting é o programa que usaremos para fazer os anúncios das nossas loopbacks via OSPF. Nesse documento usaremos a versão 10.x e para isso precisaremos configurar o repositório oficial do FRRouting e instalar os pacotes:&lt;br /&gt;
 # curl -s &amp;lt;nowiki&amp;gt;https://deb.frrouting.org/frr/keys.gpg&amp;lt;/nowiki&amp;gt; | tee /usr/share/keyrings/frrouting.gpg &amp;gt; /dev/null&lt;br /&gt;
 # echo &amp;quot;deb [signed-by=/usr/share/keyrings/frrouting.gpg] &amp;lt;nowiki&amp;gt;https://deb.frrouting.org/frr&amp;lt;/nowiki&amp;gt; bookworm frr-10&amp;quot; &amp;gt; /etc/apt/sources.list.d/frr.list&lt;br /&gt;
 # apt update&lt;br /&gt;
 # apt install frr frr-doc frr-pythontools&lt;br /&gt;
Aconselho depois de instalar os pacotes, marcá-los para não atualizar juntamente com os demais pacotes, isso é para evitar de ocorrer alguma atualização no FRRouting, que torne o serviço instável por algum motivo. Não que isso vá ocorrer, mas é melhor fazer essa atualização quando realmente for necessário.&lt;br /&gt;
 # apt-mark hold frr frr-doc frr-pythontools&lt;br /&gt;
Após esse comando acima, o sistema manterá a instalação original do pacote intacta. Para desbloquear basta executar o comando abaixo:&lt;br /&gt;
 # apt-mark unhold frr frr-doc frr-pythontools&lt;br /&gt;
&lt;br /&gt;
== Removendo o APPARMOR ==&lt;br /&gt;
O '''APPARMOR''' às vezes causa mais problemas que solução e se não for fazer uma completa configuração nele, é melhor desabilitá-lo. Para fazer isso efetivamente, o procedimento é esse abaixo:&lt;br /&gt;
 # mkdir -p /etc/default/grub.d&lt;br /&gt;
 # echo 'GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;$GRUB_CMDLINE_LINUX_DEFAULT apparmor=0&amp;quot;' | tee /etc/default/grub.d/apparmor.cfg&lt;br /&gt;
 # update-grub&lt;br /&gt;
 # reboot&lt;br /&gt;
&lt;br /&gt;
== Instalando o Unbound ==&lt;br /&gt;
Nesse momento ainda não iremos configurar o Unbound, apenas instalar o pacote e acertar o ambiente. Vamos instalar o unbound do backports porque este já possui suporte ao DoH que veremos mais à frente.&lt;br /&gt;
 # apt install unbound dns-root-data&lt;br /&gt;
 # mkdir -p /var/log/unbound&lt;br /&gt;
 # touch /var/log/unbound/unbound.log&lt;br /&gt;
 # chown -R unbound:unbound /var/log/unbound/&lt;br /&gt;
 # systemctl restart unbound&lt;br /&gt;
Configurando o logrotate:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/logrotate.d/unbound&lt;br /&gt;
 /var/log/unbound/unbound.log {&lt;br /&gt;
     rotate 5&lt;br /&gt;
     weekly&lt;br /&gt;
     postrotate&lt;br /&gt;
         unbound-control log_reopen&lt;br /&gt;
     endscript&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
Reiniciando o serviço:&lt;br /&gt;
 # systemctl restart logrotate.service&lt;br /&gt;
&lt;br /&gt;
== Desabilitando THP (Transparente Huge Pages) em arquitetura AMD64 ==&lt;br /&gt;
No Debian o '''THP''' vem habilitado como '''always''' e o '''unbound''' por trabalhar bastante com alterações do cache em memória, isso pode acabar causando um consumo crescente de uso de RAM sem necessidade. É uma boa prática desabilitá-lo com os passos abaixo:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/systemd/system/disable-thp.service&lt;br /&gt;
 [Unit]&lt;br /&gt;
 Description=Desativa Transparent Huge Pages (THP)&lt;br /&gt;
 After=network.target&lt;br /&gt;
 &lt;br /&gt;
 [Service]&lt;br /&gt;
 Type=oneshot&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled&amp;quot;&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/defrag&amp;quot;&lt;br /&gt;
 RemainAfterExit=yes&lt;br /&gt;
 &lt;br /&gt;
 [Install]&lt;br /&gt;
 WantedBy=multi-user.target&lt;br /&gt;
 EOF&lt;br /&gt;
Acima configuramos o serviço '''disable-thp.service''' para desabilitar o '''THP''' e abaixo habilitamos no '''systemd''' e iniciamos:&lt;br /&gt;
 # systemctl daemon-reload&lt;br /&gt;
 # systemctl enable --now disable-thp&lt;br /&gt;
&lt;br /&gt;
== Preparando o monitoramento do seu DNS Recursivo ==&lt;br /&gt;
O monitoramento do seu DNS Recursivo é muito importante e para isso vamos usar um '''template para Zabbix''', que modifiquei juntamente com o seu shell script e que enviará os dados para o seu Zabbix server via '''zabbix-sender'''. O projeto original está aqui '''https://github.com/jeftedelima/Unbound-DNS&amp;lt;nowiki/&amp;gt;.''' O xml alterado está aqui '''https://github.com/gondimcodes/template_zabbix_dns_unbound'''. Embora seja antigo é perfeitamente importável no Zabbix 6.0, por exemplo.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;nowiki/&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Teremos um shell script que você precisará colocar no seu '''/etc/crontab'''. No exemplo abaixo assumi que o shell script está em '''/root/scripts'''. De 5 em 5 minutos os dados serão enviados para o seu Zabbix server.&lt;br /&gt;
 */5 * * * *     root    /root/scripts/unboundSend.sh '''IP_zabbix_server''' '''nome_do_host''' 1&amp;gt; /dev/null&lt;br /&gt;
Na linha acima, troque o '''IP_zabbix_server''' pelo '''IP do seu servidor Zabbix''' e o '''nome_do_host''' pelo '''hostname''' '''do seu DNS Recursivo'''. Você precisará instalar o pacote '''zabbix-sender''' no seu DNS Recursivo pois ele será usado para enviar os dados para o Zabbix server.&lt;br /&gt;
&lt;br /&gt;
Abaixo o '''unboundSend.sh''' também alterado com inclusão de mais dados:&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 #       @Jefte de Lima Ferreira&lt;br /&gt;
 #       jeftedelima at gmail dot com&lt;br /&gt;
 #       CRON Example&lt;br /&gt;
 #       Contributor: Marcelo Gondim - gondim at gmail dot com&lt;br /&gt;
 #       */5   **** root sh /home/dir/unboundSend.sh 192.168.10.1 Unbound 1&amp;gt; /dev/null&lt;br /&gt;
 &lt;br /&gt;
 if [ -z ${1} ] || [ -z ${2} ] ; then&lt;br /&gt;
         echo &amp;quot;You need to specify the IP address of zabbix server and hostname of your DNS Unbound on zabbix&amp;quot;&lt;br /&gt;
         echo &amp;quot;Usage example: ./unboundSend.sh 192.168.10.1 UnboundServer&amp;quot;&lt;br /&gt;
         exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
 # ZABBIX_SERVER IP&lt;br /&gt;
 IP_ZABBIX=$1&lt;br /&gt;
 # NAME Unbound on Zabbix&lt;br /&gt;
 NAME_HOST=$2&lt;br /&gt;
 DIR_TEMP=/var/tmp/&lt;br /&gt;
 FILE=&amp;quot;${DIR_TEMP}dump_unbound_control_stats.txt&amp;quot;&lt;br /&gt;
 unbound-control stats &amp;gt; ${FILE}&lt;br /&gt;
 &lt;br /&gt;
 TOTAL_NUM_QUERIES=$(cat ${FILE} | grep -w 'total.num.queries' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEHITS=$(cat ${FILE} | grep -w 'total.num.cachehits' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEMISS=$(cat ${FILE} | grep -w 'total.num.cachemiss' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_PREFETCH=$(cat ${FILE} | grep -w 'total.num.prefetch' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_RECURSIVEREPLIES=$(cat ${FILE} | grep -w 'total.num.recursivereplies' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 TOTAL_REQ_MAX=$(cat ${FILE} | grep -w 'total.requestlist.max' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_AVG=$(cat ${FILE} | grep -w 'total.requestlist.avg' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_OVERWRITTEN=$(cat ${FILE} | grep -w 'total.requestlist.overwritten' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_EXCEEDED=$(cat ${FILE} | grep -w 'total.requestlist.exceeded' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_ALL=$(cat ${FILE} | grep -w 'total.requestlist.current.all' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_USER=$(cat ${FILE} | grep -w 'total.requestlist.current.user' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 TOTAL_TCPUSAGE=$(cat ${FILE} | grep -w 'total.tcpusage' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 NUM_QUERY_TYPE_A=$(cat ${FILE} | grep -w 'num.query.type.A' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NS=$(cat ${FILE} | grep -w 'num.query.type.NS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_MX=$(cat ${FILE} | grep -w 'num.query.type.MX' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TXT=$(cat ${FILE} | grep -w 'num.query.type.TXT' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_PTR=$(cat ${FILE} | grep -w 'num.query.type.PTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_AAAA=$(cat ${FILE} | grep -w 'num.query.type.AAAA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SRV=$(cat ${FILE} | grep -w 'num.query.type.SRV' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SOA=$(cat ${FILE} | grep -w 'num.query.type.SOA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HTTPS=$(cat ${FILE} | grep -w 'num.query.type.HTTPS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TYPE0=$(cat ${FILE} | grep -w 'num.query.type.TYPE0' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_CNAME=$(cat ${FILE} | grep -w 'num.query.type.CNAME' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_WKS=$(cat ${FILE} | grep -w 'num.query.type.WKS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HINFO=$(cat ${FILE} | grep -w 'num.query.type.HINFO' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_X25=$(cat ${FILE} | grep -w 'num.query.type.X25' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NAPTR=$(cat ${FILE} | grep -w 'num.query.type.NAPTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DS=$(cat ${FILE} | grep -w 'num.query.type.DS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DNSKEY=$(cat ${FILE} | grep -w 'num.query.type.DNSKEY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TLSA=$(cat ${FILE} | grep -w 'num.query.type.TLSA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SVCB=$(cat ${FILE} | grep -w 'num.query.type.SVCB' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SPF=$(cat ${FILE} | grep -w 'num.query.type.SPF' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_ANY=$(cat ${FILE} | grep -w 'num.query.type.ANY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_OTHER=$(cat ${FILE} | grep -w 'num.query.type.other' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 NUM_ANSWER_RCODE_NOERROR=$(cat ${FILE} | grep -w 'num.answer.rcode.NOERROR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_NXDOMAIN=$(cat ${FILE} | grep -w 'num.answer.rcode.NXDOMAIN' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_SERVFAIL=$(cat ${FILE} | grep -w 'num.answer.rcode.SERVFAIL' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_REFUSED=$(cat ${FILE} | grep -w 'num.answer.rcode.REFUSED' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_nodata=$(cat ${FILE} | grep -w 'num.answer.rcode.nodata' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_secure=$(cat ${FILE} | grep -w 'num.answer.secure' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 #       Sending info to zabbix_server, if variables is not empty!&lt;br /&gt;
 [ -z ${TOTAL_NUM_QUERIES} ] ||  zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.queries -o $((TOTAL_NUM_QUERIES/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_CACHEHITS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachehits -o $((TOTAL_NUM_CACHEHITS/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_CACHEMISS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachemiss -o $((TOTAL_NUM_CACHEMISS/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_PREFETCH} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.prefetch -o $((TOTAL_NUM_PREFETCH/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_RECURSIVEREPLIES} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.recursivereplies -o $((TOTAL_NUM_RECURSIVEREPLIES/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${TOTAL_REQ_MAX} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.max -o $((TOTAL_REQ_MAX/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_AVG} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.avg -o $((TOTAL_REQ_AVG/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_OVERWRITTEN} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.overwritten -o $((TOTAL_REQ_OVERWRITTEN/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_EXCEEDED} ] ||  zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.exceeded -o $((TOTAL_REQ_EXCEEDED/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_CURRENT_ALL} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.all -o $((TOTAL_REQ_CURRENT_ALL/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_CURRENT_USER} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.user -o $((TOTAL_REQ_CURRENT_USER/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${TOTAL_TCPUSAGE} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.tcpusage -o $((TOTAL_TCPUSAGE/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_A} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.a -o $((NUM_QUERY_TYPE_A/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_NS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ns -o $((NUM_QUERY_TYPE_NS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_MX} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.mx -o $((NUM_QUERY_TYPE_MX/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_TXT} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.txt -o $((NUM_QUERY_TYPE_TXT/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_PTR} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ptr -o $((NUM_QUERY_TYPE_PTR/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_AAAA} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.aaaa -o $((NUM_QUERY_TYPE_AAAA/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SRV} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.srv -o $((NUM_QUERY_TYPE_SRV/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SOA} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.soa -o $((NUM_QUERY_TYPE_SOA/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_HTTPS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.https -o $((NUM_QUERY_TYPE_HTTPS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_TYPE0} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.type0 -o $((NUM_QUERY_TYPE_TYPE0/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_CNAME} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.cname -o $((NUM_QUERY_TYPE_CNAME/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_WKS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.wks -o $((NUM_QUERY_TYPE_WKS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_HINFO} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.hinfo -o $((NUM_QUERY_TYPE_HINFO/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_X25} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.X25 -o $((NUM_QUERY_TYPE_X25/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_NAPTR} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.naptr -o $((NUM_QUERY_TYPE_NAPTR/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_DS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ds -o $((NUM_QUERY_TYPE_DS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_DNSKEY} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.dnskey -o $((NUM_QUERY_TYPE_DNSKEY/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_TLSA} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.tlsa -o $((NUM_QUERY_TYPE_TLSA/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SVCB} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.svcb -o $((NUM_QUERY_TYPE_SVCB/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SPF} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.spf -o $((NUM_QUERY_TYPE_SPF/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_ANY} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.any -o $((NUM_QUERY_TYPE_ANY/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_OTHER} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.other -o $((NUM_QUERY_TYPE_OTHER/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_NOERROR} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NOERROR -o $((NUM_ANSWER_RCODE_NOERROR/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_NXDOMAIN} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NXDOMAIN -o $((NUM_ANSWER_RCODE_NXDOMAIN/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_SERVFAIL} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.SERVFAIL -o $((NUM_ANSWER_RCODE_SERVFAIL/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_REFUSED} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.REFUSED -o $((NUM_ANSWER_RCODE_REFUSED/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_nodata} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.nodata -o $((NUM_ANSWER_RCODE_nodata/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_secure} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.secure -o $((NUM_ANSWER_secure/300))&lt;br /&gt;
No Zabbix será registrado dados como esses abaixo e posteriormente pode ser montado um Grafana com eles:&lt;br /&gt;
[[Arquivo:Zabbix dns01.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns02.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns03.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns04.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Mantendo a hora certa ==&lt;br /&gt;
Vamos instalar agora o Chrony para manter a data e hora certas no sistema:&lt;br /&gt;
 # apt install chrony&lt;br /&gt;
Após a instalação do Chrony edite o arquivo /etc/chrony/chrony.conf, comente e a linha abaixo e adicione seus servidores NTP. Caso não tenha servidores NTP, estou colocando os do NIC.br aqui.&lt;br /&gt;
 #pool 2.debian.pool.ntp.org iburst&lt;br /&gt;
 server a.st1.ntp.br iburst nts&lt;br /&gt;
 server b.st1.ntp.br iburst nts&lt;br /&gt;
 server c.st1.ntp.br iburst nts&lt;br /&gt;
 server d.st1.ntp.br iburst nts&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart chronyd.service&lt;br /&gt;
Cheque com o '''chronyc''' se os servidores estão OK:&lt;br /&gt;
 # chronyc sourcestats&lt;br /&gt;
 Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev&lt;br /&gt;
 ==============================================================================&lt;br /&gt;
 a.st1.ntp.br               10   5  155m     -0.027      0.030    -71us    51us&lt;br /&gt;
 b.st1.ntp.br               11   7  344m     +0.068      0.079    +23ms   382us&lt;br /&gt;
 c.st1.ntp.br                6   3  344m     +0.026      0.037   -124us    92us&lt;br /&gt;
 200.20.186.76               9   3  138m     -0.022      0.031   +172us    42us&lt;br /&gt;
&lt;br /&gt;
 # chronyc sources&lt;br /&gt;
 MS Name/IP address         Stratum Poll Reach LastRx Last sample&lt;br /&gt;
 ===============================================================================&lt;br /&gt;
 ^* a.st1.ntp.br                  1  10   377   588   +487us[ +397us] +/-   12ms&lt;br /&gt;
 ^- b.st1.ntp.br                  2  10   377   830    +23ms[  +23ms] +/-   49ms&lt;br /&gt;
 ^+ c.st1.ntp.br                  2  10    21  1038   -147us[ -242us] +/-   17ms&lt;br /&gt;
 ^+ 200.20.186.76                 1  10   377  1032   +381us[ +285us] +/-   15ms&lt;br /&gt;
&lt;br /&gt;
== Configurando o FRRouting ==&lt;br /&gt;
Nesse ponto iremos configurar o '''FRRouting''' para enviar os IPs das '''loopbacks''' e o '''/30''' para o nosso PE do diagrama. Em '''/etc/frr/daemons''' habilite o parâmetro conforme abaixo:&lt;br /&gt;
 ospfd=yes&lt;br /&gt;
Edite o arquivo '''/etc/frr/frr.conf''' e deixe com o conteúdo abaixo, para ficar conforme nosso diagrama do projeto. Apenas troque '''&amp;lt;SENHA&amp;gt;''' por uma senha para fechar o OSPF com mais segurança. Essa senha deve ser usada dos dois lados.&lt;br /&gt;
 frr version 10.2.1&lt;br /&gt;
 frr defaults traditional&lt;br /&gt;
 hostname dns-recursivo-01&lt;br /&gt;
 log syslog informational&lt;br /&gt;
 no ip forwarding&lt;br /&gt;
 no ipv6 forwarding&lt;br /&gt;
 service integrated-vtysh-config&lt;br /&gt;
 !&lt;br /&gt;
 interface ens18&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf message-digest-key 5 md5 &amp;lt;SENHA&amp;gt;&lt;br /&gt;
  ip ospf network point-to-point&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 network point-to-point&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 interface lo&lt;br /&gt;
  description LOOPBACKS&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf passive&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 passive&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf&lt;br /&gt;
  ospf router-id 172.16.0.6&lt;br /&gt;
  area 0.0.0.0 authentication message-digest&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf6&lt;br /&gt;
  ospf6 router-id 172.16.0.6&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart frr.service&lt;br /&gt;
Cheque se está tudo OK com o OSPF e verifique no PE se está recebendo os prefixos anunciados.&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL&lt;br /&gt;
 172.16.0.5     1 Full/-          10m49s            35.310s 172.16.0.5   ens18:172.16.0.6                  0     0     0&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri    DeadTime    State/IfState         Duration I/F[State]&lt;br /&gt;
 172.16.0.5       1    00:00:30     Full/PointToPoint 25d22:53:47 ens18[PointToPoint]&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor detail'&lt;br /&gt;
 &lt;br /&gt;
  Neighbor 172.16.0.5, interface address 172.16.0.5&lt;br /&gt;
     In the area 0.0.0.0 via interface ens18&lt;br /&gt;
     Neighbor priority is 1, State is Full/-, 5 state changes&lt;br /&gt;
     Most recent state change statistics:&lt;br /&gt;
       Progressive change 21w3d15h ago&lt;br /&gt;
     DR is 0.0.0.0, BDR is 0.0.0.0&lt;br /&gt;
     Options 18 *|-|-|EA|-|-|E|-&lt;br /&gt;
     Dead timer due in 34.685s&lt;br /&gt;
     Database Summary List 0&lt;br /&gt;
     Link State Request List 0&lt;br /&gt;
     Link State Retransmission List 0&lt;br /&gt;
     Thread Inactivity Timer on&lt;br /&gt;
     Thread Database Description Retransmision off&lt;br /&gt;
     Thread Link State Request Retransmission on&lt;br /&gt;
     Thread Link State Update Retransmission on&lt;br /&gt;
 &lt;br /&gt;
     Graceful restart Helper info:&lt;br /&gt;
       Graceful Restart HELPER Status : None&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor detail'&lt;br /&gt;
  Neighbor 172.16.0.5%ens18&lt;br /&gt;
     Area 0.0.0.0 via interface ens18 (ifindex 4)&lt;br /&gt;
     His IfIndex: 60 Link-local address: fe80::469b:c1ff:fed6:43ee&lt;br /&gt;
     State Full for a duration of 25d22:57:14&lt;br /&gt;
     His choice of DR/BDR 0.0.0.0/0.0.0.0, Priority 1&lt;br /&gt;
     DbDesc status: Master SeqNum: 0xb94b0000&lt;br /&gt;
     Summary-List: 0 LSAs&lt;br /&gt;
     Request-List: 0 LSAs&lt;br /&gt;
     Retrans-List: 0 LSAs&lt;br /&gt;
     0 Pending LSAs for DbDesc in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSReq in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSAck in Time 00:00:00 [thread off]&lt;br /&gt;
     Authentication header not present&lt;br /&gt;
&lt;br /&gt;
== Configurando o Unbound ==&lt;br /&gt;
Abaixo a configuração que usaremos nos servidores atentando para o detalhe do '''num-threads''', esse deve ter o valor igual ao número de CPUs do servidor.&lt;br /&gt;
&lt;br /&gt;
Também os IPs utilizados em '''outgoing-interface''' que serão diferentes em cada servidor, esses serão os IPs usados para '''recursividade'''. Consulte o manual do Unbound para obter mais informações sobre cada parâmetro listado na configuração.&lt;br /&gt;
&lt;br /&gt;
O tuning no Unbound pode ser alterado conforme abaixo:&lt;br /&gt;
 num-threads = nº CPUs&lt;br /&gt;
 so-reuseport = yes&lt;br /&gt;
 *-slabs = potência de 2 próximo ao num-threads&lt;br /&gt;
 msg-cache-size = 1g (quantidade de memória pra usar de cache)&lt;br /&gt;
 rrset-cache-size = 2 * msg-cache-size&lt;br /&gt;
 outgoing-range = 8192&lt;br /&gt;
 num-queries-per-thread = 4096&lt;br /&gt;
 so-rcvbuf e so-sndbuf = 4m ou 8m para servidores com muita requisição&lt;br /&gt;
Agora vamos criar nosso arquivo de configuração base em '''/etc/unbound/unbound.conf.d/local.conf''':&lt;br /&gt;
 server:&lt;br /&gt;
         verbosity: 1&lt;br /&gt;
         statistics-interval: 0&lt;br /&gt;
         statistics-cumulative: no&lt;br /&gt;
         extended-statistics: yes&lt;br /&gt;
         num-threads: 4&lt;br /&gt;
         serve-expired: yes&lt;br /&gt;
         interface: 127.0.0.1&lt;br /&gt;
         interface: 10.10.10.10&lt;br /&gt;
         interface: 10.10.9.9&lt;br /&gt;
         interface: 172.16.0.6&lt;br /&gt;
         interface: fd00::10:10:10:10&lt;br /&gt;
         interface: fd00::10:10:9:9&lt;br /&gt;
         interface: ::1&lt;br /&gt;
         interface-automatic: no&lt;br /&gt;
         outgoing-interface: 198.18.1.10&lt;br /&gt;
         outgoing-interface: 2001:db8::faca:198:18:1:10&lt;br /&gt;
         outgoing-range: 8192&lt;br /&gt;
         outgoing-num-tcp: 1024&lt;br /&gt;
         incoming-num-tcp: 2048&lt;br /&gt;
         so-rcvbuf: 4m&lt;br /&gt;
         so-sndbuf: 4m&lt;br /&gt;
         so-reuseport: yes&lt;br /&gt;
         edns-buffer-size: 1232&lt;br /&gt;
         msg-cache-size: 1g&lt;br /&gt;
         msg-cache-slabs: 4&lt;br /&gt;
         num-queries-per-thread: 4096&lt;br /&gt;
         rrset-cache-size: 2g&lt;br /&gt;
         rrset-cache-slabs: 4&lt;br /&gt;
         infra-cache-slabs: 4&lt;br /&gt;
         do-ip4: yes&lt;br /&gt;
         do-ip6: yes&lt;br /&gt;
         do-udp: yes&lt;br /&gt;
         do-tcp: yes&lt;br /&gt;
         chroot: &amp;quot;&amp;quot;&lt;br /&gt;
         username: &amp;quot;unbound&amp;quot;&lt;br /&gt;
         directory: &amp;quot;/etc/unbound&amp;quot;&lt;br /&gt;
         logfile: &amp;quot;/var/log/unbound/unbound.log&amp;quot;&lt;br /&gt;
         use-syslog: no&lt;br /&gt;
         log-time-ascii: yes&lt;br /&gt;
         log-queries: no&lt;br /&gt;
         pidfile: &amp;quot;/var/run/unbound.pid&amp;quot;&lt;br /&gt;
         root-hints: &amp;quot;/usr/share/dns/root.hints&amp;quot;&lt;br /&gt;
         hide-identity: yes&lt;br /&gt;
         hide-version: yes&lt;br /&gt;
         unwanted-reply-threshold: 10000000&lt;br /&gt;
         prefetch: yes&lt;br /&gt;
         prefetch-key: yes&lt;br /&gt;
         rrset-roundrobin: yes&lt;br /&gt;
         minimal-responses: yes&lt;br /&gt;
         module-config: &amp;quot;respip validator iterator&amp;quot;&lt;br /&gt;
         val-clean-additional: yes&lt;br /&gt;
         val-log-level: 1&lt;br /&gt;
         key-cache-slabs: 4&lt;br /&gt;
         deny-any: yes&lt;br /&gt;
         cache-min-ttl: 60&lt;br /&gt;
         key-cache-size: 128m&lt;br /&gt;
         neg-cache-size: 64m&lt;br /&gt;
         cache-max-ttl: 86400&lt;br /&gt;
         infra-cache-numhosts: 100000&lt;br /&gt;
         access-control: 198.18.0.0/22 allow&lt;br /&gt;
         access-control: 2001:db8::/32 allow&lt;br /&gt;
  &lt;br /&gt;
 rpz:&lt;br /&gt;
   name: rpz.block.host.local.zone&lt;br /&gt;
   zonefile: /etc/unbound/rpz.block.hosts.zone&lt;br /&gt;
   rpz-action-override: nxdomain&lt;br /&gt;
  &lt;br /&gt;
 python:&lt;br /&gt;
  &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;.&amp;quot;&lt;br /&gt;
     master: &amp;quot;b.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;c.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;d.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;f.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;g.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;k.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/root.zone&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;arpa.&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/arpa.zone&amp;quot;&lt;br /&gt;
No parâmetro '''interface''' colocamos os IPs que serão usados para consulta dos clientes como o '''10.10.10.10''', '''10.10.9.9, fc00::10:10:10:10 e fc00::10:10:9:9'''. Ali repare que coloquei também o IP privado '''172.16.0.6''', isso porque cada servidor terá o seu IP privado e este deve ser usado pelo seu sistema de monitoramento para checar cada servidor. No '''outgoing-interface''' teremos os IPs, tanto '''IPv4''' quanto '''IPv6''', para que seja feita a recursividade na Internet utilizando eles. Não tem '''IPv6''' ainda na sua rede? Dê uma olhada nesse artigo. Outro parâmetro importante é o '''access-control''' e é através dele que liberamos os prefixos IP para consultarem no nosso DNS Recursivo. No exemplo estou liberando todo o prefixo '''198.18.0.0/22''' e o prefixo '''2001:db8::/32'''. Além da ACL no Unbound, recomendo que crie um filtro de pacotes com iptables ou nftables protegendo seu sistema e liberando as portas '''53/UDP''', '''53/TCP,'''  '''443/TCP e 853/TCP''' apenas para seus clientes. Falarei sobre a '''443/TCP e 853/TCP''' mais para frente nessa mesma documentação.&lt;br /&gt;
&lt;br /&gt;
Agora criaremos o arquivo '''RPZ''' ('''Response Policy Zones'''). Esse arquivo contém os sites que serão bloqueados via '''&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; Recursivo'''. São aqueles sites que às vezes você recebe um Ofício da Justiça solicitando o bloqueio deles. Não entrarei no mérito da efetividade desses bloqueios, porque muitos de vocês sabem que tecnicamente, existem formas de se fazer um bypass através desses bloqueios. Contudo vamos deixar nosso ambiente preparado para esses bloqueios e por isso crie o arquivo '''/etc/unbound/rpz.block.hosts.zone''' com esse conteúdo de exemplo:&lt;br /&gt;
 $TTL 2h&lt;br /&gt;
 @ IN SOA localhost. root.localhost. (2 6h 1h 1w 2h)&lt;br /&gt;
   IN NS  localhost.&lt;br /&gt;
 ; RPZ manual block hosts&lt;br /&gt;
 *.josedascoves.com CNAME .&lt;br /&gt;
 josedascoves.com CNAME .&lt;br /&gt;
No exemplo acima estamos bloqueando qualquer consulta de DNS para '''josedascoves.com''' ou qualquer coisa '''.josedascoves.com'''.&lt;br /&gt;
&lt;br /&gt;
Para testar podemos fazer assim do próprio servidor:&lt;br /&gt;
 # host josedascoves.com ::1&lt;br /&gt;
 Using domain server:&lt;br /&gt;
 Name: ::1&lt;br /&gt;
 Address: ::1#53&lt;br /&gt;
 Aliases:&lt;br /&gt;
 &lt;br /&gt;
 Host josedascoves.com not found: 3(NXDOMAIN)&lt;br /&gt;
Se a resposta for '''NXDOMAIN''' então está funcionando o bloqueio. Para incluir novos bloqueios basta adicionar os domínios, um abaixo do outro, conforme o exemplo que coloquei no arquivo RPZ.&lt;br /&gt;
&lt;br /&gt;
== Acertando o resolv.conf ==&lt;br /&gt;
Vamos modificar nosso /etc/resolv.conf para utilizar DNS externo. Sim você deve estar se perguntando em qual situação isso seria utilizado. Primeiro entenda que o Unbound não irá utilizar o DNS externo para fazer as consultas na Internet e sim, qualquer teste que você faça do servidor precisará apontar para o Unbound usando os IPs '''127.0.0.1''' ou '''::1'''. Faremos isso pela seguinte situação: imagine que o daemon unbound morreu mas você ainda continua com conectividade na Internet. Você conseguiria acessar qualquer local na Internet através do IP mas não através do hostname porque não conseguiria resolver nomes, seu unbound estaria fora do ar. Imagine ainda que você gostaria que seu servidor te avisasse do problema via Telegram ou e-mail. Por isso estamos utilizando um DNS externo no '''/etc/resolv.conf''', apenas para essas situações. Se você não quiser utilizar desse recurso, pode usar o '''127.0.0.1''' e '''::1''' no lugar.&lt;br /&gt;
 nameserver 8.8.8.8&lt;br /&gt;
 nameserver 8.8.4.4&lt;br /&gt;
 nameserver 2001:4860:4860::8888&lt;br /&gt;
&lt;br /&gt;
== Script de teste de recursividade ==&lt;br /&gt;
Estamos montando uma '''Rede de DNS Recursivo Anycast''', então é muito importante que você monitore essa rede para saber se algum node morreu e iniciar o troubleshooting, resolver o problema e levantar o sistema novamente. Tudo isso é importante mas o cliente não deve ficar esperando até você resolver o problema, seu sistema precisa ser inteligente o suficiente para se remover da Rede quando tiver um problema e se inserir novamente, quando o problema estiver sido solucionado. Se você montar uma Rede de DNS e um dos nodes apresentar algum problema, todos os clientes atendidos por aquele node migrarão automaticamente e transparentemente para outro '''DNS Recursivo Anycast''' mais próximo. Isso se chama '''disponibilidade'''.&lt;br /&gt;
&lt;br /&gt;
O script '''/root/scripts/checa_dns.sh''' abaixo tem a função de fazer os testes de recursividade e checar se o daemon do unbound continua rodando. Se algo acontecer, ele para o anúncio do '''10.10.10.10''' e '''10.10.9.9''' e retorna eles quando tudo estiver resolvido.&lt;br /&gt;
 # mkdir /root/scripts&lt;br /&gt;
&lt;br /&gt;
 #!/usr/bin/env bash&lt;br /&gt;
 #Script para teste de DNS v2.1&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 #Informe um domínio por linha:&lt;br /&gt;
 dominios_testar=(&lt;br /&gt;
 www.google.com&lt;br /&gt;
 www.terra.com.br&lt;br /&gt;
 www.uol.com.br&lt;br /&gt;
 www.globo.com&lt;br /&gt;
 www.facebook.com&lt;br /&gt;
 www.youtube.com&lt;br /&gt;
 www.twitch.com&lt;br /&gt;
 www.discord.com&lt;br /&gt;
 www.debian.org&lt;br /&gt;
 www.redhat.com&lt;br /&gt;
 )&lt;br /&gt;
 corte_taxa_falha=100 #Porcentagem de falha para executar uma ação&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 remove_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; != &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no description' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME morreu!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 adiciona_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; == &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'description LOOPBACKS' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME retornou do inferno!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
 if [ $? -ne 0 ]; then&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME morreu DNS mas tentando levantar!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    systemctl restart unbound&lt;br /&gt;
    systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
    if [ $? -ne 0 ]; then&lt;br /&gt;
       remove_ospf&lt;br /&gt;
       exit&lt;br /&gt;
    fi&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME servico DNS voltou mas tinha morrido!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 qt_falhas=0&lt;br /&gt;
 qt_total=&amp;quot;${#dominios_testar[@]}&amp;quot;&lt;br /&gt;
 echo &amp;quot;total_dominios: $qt_total&amp;quot;&lt;br /&gt;
 for site in &amp;quot;${dominios_testar[@]}&amp;quot;&lt;br /&gt;
 do&lt;br /&gt;
   unbound-control flush $site &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   resolver=&amp;quot;127.0.0.1&amp;quot;&lt;br /&gt;
   echo -e &amp;quot; - dominio $site - $resolver - \c&amp;quot;&lt;br /&gt;
   host $site $resolver &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   if [ $? -ne 0 ]; then&lt;br /&gt;
      ((qt_falhas++))&lt;br /&gt;
      echo -e &amp;quot;[Falhou]&amp;quot;&lt;br /&gt;
   else&lt;br /&gt;
      echo -e &amp;quot;[OK]&amp;quot;&lt;br /&gt;
   fi&lt;br /&gt;
 done&lt;br /&gt;
  &lt;br /&gt;
 taxa_falha=$((qt_falhas*100/qt_total))&lt;br /&gt;
 echo &amp;quot;Falhas $qt_falhas/$qt_total ($taxa_falha%)&amp;quot;&lt;br /&gt;
  &lt;br /&gt;
 if [ &amp;quot;$taxa_falha&amp;quot; -ge &amp;quot;$corte_taxa_falha&amp;quot; ]; then&lt;br /&gt;
    remove_ospf&lt;br /&gt;
    exit&lt;br /&gt;
 fi&lt;br /&gt;
 adiciona_ospf&lt;br /&gt;
Se rodarmos o script manualmente veremos isto:&lt;br /&gt;
 # /root/scripts/checa_dns.sh&lt;br /&gt;
 total_dominios: 10&lt;br /&gt;
  - dominio www.google.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.terra.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.uol.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.globo.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.facebook.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.youtube.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.twitch.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.discord.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.debian.org - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.redhat.com - 127.0.0.1 - [OK]&lt;br /&gt;
 Falhas 0/10 (0%)&lt;br /&gt;
Se acontecer 100% de falhas o script irá remover os anúncios do OSPF. Se o daemon do unbound morrer, ele tentará reiniciá-lo. Se tudo normalizar o script irá retornar os anúncios para o OSPF. Deixei comentado no script as partes que enviariam uma notificação para o Telegram. Existem diversas documentações sobre isso na Internet, eu mesmo tenho uma. Assim que eu publicar aqui, atualizo essa documentação e sinta-se à vontade de modificar como desejar.&lt;br /&gt;
 # chmod 700 /root/scripts/checa_dns.sh&lt;br /&gt;
Adicione a linha abaixo em seu '''/etc/crontab''':&lt;br /&gt;
 */1 *   * * *   root    /root/scripts/checa_dns.sh&lt;br /&gt;
&lt;br /&gt;
== Habilitando o DoH (&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; over HTTPS) - opcional ==&lt;br /&gt;
Para habilitar o '''DoH''' no Unbound é bem simples. O recurso do '''DoH''' vem para trazer mais segurança e privacidade para o usuário. É um recurso muito pouco utilizado ainda mas que seu cliente pode vir a pedir algum dia.&lt;br /&gt;
&lt;br /&gt;
Você precisará gerar certificados SSL legítimos e para isso você poderá usar o '''Let's Encrypt''' só que de uma forma não tão convencional.&lt;br /&gt;
&lt;br /&gt;
Na sequência vamos instalar o Let's Encrypt para gerarmos nosso certificado SSL:&lt;br /&gt;
 # apt install letsencrypt&lt;br /&gt;
Escolha um '''hostname''' para ser usado no nosso '''DoH''' e aponte ele no seu DNS Autoritativo para seus IPs 10.10.10.10 e 10.10.9.9. Aqui vamos usar o seguinte como exemplo: '''doh.brasilpeeringforum.org'''. Para gerarmos nosso certificado iremos usar o tipo '''DNS-01''', ele não necessita que tenhamos um servidor web rodando no servidor e nem tão pouco levanta um serviço na porta 80 para checar o hostname. Ele utiliza o DNS como validador e vai te solicitar que crie um registro '''CNAME''' no seu '''DNS Autoritativo''' para provar que você tem o controle sobre aquele hostname. Antes disso vamos instalar um programa em Python para podermos automatizar nossa renovação de certificado no futuro. Esse programa se encontra '''[https://github.com/joohoi/acme-dns-certbot-joohoi/raw/master/acme-dns-auth.py aqui]''' mas vou deixá-lo abaixo já modificado o interpretador.&lt;br /&gt;
&lt;br /&gt;
Crie o arquivo '''/etc/letsencrypt/acme-dns-auth.py''' com o conteúdo abaixo:&lt;br /&gt;
 #!/usr/bin/env python3&lt;br /&gt;
 import json&lt;br /&gt;
 import os&lt;br /&gt;
 import requests&lt;br /&gt;
 import sys&lt;br /&gt;
 &lt;br /&gt;
 ### EDIT THESE: Configuration values ###&lt;br /&gt;
 &lt;br /&gt;
 # URL to acme-dns instance&lt;br /&gt;
 ACMEDNS_URL = &amp;quot;&amp;lt;nowiki&amp;gt;https://auth.acme-dns.io&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
 # Path for acme-dns credential storage&lt;br /&gt;
 STORAGE_PATH = &amp;quot;/etc/letsencrypt/acmedns.json&amp;quot;&lt;br /&gt;
 # Whitelist for address ranges to allow the updates from&lt;br /&gt;
 # Example: ALLOW_FROM = [&amp;quot;192.168.10.0/24&amp;quot;, &amp;quot;::1/128&amp;quot;]&lt;br /&gt;
 ALLOW_FROM = []&lt;br /&gt;
 # Force re-registration. Overwrites the already existing acme-dns accounts.&lt;br /&gt;
 FORCE_REGISTER = False&lt;br /&gt;
 &lt;br /&gt;
 ###   DO NOT EDIT BELOW THIS POINT   ###&lt;br /&gt;
 ###         HERE BE DRAGONS          ###&lt;br /&gt;
 &lt;br /&gt;
 DOMAIN = os.environ[&amp;quot;CERTBOT_DOMAIN&amp;quot;]&lt;br /&gt;
 if DOMAIN.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
     DOMAIN = DOMAIN[2:]&lt;br /&gt;
 VALIDATION_DOMAIN = &amp;quot;_acme-challenge.&amp;quot;+DOMAIN&lt;br /&gt;
 VALIDATION_TOKEN = os.environ[&amp;quot;CERTBOT_VALIDATION&amp;quot;]&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 class AcmeDnsClient(object):&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
     Handles the communication with ACME-DNS API&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
     def __init__(self, acmedns_url):&lt;br /&gt;
         self.acmedns_url = acmedns_url&lt;br /&gt;
 &lt;br /&gt;
     def register_account(self, allowfrom):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Registers a new ACME-DNS account&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
         if allowfrom:&lt;br /&gt;
             # Include whitelisted networks to the registration call&lt;br /&gt;
             reg_data = {&amp;quot;allowfrom&amp;quot;: allowfrom}&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;,&lt;br /&gt;
                                 data=json.dumps(reg_data))&lt;br /&gt;
         else:&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;)&lt;br /&gt;
         if res.status_code == 201:&lt;br /&gt;
             # The request was successful&lt;br /&gt;
             return res.json()&lt;br /&gt;
         else:&lt;br /&gt;
             # Encountered an error&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to register a new acme-dns &amp;quot;&lt;br /&gt;
                    &amp;quot;account. HTTP status {}, Response body: {}&amp;quot;)&lt;br /&gt;
             print(msg.format(res.status_code, res.text))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def update_txt_record(self, account, txt):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Updates the TXT challenge record to ACME-DNS subdomain.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         update = {&amp;quot;subdomain&amp;quot;: account['subdomain'], &amp;quot;txt&amp;quot;: txt}&lt;br /&gt;
         headers = {&amp;quot;X-Api-User&amp;quot;: account['username'],&lt;br /&gt;
                    &amp;quot;X-Api-Key&amp;quot;: account['password'],&lt;br /&gt;
                    &amp;quot;Content-Type&amp;quot;: &amp;quot;application/json&amp;quot;}&lt;br /&gt;
         res = requests.post(self.acmedns_url+&amp;quot;/update&amp;quot;,&lt;br /&gt;
                             headers=headers,&lt;br /&gt;
                             data=json.dumps(update))&lt;br /&gt;
         if res.status_code == 200:&lt;br /&gt;
             # Successful update&lt;br /&gt;
             return&lt;br /&gt;
         else:&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to update TXT record in &amp;quot;&lt;br /&gt;
                    &amp;quot;acme-dns. \n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request headers:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request body:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response HTTP status: {}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response body: {}&amp;quot;)&lt;br /&gt;
             s_headers = json.dumps(headers, indent=2, sort_keys=True)&lt;br /&gt;
             s_update = json.dumps(update, indent=2, sort_keys=True)&lt;br /&gt;
             s_body = json.dumps(res.json(), indent=2, sort_keys=True)&lt;br /&gt;
             print(msg.format(s_headers, s_update, res.status_code, s_body))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
 class Storage(object):&lt;br /&gt;
     def __init__(self, storagepath):&lt;br /&gt;
         self.storagepath = storagepath&lt;br /&gt;
         self._data = self.load()&lt;br /&gt;
 &lt;br /&gt;
     def load(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Reads the storage content from the disk to a dict structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         data = dict()&lt;br /&gt;
         filedata = &amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             with open(self.storagepath, 'r') as fh:&lt;br /&gt;
                 filedata = fh.read()&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             if os.path.isfile(self.storagepath):&lt;br /&gt;
                 # Only error out if file exists, but cannot be read&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage file exists but cannot be read&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         try:&lt;br /&gt;
             data = json.loads(filedata)&lt;br /&gt;
         except ValueError:&lt;br /&gt;
             if len(filedata) &amp;gt; 0:&lt;br /&gt;
                 # Storage file is corrupted&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage JSON is corrupted&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         return data&lt;br /&gt;
 &lt;br /&gt;
     def save(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Saves the storage content to disk&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         serialized = json.dumps(self._data)&lt;br /&gt;
         try:&lt;br /&gt;
             with os.fdopen(os.open(self.storagepath,&lt;br /&gt;
                                    os.O_WRONLY | os.O_CREAT, 0o600), 'w') as fh:&lt;br /&gt;
                 fh.truncate()&lt;br /&gt;
                 fh.write(serialized)&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             print(&amp;quot;ERROR: Could not write storage file.&amp;quot;)&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def put(self, key, value):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Puts the configuration value to storage and sanitize it&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         # If wildcard domain, remove the wildcard part as this will use the&lt;br /&gt;
         # same validation record name as the base domain&lt;br /&gt;
         if key.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
             key = key[2:]&lt;br /&gt;
         self._data[key] = value&lt;br /&gt;
 &lt;br /&gt;
     def fetch(self, key):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Gets configuration value from storage&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             return self._data[key]&lt;br /&gt;
         except KeyError:&lt;br /&gt;
             return None&lt;br /&gt;
 &lt;br /&gt;
 if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
     # Init&lt;br /&gt;
     client = AcmeDnsClient(ACMEDNS_URL)&lt;br /&gt;
     storage = Storage(STORAGE_PATH)&lt;br /&gt;
 &lt;br /&gt;
     # Check if an account already exists in storage&lt;br /&gt;
     account = storage.fetch(DOMAIN)&lt;br /&gt;
     if FORCE_REGISTER or not account:&lt;br /&gt;
         # Create and save the new account&lt;br /&gt;
         account = client.register_account(ALLOW_FROM)&lt;br /&gt;
         storage.put(DOMAIN, account)&lt;br /&gt;
         storage.save()&lt;br /&gt;
 &lt;br /&gt;
         # Display the notification for the user to update the main zone&lt;br /&gt;
         msg = &amp;quot;Please add the following CNAME record to your main DNS zone:\n{}&amp;quot;&lt;br /&gt;
         cname = &amp;quot;{} CNAME {}.&amp;quot;.format(VALIDATION_DOMAIN, account[&amp;quot;fulldomain&amp;quot;])&lt;br /&gt;
         print(msg.format(cname))&lt;br /&gt;
 &lt;br /&gt;
     # Update the TXT record in acme-dns instance&lt;br /&gt;
     client.update_txt_record(account, VALIDATION_TOKEN)&lt;br /&gt;
&lt;br /&gt;
 # chmod +x /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
Usaremos a seguinte instrução para criar nosso certificado:&lt;br /&gt;
 # certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d doh.brasilpeeringforum.org&lt;br /&gt;
 Saving debug log to /var/log/letsencrypt/letsencrypt.log&lt;br /&gt;
 Plugins selected: Authenticator manual, Installer None&lt;br /&gt;
 Cert is due for renewal, auto-renewing...&lt;br /&gt;
 Renewing an existing certificate for doh.brasilpeeringforum.org&lt;br /&gt;
 Performing the following challenges:&lt;br /&gt;
 dns-01 challenge for doh.brasilpeeringforum.org&lt;br /&gt;
 Running manual-auth-hook command: /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
 Output from manual-auth-hook command acme-dns-auth.py:&lt;br /&gt;
 Please add the following CNAME record to your main DNS zone:&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
 &lt;br /&gt;
 Waiting for verification...&lt;br /&gt;
 &lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Challenges loaded. Press continue to submit to CA. Pass &amp;quot;-v&amp;quot; for more info about&lt;br /&gt;
 challenges.&lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Press Enter to Continue&lt;br /&gt;
Nesse momento você cria o registro '''CNAME''' no seu DNS Autoritativo conforme ele solicitou: '''_acme-challenge.doh.brasilpeeringforum.org IN CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.''' e somente depois de criado e checado no DNS, você pressiona o '''Enter''' para continuar. Você pode checar dessa forma:&lt;br /&gt;
 # host -t cname _acme-challenge.doh.brasilpeeringforum.org&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org is an alias for b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
Para que nosso certificado seja automaticamente renovado colocaremos no '''/etc/crontab''' a seguinte linha abaixo:&lt;br /&gt;
 00 00   1 * *   root    /usr/bin/certbot -q renew&lt;br /&gt;
Acima temos a instrução para renovação automática do certificado. Repare que você vai precisar também copiar esse certificado para seus outros servidores, escolha um servidor para manter o certificado sempre atualizado e crie um script que faça a mesma cópia remotamente para os outros servidores. O '''scp''' e o '''rsync''' são seus aliados nisso.&lt;br /&gt;
&lt;br /&gt;
=== Configurando o Unbound ===&lt;br /&gt;
Em nosso '''/etc/unbound/unbound.conf.d/local.conf''', adicionaremos no bloco &amp;quot;'''server:'''&amp;quot; o seguinte:&lt;br /&gt;
 interface: 10.10.10.10@443 &lt;br /&gt;
 interface: 10.10.9.9@443&lt;br /&gt;
 interface: fd00::10:10:10:10@443&lt;br /&gt;
 interface: fd00::10:10:9:9@443&lt;br /&gt;
 tls-service-key: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/privkey.pem&amp;quot; &lt;br /&gt;
 tls-service-pem: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/fullchain.pem&amp;quot;&lt;br /&gt;
Para usar o recurso do '''DoH''' você precisará habilitar o recurso no seu navegador e informar a URL. Vou colocar o exemplo do '''Google Chrome''': Digite '''chrome://settings/security?search=dns''' no seu Chrome e ative '''Usar DNS seguro''', selecione '''Personalizado''' e adicione nossa URL:&lt;br /&gt;
[[Arquivo:Doh bpf2.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Finalizando ==&lt;br /&gt;
Aqui finalizamos nosso projeto para uma Rede de DNS(s) Recursivos Anycast com Hyperlocal. Esse projeto é escalável, seguro, resiliente e você entregará muito mais qualidade de Internet para o seu cliente. Pare de entregar o '''8.8.8.8''' para os seus clientes, você está contribuindo para uma Internet mais lenta, sem a qualidade que o seu cliente merece. Investi meu tempo, que é muito pouco, para deixar esse documento para a comunidade, para você melhorar o seu ISP, para dar um UP! nele, então vamos começar 2023 com o pé direito. O que acha?&lt;br /&gt;
&lt;br /&gt;
Como prova de conceito, uma imagem abaixo onde temos uma Rede em produção de DNS(s) Recursivos Anycast e apontando exatamente o momento em que houve alguma situação que fez com que as queries de DNS, convergissem de um node para outro, de forma transparente e automática para o cliente. Podemos notar também que ao ser resolvido o problema, o tráfego retornou para o seu node correto:&lt;br /&gt;
[[Arquivo:Convergencia.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== KINDNS (Stands for Knowledge-Sharing and Instantiating Norms for DNS and Naming Security) ==&lt;br /&gt;
Achou que havia terminado? Agora que você tem a capacidade de montar uma '''Rede de DNS Recursivo''' com todas essas features acima, com todas as ferramentas que foram comentadas, o que acha de certificar o que fez?&lt;br /&gt;
&lt;br /&gt;
Assim como o [https://www.manrs.org/ MANRS] veio para certificar nosso sistema de roteamento na Internet, agora temos o [https://kindns.org/ KINDNS] para certificar que nossos sistemas de DNS estão bem feitos e dentro dos padrões de segurança. Existem '''7 ações''' que podem ser certificadas para nossos DNS Recursivos e estão aqui em https://kindns.org/shared-private-resolvers/. Com essa nossa documentação, se bem aplicada, você pode se candidatar ao KINDNS e ter seu ASN listado aqui https://kindns.org/participants/&lt;br /&gt;
&lt;br /&gt;
Obter e manter o '''MANRS''' e '''KINDNS''' demonstra seu compromisso com as Boas Práticas, contribui para termos uma '''Internet''' mais segura e te abre portas para novos negócios que possam exigir essas conformidades.&lt;br /&gt;
&lt;br /&gt;
Autor: [[Usuário:Gondim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Infraestrutura]]&lt;br /&gt;
__FORCARTDC__&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Recursivo99.png&amp;diff=3949</id>
		<title>Arquivo:Recursivo99.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=Arquivo:Recursivo99.png&amp;diff=3949"/>
		<updated>2025-09-16T02:20:01Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;recursivo99&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3945</id>
		<title>DNS Recursivo Anycast Hyperlocal</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3945"/>
		<updated>2025-09-14T13:27:05Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
==Introdução==&lt;br /&gt;
Você sabe como funciona a Internet? Essa é uma pergunta que meu amigo '''Thiago Ayub''' sempre faz aos seus candidatos à vagas de emprego e não importa o quanto tenham de experiência em '''Engenharia de Redes''', todos sempre travam nesse momento. Todos estão sempre prontos e preparados para resolver os problemas mais cabeludos em '''BGP''', '''OSPF''', '''MPLS''', etc mas travam com essa simples pergunta. Para contextualizar e visualizarmos melhor vamos nos atentar à imagem abaixo e uma explicação simplificada de como funciona:&lt;br /&gt;
[[Arquivo:Dns hierarquia.png|esquerda|commoldura]]&lt;br /&gt;
Tudo começa com um usuário sentado confortavelmente e querendo acessar um conteúdo disponível na Internet. Ele digita em seu navegador preferido a URL: '''&amp;lt;nowiki&amp;gt;https://wiki.brasilpeeringforum.org&amp;lt;/nowiki&amp;gt;''',&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;1)&amp;lt;/big&amp;gt;''' &amp;lt;big&amp;gt;O&amp;lt;/big&amp;gt; &amp;lt;big&amp;gt;navegador irá requisitar do '''DNS Recursivo''' utilizado pelo usuário, o '''endereço IP''' que responde pelo nome '''wiki.'''&amp;lt;/big&amp;gt;'''brasilpeeringforum.org'''&amp;lt;big&amp;gt;. Isso porque todos os acessos se dão na Internet através do '''endereço''' '''IP''' e não através do '''nome'''. Imaginem se tivéssemos que decorar os endereços IPs de todos os sites e serviços que quiséssemos acessar na Internet?&amp;lt;/big&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;big&amp;gt;'''2)''' Nosso DNS Recursivo checa se a informação consta em seu cache.&amp;lt;/big&amp;gt; Se a informação existir ela é devolvida ao navegador do usuário e aí este consegue acessar o site.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Do contrário o DNS Recursivo pergunta ao '''Root Server''' quem é o '''TLD (Top Level Domain)''' responsável para atender a requisição. &lt;br /&gt;
&lt;br /&gt;
'''4)''' O '''Root Server''' informa ao DNS Recursivo o endereço do '''TLD responsável'''. No Brasil o '''TLD''' responsável pelo '''.br''' seria o '''Registro.br'''.&lt;br /&gt;
&lt;br /&gt;
'''5)''' O DNS Recursivo pergunta ao '''TLD''' sobre '''wiki.brasilpeeringforum.org''' e este responde com os endereços IP dos '''DNS Autoritativos''' responsáveis pelo domínio '''brasilpeeringforum.org.'''&lt;br /&gt;
&lt;br /&gt;
'''6)''' O DNS Recursivo pergunta aos '''DNS Autoritativos''' pelo '''wiki.brasilpeeringforum.org''' e este responde com o '''endereço IP'''.&lt;br /&gt;
&lt;br /&gt;
'''7)''' Por último o DNS Recursivo devolve a informação para o navegador do usuário.&lt;br /&gt;
&lt;br /&gt;
Como que se dá a comunicação entre os '''DNS(s) Recursivos, Root Servers, TLDs''' e '''Autoritativos'''? Como que o navegador do usuário, após receber o IP do site, consegue chegar no servidor que tem o conteúdo? Isso só é possível devido ao protocolo chamado '''BGP (Border Gateway Protocol)''', todos os caminhos que conhecemos como rotas de destino, são anunciadas por milhares de participantes na '''Internet''' conhecidos como '''AS (Autonomous System)''', esses participantes se interligam para disponibilizar conteúdos e acessos pelo mundo aos milhares de usuários. É uma imensa rede colaborativa formada por Empresas, Universidades, Governos e todos que queiram se interconectar. Percebam que sem o '''BGP''', que serve de caminho para chegarmos nos conteúdos e sem o '''DNS (Domain Name System)''' para traduzir o nome para o endereço IP, a '''Internet''' não funcionaria e por isso precisamos cuidar muito bem desses dois serviços.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Mas não acaba por aí. O '''DNS Recursivo''' tem um papel muito importante para o Provedor de Internet e que envolve segurança, qualidade de acesso à Internet e a disponibilidade do serviço entregue ao cliente. Quando bem configurado acelera as consultas dos acessos graças ao seu cache interno, mas para que isso seja percebido pelo assinante, é necessário que esteja o mais próximo possível do seu cliente.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Um erro que destrói a qualidade do nosso serviço ==&lt;br /&gt;
Um erro muito comum que muitas operadoras cometem é utilizar DNS Recursivo externo, como o '''8.8.8.8''', '''1.1.1.1''' e outros, para seus clientes. Quanto mais próximo dos seus clientes, mais qualidade de serviço estará entregando a eles. Conteúdos serão entregues mais rapidamente pois serão resolvidos e armazenados em caches locais e não consultados remotamente na Internet. Para falar mais sobre isso, te convido leitor desse documento, que assista essa palestra do '''Thiago Ayub''' no '''GTER 51/GTS 37''' (2022) '''8.888 MOTIVOS PARA NÃO USAR DNS RECURSIVO EXTERNO EM SEU AS''': https://www.youtube.com/watch?v=Rsvpu5uF2Io&lt;br /&gt;
&lt;br /&gt;
== Objetivo ==&lt;br /&gt;
O objetivo desta documentação não é te ensinar tudo sobre '''DNS''', '''BGP''', '''OSPF''' e nem tão pouco sobre GNU/Linux e sim te mostrar um exemplo de servidor DNS Recursivo implementado pensando em segurança, qualidade e resiliência. Usaremos em todas as nossas documentações o [https://www.debian.org/ Debian GNU/Linux], por ser uma distribuição que considero uma obra de arte criada por uma enorme comunidade séria, com vasta experiência de anos, qualidade no empacotamento dos programas, estável e com uma equipe de segurança excelente e ativa. Caso você leitor, utilize alguma outra distribuição GNU/Linux, todo conteúdo apresentado aqui pode ser aplicado em outras distros, desde que respeitando as particularidades de cada uma.&lt;br /&gt;
&lt;br /&gt;
Aqui construiremos um sistema do tipo '''Anycast''', ou seja, terás o serviço rodando em diversas localidades da sua Rede utilizando o mesmo endereçamento IP e que atenderá seu cliente mais próximo. Em caso de falhas, seus clientes automaticamente e de forma transparente continuarão consultando o DNS mais próximo deles. Para que ele funcione dessa forma você precisará ter uma '''Rede OSPF''' implementada no seu Provedor Internet ou algum outro protocolo como por exemplo o '''ISIS,''' mas esse documento não irá abordar o '''ISIS'''. Também utilizaremos o '''Hyperlocal''' como recurso adicional para gerar algumas proteções de segurança e velocidade na resposta relacionada aos servidores de DNS Raiz da Internet.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
Para exemplificar nosso servidor de DNS Recursivo, usaremos como base das explicações um diagrama demonstrando o uso do DNS Recursivo em uma Rede fictícia. Adotaremos IPs privados e reservados para demonstrar todo o ambiente do Provedor de Internet.&lt;br /&gt;
[[Arquivo:Diagrama dns recursiv2.png|alt=|esquerda|miniaturadaimagem|695x695px]]&lt;br /&gt;
Nesse diagrama podemos observar alguns detalhes técnicos como por exemplo: existem '''3 servidores de DNS Recursivo''' posicionados em locais diferentes, que poderiam estar em bairros diferentes e até em cidades diferentes. Em cada servidor teremos '''2 loopbacks''' com os IPs:&lt;br /&gt;
&lt;br /&gt;
'''10.10.10.10/32 - fc00::10:10:10:10/128'''&lt;br /&gt;
&lt;br /&gt;
'''10.10.9.9/32 - fc00::10:10:9:9/128'''&lt;br /&gt;
&lt;br /&gt;
Esses IPs serão entregues pelos concentradores '''PPPoE''' ou '''IPoE''' ('''BNG''') para seus clientes como '''DNS primário''' e '''secundário'''. Podemos usar IPs privados como DNS primário e secundário em um ambiente real? Sim podemos, desde que não sejam IPs que possam ter problemas com as redes privadas dos clientes. Ex.: rede do cliente usando '''192.168.0.0/24'''. Se entregarmos o DNS sendo '''192.168.0.10''' e '''192.168.0.20''' teremos problemas e o cliente ficará sem Internet, porque '''192.168.0.10''' e '''192.168.0.20''' fazem parte da rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
Agora entregando '''10.10.10.10,''' '''10.10.9.9, fc00::10:10:10:10 e fc00::10:10:9:9''' não teríamos problemas com a rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
'''Motivos para usarmos IPs privados:'''&lt;br /&gt;
* O principal motivo está relacionado com a segurança, uma vez que sendo um IP privado, não pode sofrer ataques DDoS direcionados diretamente para ele, vindos da Internet.&lt;br /&gt;
* Nem mesmo o cliente da sua rede conhece os '''IPs públicos''' utilizados para recursividade na Internet.&lt;br /&gt;
* Memorizar os IPs '''10.10.10.10''' e '''10.10.9.9''' é tão fácil quanto memorizar o '''8.8.8.8''' e o '''1.1.1.1'''. Mais fácil para o seu técnico guardar essa informação e utilizar onde for necessário.&lt;br /&gt;
Cada servidor DNS Recursivo possui um '''IPv4 público''', aqui representado por '''198.18.x.x/27''' e um '''IPv6 global''' representado por um IP dentro do prefixo '''2001:db8::/32'''. Cada servidor precisa ter os seus próprios IPs e são através destes IPs que as consultas de DNS serão realizadas na Internet.&lt;br /&gt;
&lt;br /&gt;
Nessa topologia usando '''Anycast''', o cliente será sempre atendido pelo '''DNS Recursivo''' mais próximo, desde que os pesos no '''OSPF''' estejam ajustados corretamente.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
== Dados do servidor ==&lt;br /&gt;
Podemos utilizar um sistema virtualizado ou não. Sistemas virtualizados são bem vindos pois são mais simples quando precisamos fazer backups, levantar outros sistemas sem complicações e se precisarmos restaurar rapidamente algum sistema que ficou indisponível por algum motivo. A configuração abaixo tem capacidade para atender algo em torno a '''50.000 assinantes ou mais'''. O DNS Recursivo é um serviço que pode ser utilizado até mesmo em um '''Raspberry Pi''' e atender operações pequenas, nesse caso com o intuito de economizar energia e espaço. Nosso foco aqui é montar uma rede de '''DNS Recursivo Anycast com HyperLocal'''. Como comentei acima o servidor deve ficar o mais próximo dos clientes para termos a '''menor latência possível''' e '''sempre menor que 5ms''' entre o cliente e o servidor.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!CPU&lt;br /&gt;
!Memória&lt;br /&gt;
!Disco&lt;br /&gt;
!Sistema&lt;br /&gt;
|-&lt;br /&gt;
|2.4Ghz 4 cores&lt;br /&gt;
|16G DDR4&lt;br /&gt;
|30G&lt;br /&gt;
|Debian 12 amd64 (Bookworm)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Softwares utilizados ==&lt;br /&gt;
* Debian 12 amd64 (Bookworm) instalação mínima.&lt;br /&gt;
&lt;br /&gt;
* [https://frrouting.org/ FRRouting].&lt;br /&gt;
* Unbound.&lt;br /&gt;
* Chrony (NTP/NTS).&lt;br /&gt;
* Shell script em bash.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades que teremos ==&lt;br /&gt;
* Sistema em Anycast.&lt;br /&gt;
* Hyperlocal.&lt;br /&gt;
* Controle de acesso por &amp;lt;abbr&amp;gt;ACL&amp;lt;/abbr&amp;gt;.&lt;br /&gt;
* RPZ (Response Policy Zone).&lt;br /&gt;
* Bloqueio de consultas do tipo ANY.&lt;br /&gt;
* QNAME minimization habilitado. (habilitado por default no Unbound)&lt;br /&gt;
* Recursividade em IPv4 e IPv6.&lt;br /&gt;
* DNSSEC habilitado.&lt;br /&gt;
* &amp;lt;abbr&amp;gt;DoH (DNS&amp;lt;/abbr&amp;gt; over HTTPS) habilitado.&lt;br /&gt;
&lt;br /&gt;
== Monitoramento ==&lt;br /&gt;
O monitoramento é algo bem específico e não é o foco deste documento mas é extremamente importante que você monitore seus servidores de DNS por alguma ferramenta como o Zabbix. Aqui mostrarei apenas como enviar as informações para o Zabbix. Algumas coisas que você deveria monitorar nos servidores de DNS Recursivo:&lt;br /&gt;
* Serviço do unbound parou.&lt;br /&gt;
* Perda de pacotes.&lt;br /&gt;
* Latência alta de pacotes.&lt;br /&gt;
* Lentidão na resolução de queries.&lt;br /&gt;
* CPU alta.&lt;br /&gt;
* Load alto.&lt;br /&gt;
* Memória com uso alto.&lt;br /&gt;
* Disco com pouco espaço.&lt;br /&gt;
* Queda brusca nas queries.&lt;br /&gt;
* A recursividade parou de funcionar.&lt;br /&gt;
* A recursividade voltou a funcionar.&lt;br /&gt;
Este abaixo é um exemplo de monitoramento de um sistema de DNS Recursivo que atende 50.000 assinantes:&lt;br /&gt;
[[Arquivo:Grafana dns.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Configurando a Rede ==&lt;br /&gt;
Nossa documentação será baseada no diagrama apresentado acima e por isso configuraremos apenas um dos três servidores, porque os outros serão configurados da mesma forma, só que com dados diferentes. Para tanto assumirei que já temos um sistema Debian instalado com o mínimo de pacotes e somente com sshd, para que possamos acessar remotamente mais tarde. '''Não instale um ambiente gráfico no servidor''', você não deve querer fazer isso por diversos motivos e os principais: primeiro porque não é um Desktop e segundo porque o ambiente gráfico devoraria toda a memória com recursos que não seriam úteis aqui.&lt;br /&gt;
&lt;br /&gt;
Em '''/etc/network/interfaces''' deixaremos assim:&lt;br /&gt;
 # This file describes the network interfaces available on your system&lt;br /&gt;
 # and how to activate them. For more information, see interfaces(5).&lt;br /&gt;
  &lt;br /&gt;
 source /etc/network/interfaces.d/*&lt;br /&gt;
  &lt;br /&gt;
 # The loopback network interface&lt;br /&gt;
 auto lo&lt;br /&gt;
 iface lo inet loopback&lt;br /&gt;
  &lt;br /&gt;
 auto lo:0&lt;br /&gt;
 iface lo:0 inet static&lt;br /&gt;
       address 10.10.10.10/32&lt;br /&gt;
  &lt;br /&gt;
 auto lo:1&lt;br /&gt;
 iface lo:1 inet static&lt;br /&gt;
       address 10.10.9.9/32&lt;br /&gt;
 &lt;br /&gt;
 auto lo:2&lt;br /&gt;
 iface lo:2 inet6 static&lt;br /&gt;
       address fc00::10:10:10:10/128&lt;br /&gt;
 &lt;br /&gt;
 auto lo:3&lt;br /&gt;
 iface lo:3 inet6 static&lt;br /&gt;
       address fc00::10:10:9:9/128&lt;br /&gt;
  &lt;br /&gt;
 # The primary network interface&lt;br /&gt;
 auto ens18&lt;br /&gt;
 iface ens18 inet static&lt;br /&gt;
         address 198.18.1.10/27&lt;br /&gt;
         gateway 198.18.1.1&lt;br /&gt;
  &lt;br /&gt;
 iface ens18 inet6 static&lt;br /&gt;
         address 2001:db8::faca:198:18:1:10/64&lt;br /&gt;
         gateway 2001:db8::faca:198:18:1:1&lt;br /&gt;
  &lt;br /&gt;
 # The secondary network interface&lt;br /&gt;
 auto ens18:0&lt;br /&gt;
 iface ens18:0 inet static&lt;br /&gt;
         address 172.16.0.6/30&lt;br /&gt;
Nesse cenário temos as duas '''loopbacks''' com os IPs '''10.10.10.10''', '''10.10.9.9, fc00::10:10:10:10''' e '''fc00::10:10:9:9''' que serão anunciados via OSPF para a rede e serem entregues aos clientes via BNG. Os IPs '''198.18.1.10''' e '''2001:db8::faca:198:18:1:10''' serão usados para fazerem a recursividade na Internet tanto em IPv4 quanto em IPv6. Esses IPs não devem ser divulgados para clientes; os IPs públicos são dedicados apenas para essa finalidade.&lt;br /&gt;
&lt;br /&gt;
== Configuração dos repositórios Debian ==&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list''' conforme abaixo:&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://security.debian.org/debian-security&amp;lt;/nowiki&amp;gt; bookworm-security main contrib non-free non-free-firmware&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian&amp;lt;/nowiki&amp;gt; bookworm main contrib non-free non-free-firmware&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian&amp;lt;/nowiki&amp;gt; bookworm-updates main contrib non-free non-free-firmware&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian&amp;lt;/nowiki&amp;gt; bookworm-backports main contrib non-free non-free-firmware&lt;br /&gt;
Após a configuração vamos instalar alguns pacotes necessários e outros úteis:&lt;br /&gt;
 # apt update &amp;amp;&amp;amp; apt full-upgrade&lt;br /&gt;
 # apt install net-tools nftables htop iotop sipcalc tcpdump curl gnupg rsync wget host dnsutils mtr-tiny bmon sudo tmux whois ethtool dnstop&lt;br /&gt;
&lt;br /&gt;
== Fazendo algum tuning no sistema ==&lt;br /&gt;
Em '''/etc/sysctl.conf''' adicionamos no final do arquivo essas instruções:&lt;br /&gt;
 net.core.rmem_max = 2147483647&lt;br /&gt;
 net.core.wmem_max = 2147483647&lt;br /&gt;
 net.ipv4.tcp_rmem = 4096 87380 2147483647&lt;br /&gt;
 net.ipv4.tcp_wmem = 4096 65536 2147483647&lt;br /&gt;
 net.netfilter.nf_conntrack_buckets = 512000&lt;br /&gt;
 net.netfilter.nf_conntrack_max = 4096000&lt;br /&gt;
 vm.swappiness=10&lt;br /&gt;
Estamos fazendo algumas melhorias de memória, algumas relacionadas a '''conntrack''' porque se for usar um filtro de pacotes stateful, como o '''Netfilter/IPTables''' ou '''Netfilter/NFTables''', o valor default da tabela é pequeno e dependendo da situação, se estourar essa tabela, as consultas de DNS terão problemas também. O DNS Recursivo não deve ficar aberto para qualquer um na Internet, ele deve ser liberado apenas para seus clientes. Podemos fazer através das ACLs do Unbound e pelo filtro de pacotes. O último parâmetro diz respeito ao uso de swap, por padrão o Debian permite o uso de swap após 40% do uso da memória, nesse caso estamos dizendo para o sistema usar o swap com 90% de uso da memória.&lt;br /&gt;
&lt;br /&gt;
Precisamos adicionar o módulo '''nf_conntrack''' em '''/etc/modules''' para que seja carregado em tempo de boot, senão os parâmetros de '''conntrack''' que colocamos em '''/etc/sysctl.conf''' não serão carregados.&lt;br /&gt;
 # echo nf_conntrack &amp;gt;&amp;gt; /etc/modules&lt;br /&gt;
 # modprobe nf_conntrack&lt;br /&gt;
 # sysctl -p&lt;br /&gt;
&lt;br /&gt;
== Instalando o FRRouting ==&lt;br /&gt;
O FRRouting é o programa que usaremos para fazer os anúncios das nossas loopbacks via OSPF. Nesse documento usaremos a versão 10.x e para isso precisaremos configurar o repositório oficial do FRRouting e instalar os pacotes:&lt;br /&gt;
 # curl -s &amp;lt;nowiki&amp;gt;https://deb.frrouting.org/frr/keys.gpg&amp;lt;/nowiki&amp;gt; | tee /usr/share/keyrings/frrouting.gpg &amp;gt; /dev/null&lt;br /&gt;
 # echo &amp;quot;deb [signed-by=/usr/share/keyrings/frrouting.gpg] &amp;lt;nowiki&amp;gt;https://deb.frrouting.org/frr&amp;lt;/nowiki&amp;gt; bookworm frr-10&amp;quot; &amp;gt; /etc/apt/sources.list.d/frr.list&lt;br /&gt;
 # apt update&lt;br /&gt;
 # apt install frr frr-doc frr-pythontools&lt;br /&gt;
Aconselho depois de instalar os pacotes, marcá-los para não atualizar juntamente com os demais pacotes, isso é para evitar de ocorrer alguma atualização no FRRouting, que torne o serviço instável por algum motivo. Não que isso vá ocorrer, mas é melhor fazer essa atualização quando realmente for necessário.&lt;br /&gt;
 # apt-mark hold frr frr-doc frr-pythontools&lt;br /&gt;
Após esse comando acima, o sistema manterá a instalação original do pacote intacta. Para desbloquear basta executar o comando abaixo:&lt;br /&gt;
 # apt-mark unhold frr frr-doc frr-pythontools&lt;br /&gt;
&lt;br /&gt;
== Removendo o APPARMOR ==&lt;br /&gt;
O '''APPARMOR''' às vezes causa mais problemas que solução e se não for fazer uma completa configuração nele, é melhor desabilitá-lo. Para fazer isso efetivamente, o procedimento é esse abaixo:&lt;br /&gt;
 # mkdir -p /etc/default/grub.d&lt;br /&gt;
 # echo 'GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;$GRUB_CMDLINE_LINUX_DEFAULT apparmor=0&amp;quot;' | tee /etc/default/grub.d/apparmor.cfg&lt;br /&gt;
 # update-grub&lt;br /&gt;
 # reboot&lt;br /&gt;
&lt;br /&gt;
== Instalando o Unbound ==&lt;br /&gt;
Nesse momento ainda não iremos configurar o Unbound, apenas instalar o pacote e acertar o ambiente. Vamos instalar o unbound do backports porque este já possui suporte ao DoH que veremos mais à frente.&lt;br /&gt;
 # apt install unbound dns-root-data&lt;br /&gt;
 # mkdir -p /var/log/unbound&lt;br /&gt;
 # touch /var/log/unbound/unbound.log&lt;br /&gt;
 # chown -R unbound:unbound /var/log/unbound/&lt;br /&gt;
 # systemctl restart unbound&lt;br /&gt;
Configurando o logrotate:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/logrotate.d/unbound&lt;br /&gt;
 /var/log/unbound/unbound.log {&lt;br /&gt;
     rotate 5&lt;br /&gt;
     weekly&lt;br /&gt;
     postrotate&lt;br /&gt;
         unbound-control log_reopen&lt;br /&gt;
     endscript&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
Reiniciando o serviço:&lt;br /&gt;
 # systemctl restart logrotate.service&lt;br /&gt;
&lt;br /&gt;
== Desabilitando THP (Transparente Huge Pages) em arquitetura AMD64 ==&lt;br /&gt;
No Debian o '''THP''' vem habilitado como '''always''' e o '''unbound''' por trabalhar bastante com alterações do cache em memória, isso pode acabar causando um consumo crescente de uso de RAM sem necessidade. É uma boa prática desabilitá-lo com os passos abaixo:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/systemd/system/disable-thp.service&lt;br /&gt;
 [Unit]&lt;br /&gt;
 Description=Desativa Transparent Huge Pages (THP)&lt;br /&gt;
 After=network.target&lt;br /&gt;
 &lt;br /&gt;
 [Service]&lt;br /&gt;
 Type=oneshot&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled&amp;quot;&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/defrag&amp;quot;&lt;br /&gt;
 RemainAfterExit=yes&lt;br /&gt;
 &lt;br /&gt;
 [Install]&lt;br /&gt;
 WantedBy=multi-user.target&lt;br /&gt;
 EOF&lt;br /&gt;
Acima configuramos o serviço '''disable-thp.service''' para desabilitar o '''THP''' e abaixo habilitamos no '''systemd''' e iniciamos:&lt;br /&gt;
 # systemctl daemon-reload&lt;br /&gt;
 # systemctl enable --now disable-thp&lt;br /&gt;
&lt;br /&gt;
== Preparando o monitoramento do seu DNS Recursivo ==&lt;br /&gt;
O monitoramento do seu DNS Recursivo é muito importante e para isso vamos usar um '''template para Zabbix''', que modifiquei juntamente com o seu shell script e que enviará os dados para o seu Zabbix server via '''zabbix-sender'''. O projeto original está aqui '''https://github.com/jeftedelima/Unbound-DNS&amp;lt;nowiki/&amp;gt;.''' O xml alterado está aqui '''https://github.com/gondimcodes/template_zabbix_dns_unbound'''. Embora seja antigo é perfeitamente importável no Zabbix 6.0, por exemplo.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;nowiki/&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Teremos um shell script que você precisará colocar no seu '''/etc/crontab'''. No exemplo abaixo assumi que o shell script está em '''/root/scripts'''. De 5 em 5 minutos os dados serão enviados para o seu Zabbix server.&lt;br /&gt;
 */5 * * * *     root    /root/scripts/unboundSend.sh '''IP_zabbix_server''' '''nome_do_host''' 1&amp;gt; /dev/null&lt;br /&gt;
Na linha acima, troque o '''IP_zabbix_server''' pelo '''IP do seu servidor Zabbix''' e o '''nome_do_host''' pelo '''hostname''' '''do seu DNS Recursivo'''. Você precisará instalar o pacote '''zabbix-sender''' no seu DNS Recursivo pois ele será usado para enviar os dados para o Zabbix server.&lt;br /&gt;
&lt;br /&gt;
Abaixo o '''unboundSend.sh''' também alterado com inclusão de mais dados:&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 #       @Jefte de Lima Ferreira&lt;br /&gt;
 #       jeftedelima at gmail dot com&lt;br /&gt;
 #       CRON Example&lt;br /&gt;
 #       Contributor: Marcelo Gondim - gondim at gmail dot com&lt;br /&gt;
 #       */5   **** root sh /home/dir/unboundSend.sh 192.168.10.1 Unbound 1&amp;gt; /dev/null&lt;br /&gt;
 &lt;br /&gt;
 if [ -z ${1} ] || [ -z ${2} ] ; then&lt;br /&gt;
         echo &amp;quot;You need to specify the IP address of zabbix server and hostname of your DNS Unbound on zabbix&amp;quot;&lt;br /&gt;
         echo &amp;quot;Usage example: ./unboundSend.sh 192.168.10.1 UnboundServer&amp;quot;&lt;br /&gt;
         exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
 # ZABBIX_SERVER IP&lt;br /&gt;
 IP_ZABBIX=$1&lt;br /&gt;
 # NAME Unbound on Zabbix&lt;br /&gt;
 NAME_HOST=$2&lt;br /&gt;
 DIR_TEMP=/var/tmp/&lt;br /&gt;
 FILE=&amp;quot;${DIR_TEMP}dump_unbound_control_stats.txt&amp;quot;&lt;br /&gt;
 unbound-control stats &amp;gt; ${FILE}&lt;br /&gt;
 &lt;br /&gt;
 TOTAL_NUM_QUERIES=$(cat ${FILE} | grep -w 'total.num.queries' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEHITS=$(cat ${FILE} | grep -w 'total.num.cachehits' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEMISS=$(cat ${FILE} | grep -w 'total.num.cachemiss' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_PREFETCH=$(cat ${FILE} | grep -w 'total.num.prefetch' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_RECURSIVEREPLIES=$(cat ${FILE} | grep -w 'total.num.recursivereplies' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 TOTAL_REQ_MAX=$(cat ${FILE} | grep -w 'total.requestlist.max' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_AVG=$(cat ${FILE} | grep -w 'total.requestlist.avg' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_OVERWRITTEN=$(cat ${FILE} | grep -w 'total.requestlist.overwritten' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_EXCEEDED=$(cat ${FILE} | grep -w 'total.requestlist.exceeded' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_ALL=$(cat ${FILE} | grep -w 'total.requestlist.current.all' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_USER=$(cat ${FILE} | grep -w 'total.requestlist.current.user' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 TOTAL_TCPUSAGE=$(cat ${FILE} | grep -w 'total.tcpusage' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 NUM_QUERY_TYPE_A=$(cat ${FILE} | grep -w 'num.query.type.A' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NS=$(cat ${FILE} | grep -w 'num.query.type.NS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_MX=$(cat ${FILE} | grep -w 'num.query.type.MX' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TXT=$(cat ${FILE} | grep -w 'num.query.type.TXT' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_PTR=$(cat ${FILE} | grep -w 'num.query.type.PTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_AAAA=$(cat ${FILE} | grep -w 'num.query.type.AAAA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SRV=$(cat ${FILE} | grep -w 'num.query.type.SRV' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SOA=$(cat ${FILE} | grep -w 'num.query.type.SOA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HTTPS=$(cat ${FILE} | grep -w 'num.query.type.HTTPS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TYPE0=$(cat ${FILE} | grep -w 'num.query.type.TYPE0' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_CNAME=$(cat ${FILE} | grep -w 'num.query.type.CNAME' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_WKS=$(cat ${FILE} | grep -w 'num.query.type.WKS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HINFO=$(cat ${FILE} | grep -w 'num.query.type.HINFO' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_X25=$(cat ${FILE} | grep -w 'num.query.type.X25' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NAPTR=$(cat ${FILE} | grep -w 'num.query.type.NAPTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DS=$(cat ${FILE} | grep -w 'num.query.type.DS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DNSKEY=$(cat ${FILE} | grep -w 'num.query.type.DNSKEY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TLSA=$(cat ${FILE} | grep -w 'num.query.type.TLSA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SVCB=$(cat ${FILE} | grep -w 'num.query.type.SVCB' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SPF=$(cat ${FILE} | grep -w 'num.query.type.SPF' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_ANY=$(cat ${FILE} | grep -w 'num.query.type.ANY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_OTHER=$(cat ${FILE} | grep -w 'num.query.type.other' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 NUM_ANSWER_RCODE_NOERROR=$(cat ${FILE} | grep -w 'num.answer.rcode.NOERROR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_NXDOMAIN=$(cat ${FILE} | grep -w 'num.answer.rcode.NXDOMAIN' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_SERVFAIL=$(cat ${FILE} | grep -w 'num.answer.rcode.SERVFAIL' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_REFUSED=$(cat ${FILE} | grep -w 'num.answer.rcode.REFUSED' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_nodata=$(cat ${FILE} | grep -w 'num.answer.rcode.nodata' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_secure=$(cat ${FILE} | grep -w 'num.answer.secure' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 #       Sending info to zabbix_server, if variables is not empty!&lt;br /&gt;
 [ -z ${TOTAL_NUM_QUERIES} ] ||  zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.queries -o $((TOTAL_NUM_QUERIES/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_CACHEHITS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachehits -o $((TOTAL_NUM_CACHEHITS/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_CACHEMISS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachemiss -o $((TOTAL_NUM_CACHEMISS/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_PREFETCH} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.prefetch -o $((TOTAL_NUM_PREFETCH/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_RECURSIVEREPLIES} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.recursivereplies -o $((TOTAL_NUM_RECURSIVEREPLIES/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${TOTAL_REQ_MAX} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.max -o $((TOTAL_REQ_MAX/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_AVG} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.avg -o $((TOTAL_REQ_AVG/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_OVERWRITTEN} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.overwritten -o $((TOTAL_REQ_OVERWRITTEN/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_EXCEEDED} ] ||  zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.exceeded -o $((TOTAL_REQ_EXCEEDED/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_CURRENT_ALL} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.all -o $((TOTAL_REQ_CURRENT_ALL/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_CURRENT_USER} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.user -o $((TOTAL_REQ_CURRENT_USER/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${TOTAL_TCPUSAGE} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.tcpusage -o $((TOTAL_TCPUSAGE/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_A} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.a -o $((NUM_QUERY_TYPE_A/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_NS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ns -o $((NUM_QUERY_TYPE_NS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_MX} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.mx -o $((NUM_QUERY_TYPE_MX/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_TXT} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.txt -o $((NUM_QUERY_TYPE_TXT/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_PTR} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ptr -o $((NUM_QUERY_TYPE_PTR/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_AAAA} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.aaaa -o $((NUM_QUERY_TYPE_AAAA/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SRV} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.srv -o $((NUM_QUERY_TYPE_SRV/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SOA} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.soa -o $((NUM_QUERY_TYPE_SOA/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_HTTPS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.https -o $((NUM_QUERY_TYPE_HTTPS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_TYPE0} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.type0 -o $((NUM_QUERY_TYPE_TYPE0/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_CNAME} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.cname -o $((NUM_QUERY_TYPE_CNAME/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_WKS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.wks -o $((NUM_QUERY_TYPE_WKS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_HINFO} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.hinfo -o $((NUM_QUERY_TYPE_HINFO/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_X25} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.X25 -o $((NUM_QUERY_TYPE_X25/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_NAPTR} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.naptr -o $((NUM_QUERY_TYPE_NAPTR/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_DS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ds -o $((NUM_QUERY_TYPE_DS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_DNSKEY} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.dnskey -o $((NUM_QUERY_TYPE_DNSKEY/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_TLSA} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.tlsa -o $((NUM_QUERY_TYPE_TLSA/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SVCB} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.svcb -o $((NUM_QUERY_TYPE_SVCB/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SPF} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.spf -o $((NUM_QUERY_TYPE_SPF/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_ANY} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.any -o $((NUM_QUERY_TYPE_ANY/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_OTHER} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.other -o $((NUM_QUERY_TYPE_OTHER/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_NOERROR} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NOERROR -o $((NUM_ANSWER_RCODE_NOERROR/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_NXDOMAIN} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NXDOMAIN -o $((NUM_ANSWER_RCODE_NXDOMAIN/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_SERVFAIL} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.SERVFAIL -o $((NUM_ANSWER_RCODE_SERVFAIL/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_REFUSED} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.REFUSED -o $((NUM_ANSWER_RCODE_REFUSED/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_nodata} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.nodata -o $((NUM_ANSWER_RCODE_nodata/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_secure} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.secure -o $((NUM_ANSWER_secure/300))&lt;br /&gt;
No Zabbix será registrado dados como esses abaixo e posteriormente pode ser montado um Grafana com eles:&lt;br /&gt;
[[Arquivo:Zabbix dns01.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns02.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns03.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns04.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Mantendo a hora certa ==&lt;br /&gt;
Vamos instalar agora o Chrony para manter a data e hora certas no sistema:&lt;br /&gt;
 # apt install chrony&lt;br /&gt;
Após a instalação do Chrony edite o arquivo /etc/chrony/chrony.conf, comente e a linha abaixo e adicione seus servidores NTP. Caso não tenha servidores NTP, estou colocando os do NIC.br aqui.&lt;br /&gt;
 #pool 2.debian.pool.ntp.org iburst&lt;br /&gt;
 server a.st1.ntp.br iburst nts&lt;br /&gt;
 server b.st1.ntp.br iburst nts&lt;br /&gt;
 server c.st1.ntp.br iburst nts&lt;br /&gt;
 server d.st1.ntp.br iburst nts&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart chronyd.service&lt;br /&gt;
Cheque com o '''chronyc''' se os servidores estão OK:&lt;br /&gt;
 # chronyc sourcestats&lt;br /&gt;
 Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev&lt;br /&gt;
 ==============================================================================&lt;br /&gt;
 a.st1.ntp.br               10   5  155m     -0.027      0.030    -71us    51us&lt;br /&gt;
 b.st1.ntp.br               11   7  344m     +0.068      0.079    +23ms   382us&lt;br /&gt;
 c.st1.ntp.br                6   3  344m     +0.026      0.037   -124us    92us&lt;br /&gt;
 200.20.186.76               9   3  138m     -0.022      0.031   +172us    42us&lt;br /&gt;
&lt;br /&gt;
 # chronyc sources&lt;br /&gt;
 MS Name/IP address         Stratum Poll Reach LastRx Last sample&lt;br /&gt;
 ===============================================================================&lt;br /&gt;
 ^* a.st1.ntp.br                  1  10   377   588   +487us[ +397us] +/-   12ms&lt;br /&gt;
 ^- b.st1.ntp.br                  2  10   377   830    +23ms[  +23ms] +/-   49ms&lt;br /&gt;
 ^+ c.st1.ntp.br                  2  10    21  1038   -147us[ -242us] +/-   17ms&lt;br /&gt;
 ^+ 200.20.186.76                 1  10   377  1032   +381us[ +285us] +/-   15ms&lt;br /&gt;
&lt;br /&gt;
== Configurando o FRRouting ==&lt;br /&gt;
Nesse ponto iremos configurar o '''FRRouting''' para enviar os IPs das '''loopbacks''' e o '''/30''' para o nosso PE do diagrama. Em '''/etc/frr/daemons''' habilite o parâmetro conforme abaixo:&lt;br /&gt;
 ospfd=yes&lt;br /&gt;
Edite o arquivo '''/etc/frr/frr.conf''' e deixe com o conteúdo abaixo, para ficar conforme nosso diagrama do projeto. Apenas troque '''&amp;lt;SENHA&amp;gt;''' por uma senha para fechar o OSPF com mais segurança. Essa senha deve ser usada dos dois lados.&lt;br /&gt;
 frr version 10.2.1&lt;br /&gt;
 frr defaults traditional&lt;br /&gt;
 hostname dns-recursivo-01&lt;br /&gt;
 log syslog informational&lt;br /&gt;
 no ip forwarding&lt;br /&gt;
 no ipv6 forwarding&lt;br /&gt;
 service integrated-vtysh-config&lt;br /&gt;
 !&lt;br /&gt;
 interface ens18&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf message-digest-key 5 md5 &amp;lt;SENHA&amp;gt;&lt;br /&gt;
  ip ospf network point-to-point&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 network point-to-point&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 interface lo&lt;br /&gt;
  description LOOPBACKS&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf passive&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 passive&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf&lt;br /&gt;
  ospf router-id 172.16.0.6&lt;br /&gt;
  area 0.0.0.0 authentication message-digest&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf6&lt;br /&gt;
  ospf6 router-id 172.16.0.6&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart frr.service&lt;br /&gt;
Cheque se está tudo OK com o OSPF e verifique no PE se está recebendo os prefixos anunciados.&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL&lt;br /&gt;
 172.16.0.5     1 Full/-          10m49s            35.310s 172.16.0.5   ens18:172.16.0.6                  0     0     0&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri    DeadTime    State/IfState         Duration I/F[State]&lt;br /&gt;
 172.16.0.5       1    00:00:30     Full/PointToPoint 25d22:53:47 ens18[PointToPoint]&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor detail'&lt;br /&gt;
 &lt;br /&gt;
  Neighbor 172.16.0.5, interface address 172.16.0.5&lt;br /&gt;
     In the area 0.0.0.0 via interface ens18&lt;br /&gt;
     Neighbor priority is 1, State is Full/-, 5 state changes&lt;br /&gt;
     Most recent state change statistics:&lt;br /&gt;
       Progressive change 21w3d15h ago&lt;br /&gt;
     DR is 0.0.0.0, BDR is 0.0.0.0&lt;br /&gt;
     Options 18 *|-|-|EA|-|-|E|-&lt;br /&gt;
     Dead timer due in 34.685s&lt;br /&gt;
     Database Summary List 0&lt;br /&gt;
     Link State Request List 0&lt;br /&gt;
     Link State Retransmission List 0&lt;br /&gt;
     Thread Inactivity Timer on&lt;br /&gt;
     Thread Database Description Retransmision off&lt;br /&gt;
     Thread Link State Request Retransmission on&lt;br /&gt;
     Thread Link State Update Retransmission on&lt;br /&gt;
 &lt;br /&gt;
     Graceful restart Helper info:&lt;br /&gt;
       Graceful Restart HELPER Status : None&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor detail'&lt;br /&gt;
  Neighbor 172.16.0.5%ens18&lt;br /&gt;
     Area 0.0.0.0 via interface ens18 (ifindex 4)&lt;br /&gt;
     His IfIndex: 60 Link-local address: fe80::469b:c1ff:fed6:43ee&lt;br /&gt;
     State Full for a duration of 25d22:57:14&lt;br /&gt;
     His choice of DR/BDR 0.0.0.0/0.0.0.0, Priority 1&lt;br /&gt;
     DbDesc status: Master SeqNum: 0xb94b0000&lt;br /&gt;
     Summary-List: 0 LSAs&lt;br /&gt;
     Request-List: 0 LSAs&lt;br /&gt;
     Retrans-List: 0 LSAs&lt;br /&gt;
     0 Pending LSAs for DbDesc in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSReq in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSAck in Time 00:00:00 [thread off]&lt;br /&gt;
     Authentication header not present&lt;br /&gt;
&lt;br /&gt;
== Configurando o Unbound ==&lt;br /&gt;
Abaixo a configuração que usaremos nos servidores atentando para o detalhe do '''num-threads''', esse deve ter o valor igual ao número de CPUs do servidor.&lt;br /&gt;
&lt;br /&gt;
Também os IPs utilizados em '''outgoing-interface''' que serão diferentes em cada servidor, esses serão os IPs usados para '''recursividade'''. Consulte o manual do Unbound para obter mais informações sobre cada parâmetro listado na configuração.&lt;br /&gt;
&lt;br /&gt;
O tuning no Unbound pode ser alterado conforme abaixo:&lt;br /&gt;
 num-threads = nº CPUs&lt;br /&gt;
 so-reuseport = yes&lt;br /&gt;
 *-slabs = potência de 2 próximo ao num-threads&lt;br /&gt;
 msg-cache-size = 1g (quantidade de memória pra usar de cache)&lt;br /&gt;
 rrset-cache-size = 2 * msg-cache-size&lt;br /&gt;
 outgoing-range = 8192&lt;br /&gt;
 num-queries-per-thread = 4096&lt;br /&gt;
 so-rcvbuf e so-sndbuf = 4m ou 8m para servidores com muita requisição&lt;br /&gt;
Agora vamos criar nosso arquivo de configuração base em '''/etc/unbound/unbound.conf.d/local.conf''':&lt;br /&gt;
 server:&lt;br /&gt;
         verbosity: 1&lt;br /&gt;
         statistics-interval: 0&lt;br /&gt;
         statistics-cumulative: no&lt;br /&gt;
         extended-statistics: yes&lt;br /&gt;
         num-threads: 4&lt;br /&gt;
         serve-expired: yes&lt;br /&gt;
         interface: 127.0.0.1&lt;br /&gt;
         interface: 10.10.10.10&lt;br /&gt;
         interface: 10.10.9.9&lt;br /&gt;
         interface: 172.16.0.6&lt;br /&gt;
         interface: fc00::10:10:10:10&lt;br /&gt;
         interface: fc00::10:10:9:9&lt;br /&gt;
         interface: ::1&lt;br /&gt;
         interface-automatic: no&lt;br /&gt;
         outgoing-interface: 198.18.1.10&lt;br /&gt;
         outgoing-interface: 2001:db8::faca:198:18:1:10&lt;br /&gt;
         outgoing-range: 8192&lt;br /&gt;
         outgoing-num-tcp: 1024&lt;br /&gt;
         incoming-num-tcp: 2048&lt;br /&gt;
         so-rcvbuf: 4m&lt;br /&gt;
         so-sndbuf: 4m&lt;br /&gt;
         so-reuseport: yes&lt;br /&gt;
         edns-buffer-size: 1232&lt;br /&gt;
         msg-cache-size: 1g&lt;br /&gt;
         msg-cache-slabs: 4&lt;br /&gt;
         num-queries-per-thread: 4096&lt;br /&gt;
         rrset-cache-size: 2g&lt;br /&gt;
         rrset-cache-slabs: 4&lt;br /&gt;
         infra-cache-slabs: 4&lt;br /&gt;
         do-ip4: yes&lt;br /&gt;
         do-ip6: yes&lt;br /&gt;
         do-udp: yes&lt;br /&gt;
         do-tcp: yes&lt;br /&gt;
         chroot: &amp;quot;&amp;quot;&lt;br /&gt;
         username: &amp;quot;unbound&amp;quot;&lt;br /&gt;
         directory: &amp;quot;/etc/unbound&amp;quot;&lt;br /&gt;
         logfile: &amp;quot;/var/log/unbound/unbound.log&amp;quot;&lt;br /&gt;
         use-syslog: no&lt;br /&gt;
         log-time-ascii: yes&lt;br /&gt;
         log-queries: no&lt;br /&gt;
         pidfile: &amp;quot;/var/run/unbound.pid&amp;quot;&lt;br /&gt;
         root-hints: &amp;quot;/usr/share/dns/root.hints&amp;quot;&lt;br /&gt;
         hide-identity: yes&lt;br /&gt;
         hide-version: yes&lt;br /&gt;
         unwanted-reply-threshold: 10000000&lt;br /&gt;
         prefetch: yes&lt;br /&gt;
         prefetch-key: yes&lt;br /&gt;
         rrset-roundrobin: yes&lt;br /&gt;
         minimal-responses: yes&lt;br /&gt;
         module-config: &amp;quot;respip validator iterator&amp;quot;&lt;br /&gt;
         val-clean-additional: yes&lt;br /&gt;
         val-log-level: 1&lt;br /&gt;
         key-cache-slabs: 4&lt;br /&gt;
         deny-any: yes&lt;br /&gt;
         cache-min-ttl: 60&lt;br /&gt;
         key-cache-size: 128m&lt;br /&gt;
         neg-cache-size: 64m&lt;br /&gt;
         cache-max-ttl: 86400&lt;br /&gt;
         infra-cache-numhosts: 100000&lt;br /&gt;
         access-control: 198.18.0.0/22 allow&lt;br /&gt;
         access-control: 2001:db8::/32 allow&lt;br /&gt;
  &lt;br /&gt;
 rpz:&lt;br /&gt;
   name: rpz.block.host.local.zone&lt;br /&gt;
   zonefile: /etc/unbound/rpz.block.hosts.zone&lt;br /&gt;
   rpz-action-override: nxdomain&lt;br /&gt;
  &lt;br /&gt;
 python:&lt;br /&gt;
  &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;.&amp;quot;&lt;br /&gt;
     master: &amp;quot;b.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;c.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;d.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;f.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;g.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;k.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/root.zone&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;arpa.&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/arpa.zone&amp;quot;&lt;br /&gt;
No parâmetro '''interface''' colocamos os IPs que serão usados para consulta dos clientes como o '''10.10.10.10''', '''10.10.9.9, fc00::10:10:10:10 e fc00::10:10:9:9'''. Ali repare que coloquei também o IP privado '''172.16.0.6''', isso porque cada servidor terá o seu IP privado e este deve ser usado pelo seu sistema de monitoramento para checar cada servidor. No '''outgoing-interface''' teremos os IPs, tanto '''IPv4''' quanto '''IPv6''', para que seja feita a recursividade na Internet utilizando eles. Não tem '''IPv6''' ainda na sua rede? Dê uma olhada nesse artigo. Outro parâmetro importante é o '''access-control''' e é através dele que liberamos os prefixos IP para consultarem no nosso DNS Recursivo. No exemplo estou liberando todo o prefixo '''198.18.0.0/22''' e o prefixo '''2001:db8::/32'''. Além da ACL no Unbound, recomendo que crie um filtro de pacotes com iptables ou nftables protegendo seu sistema e liberando as portas '''53/UDP''', '''53/TCP,'''  '''443/TCP e 853/TCP''' apenas para seus clientes. Falarei sobre a '''443/TCP e 853/TCP''' mais para frente nessa mesma documentação.&lt;br /&gt;
&lt;br /&gt;
Agora criaremos o arquivo '''RPZ''' ('''Response Policy Zones'''). Esse arquivo contém os sites que serão bloqueados via '''&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; Recursivo'''. São aqueles sites que às vezes você recebe um Ofício da Justiça solicitando o bloqueio deles. Não entrarei no mérito da efetividade desses bloqueios, porque muitos de vocês sabem que tecnicamente, existem formas de se fazer um bypass através desses bloqueios. Contudo vamos deixar nosso ambiente preparado para esses bloqueios e por isso crie o arquivo '''/etc/unbound/rpz.block.hosts.zone''' com esse conteúdo de exemplo:&lt;br /&gt;
 $TTL 2h&lt;br /&gt;
 @ IN SOA localhost. root.localhost. (2 6h 1h 1w 2h)&lt;br /&gt;
   IN NS  localhost.&lt;br /&gt;
 ; RPZ manual block hosts&lt;br /&gt;
 *.josedascoves.com CNAME .&lt;br /&gt;
 josedascoves.com CNAME .&lt;br /&gt;
No exemplo acima estamos bloqueando qualquer consulta de DNS para '''josedascoves.com''' ou qualquer coisa '''.josedascoves.com'''.&lt;br /&gt;
&lt;br /&gt;
Para testar podemos fazer assim do próprio servidor:&lt;br /&gt;
 # host josedascoves.com ::1&lt;br /&gt;
 Using domain server:&lt;br /&gt;
 Name: ::1&lt;br /&gt;
 Address: ::1#53&lt;br /&gt;
 Aliases:&lt;br /&gt;
 &lt;br /&gt;
 Host josedascoves.com not found: 3(NXDOMAIN)&lt;br /&gt;
Se a resposta for '''NXDOMAIN''' então está funcionando o bloqueio. Para incluir novos bloqueios basta adicionar os domínios, um abaixo do outro, conforme o exemplo que coloquei no arquivo RPZ.&lt;br /&gt;
&lt;br /&gt;
== Acertando o resolv.conf ==&lt;br /&gt;
Vamos modificar nosso /etc/resolv.conf para utilizar DNS externo. Sim você deve estar se perguntando em qual situação isso seria utilizado. Primeiro entenda que o Unbound não irá utilizar o DNS externo para fazer as consultas na Internet e sim, qualquer teste que você faça do servidor precisará apontar para o Unbound usando os IPs '''127.0.0.1''' ou '''::1'''. Faremos isso pela seguinte situação: imagine que o daemon unbound morreu mas você ainda continua com conectividade na Internet. Você conseguiria acessar qualquer local na Internet através do IP mas não através do hostname porque não conseguiria resolver nomes, seu unbound estaria fora do ar. Imagine ainda que você gostaria que seu servidor te avisasse do problema via Telegram ou e-mail. Por isso estamos utilizando um DNS externo no '''/etc/resolv.conf''', apenas para essas situações. Se você não quiser utilizar desse recurso, pode usar o '''127.0.0.1''' e '''::1''' no lugar.&lt;br /&gt;
 nameserver 8.8.8.8&lt;br /&gt;
 nameserver 8.8.4.4&lt;br /&gt;
 nameserver 2001:4860:4860::8888&lt;br /&gt;
&lt;br /&gt;
== Script de teste de recursividade ==&lt;br /&gt;
Estamos montando uma '''Rede de DNS Recursivo Anycast''', então é muito importante que você monitore essa rede para saber se algum node morreu e iniciar o troubleshooting, resolver o problema e levantar o sistema novamente. Tudo isso é importante mas o cliente não deve ficar esperando até você resolver o problema, seu sistema precisa ser inteligente o suficiente para se remover da Rede quando tiver um problema e se inserir novamente, quando o problema estiver sido solucionado. Se você montar uma Rede de DNS e um dos nodes apresentar algum problema, todos os clientes atendidos por aquele node migrarão automaticamente e transparentemente para outro '''DNS Recursivo Anycast''' mais próximo. Isso se chama '''disponibilidade'''.&lt;br /&gt;
&lt;br /&gt;
O script '''/root/scripts/checa_dns.sh''' abaixo tem a função de fazer os testes de recursividade e checar se o daemon do unbound continua rodando. Se algo acontecer, ele para o anúncio do '''10.10.10.10''' e '''10.10.9.9''' e retorna eles quando tudo estiver resolvido.&lt;br /&gt;
 # mkdir /root/scripts&lt;br /&gt;
&lt;br /&gt;
 #!/usr/bin/env bash&lt;br /&gt;
 #Script para teste de DNS v2.1&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 #Informe um domínio por linha:&lt;br /&gt;
 dominios_testar=(&lt;br /&gt;
 www.google.com&lt;br /&gt;
 www.terra.com.br&lt;br /&gt;
 www.uol.com.br&lt;br /&gt;
 www.globo.com&lt;br /&gt;
 www.facebook.com&lt;br /&gt;
 www.youtube.com&lt;br /&gt;
 www.twitch.com&lt;br /&gt;
 www.discord.com&lt;br /&gt;
 www.debian.org&lt;br /&gt;
 www.redhat.com&lt;br /&gt;
 )&lt;br /&gt;
 corte_taxa_falha=100 #Porcentagem de falha para executar uma ação&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 remove_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; != &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no description' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME morreu!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 adiciona_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; == &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'description LOOPBACKS' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME retornou do inferno!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
 if [ $? -ne 0 ]; then&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME morreu DNS mas tentando levantar!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    systemctl restart unbound&lt;br /&gt;
    systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
    if [ $? -ne 0 ]; then&lt;br /&gt;
       remove_ospf&lt;br /&gt;
       exit&lt;br /&gt;
    fi&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME servico DNS voltou mas tinha morrido!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 qt_falhas=0&lt;br /&gt;
 qt_total=&amp;quot;${#dominios_testar[@]}&amp;quot;&lt;br /&gt;
 echo &amp;quot;total_dominios: $qt_total&amp;quot;&lt;br /&gt;
 for site in &amp;quot;${dominios_testar[@]}&amp;quot;&lt;br /&gt;
 do&lt;br /&gt;
   unbound-control flush $site &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   resolver=&amp;quot;127.0.0.1&amp;quot;&lt;br /&gt;
   echo -e &amp;quot; - dominio $site - $resolver - \c&amp;quot;&lt;br /&gt;
   host $site $resolver &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   if [ $? -ne 0 ]; then&lt;br /&gt;
      ((qt_falhas++))&lt;br /&gt;
      echo -e &amp;quot;[Falhou]&amp;quot;&lt;br /&gt;
   else&lt;br /&gt;
      echo -e &amp;quot;[OK]&amp;quot;&lt;br /&gt;
   fi&lt;br /&gt;
 done&lt;br /&gt;
  &lt;br /&gt;
 taxa_falha=$((qt_falhas*100/qt_total))&lt;br /&gt;
 echo &amp;quot;Falhas $qt_falhas/$qt_total ($taxa_falha%)&amp;quot;&lt;br /&gt;
  &lt;br /&gt;
 if [ &amp;quot;$taxa_falha&amp;quot; -ge &amp;quot;$corte_taxa_falha&amp;quot; ]; then&lt;br /&gt;
    remove_ospf&lt;br /&gt;
    exit&lt;br /&gt;
 fi&lt;br /&gt;
 adiciona_ospf&lt;br /&gt;
Se rodarmos o script manualmente veremos isto:&lt;br /&gt;
 # /root/scripts/checa_dns.sh&lt;br /&gt;
 total_dominios: 10&lt;br /&gt;
  - dominio www.google.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.terra.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.uol.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.globo.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.facebook.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.youtube.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.twitch.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.discord.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.debian.org - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.redhat.com - 127.0.0.1 - [OK]&lt;br /&gt;
 Falhas 0/10 (0%)&lt;br /&gt;
Se acontecer 100% de falhas o script irá remover os anúncios do OSPF. Se o daemon do unbound morrer, ele tentará reiniciá-lo. Se tudo normalizar o script irá retornar os anúncios para o OSPF. Deixei comentado no script as partes que enviariam uma notificação para o Telegram. Existem diversas documentações sobre isso na Internet, eu mesmo tenho uma. Assim que eu publicar aqui, atualizo essa documentação e sinta-se à vontade de modificar como desejar.&lt;br /&gt;
 # chmod 700 /root/scripts/checa_dns.sh&lt;br /&gt;
Adicione a linha abaixo em seu '''/etc/crontab''':&lt;br /&gt;
 */1 *   * * *   root    /root/scripts/checa_dns.sh&lt;br /&gt;
&lt;br /&gt;
== Habilitando o DoH (&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; over HTTPS) e DoT (DNS over TLS) - opcional ==&lt;br /&gt;
Para habilitar o '''DoH''' e o '''DoT''' no Unbound é bem simples. O recurso do '''DoH''' e '''DoT''' vem para trazer mais segurança e privacidade para o usuário. É um recurso muito pouco utilizado ainda mas que seu cliente pode vir a pedir algum dia.&lt;br /&gt;
&lt;br /&gt;
Você precisará gerar certificados SSL legítimos e para isso você poderá usar o '''Let's Encrypt''' só que de uma forma não tão convencional.&lt;br /&gt;
&lt;br /&gt;
Na sequência vamos instalar o Let's Encrypt para gerarmos nosso certificado SSL:&lt;br /&gt;
 # apt install letsencrypt&lt;br /&gt;
Escolha um '''hostname''' para ser usado no nosso '''DoH''' e aponte ele no seu DNS Autoritativo para seus IPs 10.10.10.10 e 10.10.9.9. Aqui vamos usar o seguinte como exemplo: '''doh.brasilpeeringforum.org'''. Para gerarmos nosso certificado iremos usar o tipo '''DNS-01''', ele não necessita que tenhamos um servidor web rodando no servidor e nem tão pouco levanta um serviço na porta 80 para checar o hostname. Ele utiliza o DNS como validador e vai te solicitar que crie um registro '''CNAME''' no seu '''DNS Autoritativo''' para provar que você tem o controle sobre aquele hostname. Antes disso vamos instalar um programa em Python para podermos automatizar nossa renovação de certificado no futuro. Esse programa se encontra '''[https://github.com/joohoi/acme-dns-certbot-joohoi/raw/master/acme-dns-auth.py aqui]''' mas vou deixá-lo abaixo já modificado o interpretador.&lt;br /&gt;
&lt;br /&gt;
Crie o arquivo '''/etc/letsencrypt/acme-dns-auth.py''' com o conteúdo abaixo:&lt;br /&gt;
 #!/usr/bin/env python3&lt;br /&gt;
 import json&lt;br /&gt;
 import os&lt;br /&gt;
 import requests&lt;br /&gt;
 import sys&lt;br /&gt;
 &lt;br /&gt;
 ### EDIT THESE: Configuration values ###&lt;br /&gt;
 &lt;br /&gt;
 # URL to acme-dns instance&lt;br /&gt;
 ACMEDNS_URL = &amp;quot;&amp;lt;nowiki&amp;gt;https://auth.acme-dns.io&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
 # Path for acme-dns credential storage&lt;br /&gt;
 STORAGE_PATH = &amp;quot;/etc/letsencrypt/acmedns.json&amp;quot;&lt;br /&gt;
 # Whitelist for address ranges to allow the updates from&lt;br /&gt;
 # Example: ALLOW_FROM = [&amp;quot;192.168.10.0/24&amp;quot;, &amp;quot;::1/128&amp;quot;]&lt;br /&gt;
 ALLOW_FROM = []&lt;br /&gt;
 # Force re-registration. Overwrites the already existing acme-dns accounts.&lt;br /&gt;
 FORCE_REGISTER = False&lt;br /&gt;
 &lt;br /&gt;
 ###   DO NOT EDIT BELOW THIS POINT   ###&lt;br /&gt;
 ###         HERE BE DRAGONS          ###&lt;br /&gt;
 &lt;br /&gt;
 DOMAIN = os.environ[&amp;quot;CERTBOT_DOMAIN&amp;quot;]&lt;br /&gt;
 if DOMAIN.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
     DOMAIN = DOMAIN[2:]&lt;br /&gt;
 VALIDATION_DOMAIN = &amp;quot;_acme-challenge.&amp;quot;+DOMAIN&lt;br /&gt;
 VALIDATION_TOKEN = os.environ[&amp;quot;CERTBOT_VALIDATION&amp;quot;]&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 class AcmeDnsClient(object):&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
     Handles the communication with ACME-DNS API&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
     def __init__(self, acmedns_url):&lt;br /&gt;
         self.acmedns_url = acmedns_url&lt;br /&gt;
 &lt;br /&gt;
     def register_account(self, allowfrom):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Registers a new ACME-DNS account&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
         if allowfrom:&lt;br /&gt;
             # Include whitelisted networks to the registration call&lt;br /&gt;
             reg_data = {&amp;quot;allowfrom&amp;quot;: allowfrom}&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;,&lt;br /&gt;
                                 data=json.dumps(reg_data))&lt;br /&gt;
         else:&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;)&lt;br /&gt;
         if res.status_code == 201:&lt;br /&gt;
             # The request was successful&lt;br /&gt;
             return res.json()&lt;br /&gt;
         else:&lt;br /&gt;
             # Encountered an error&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to register a new acme-dns &amp;quot;&lt;br /&gt;
                    &amp;quot;account. HTTP status {}, Response body: {}&amp;quot;)&lt;br /&gt;
             print(msg.format(res.status_code, res.text))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def update_txt_record(self, account, txt):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Updates the TXT challenge record to ACME-DNS subdomain.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         update = {&amp;quot;subdomain&amp;quot;: account['subdomain'], &amp;quot;txt&amp;quot;: txt}&lt;br /&gt;
         headers = {&amp;quot;X-Api-User&amp;quot;: account['username'],&lt;br /&gt;
                    &amp;quot;X-Api-Key&amp;quot;: account['password'],&lt;br /&gt;
                    &amp;quot;Content-Type&amp;quot;: &amp;quot;application/json&amp;quot;}&lt;br /&gt;
         res = requests.post(self.acmedns_url+&amp;quot;/update&amp;quot;,&lt;br /&gt;
                             headers=headers,&lt;br /&gt;
                             data=json.dumps(update))&lt;br /&gt;
         if res.status_code == 200:&lt;br /&gt;
             # Successful update&lt;br /&gt;
             return&lt;br /&gt;
         else:&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to update TXT record in &amp;quot;&lt;br /&gt;
                    &amp;quot;acme-dns. \n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request headers:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request body:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response HTTP status: {}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response body: {}&amp;quot;)&lt;br /&gt;
             s_headers = json.dumps(headers, indent=2, sort_keys=True)&lt;br /&gt;
             s_update = json.dumps(update, indent=2, sort_keys=True)&lt;br /&gt;
             s_body = json.dumps(res.json(), indent=2, sort_keys=True)&lt;br /&gt;
             print(msg.format(s_headers, s_update, res.status_code, s_body))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
 class Storage(object):&lt;br /&gt;
     def __init__(self, storagepath):&lt;br /&gt;
         self.storagepath = storagepath&lt;br /&gt;
         self._data = self.load()&lt;br /&gt;
 &lt;br /&gt;
     def load(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Reads the storage content from the disk to a dict structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         data = dict()&lt;br /&gt;
         filedata = &amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             with open(self.storagepath, 'r') as fh:&lt;br /&gt;
                 filedata = fh.read()&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             if os.path.isfile(self.storagepath):&lt;br /&gt;
                 # Only error out if file exists, but cannot be read&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage file exists but cannot be read&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         try:&lt;br /&gt;
             data = json.loads(filedata)&lt;br /&gt;
         except ValueError:&lt;br /&gt;
             if len(filedata) &amp;gt; 0:&lt;br /&gt;
                 # Storage file is corrupted&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage JSON is corrupted&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         return data&lt;br /&gt;
 &lt;br /&gt;
     def save(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Saves the storage content to disk&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         serialized = json.dumps(self._data)&lt;br /&gt;
         try:&lt;br /&gt;
             with os.fdopen(os.open(self.storagepath,&lt;br /&gt;
                                    os.O_WRONLY | os.O_CREAT, 0o600), 'w') as fh:&lt;br /&gt;
                 fh.truncate()&lt;br /&gt;
                 fh.write(serialized)&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             print(&amp;quot;ERROR: Could not write storage file.&amp;quot;)&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def put(self, key, value):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Puts the configuration value to storage and sanitize it&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         # If wildcard domain, remove the wildcard part as this will use the&lt;br /&gt;
         # same validation record name as the base domain&lt;br /&gt;
         if key.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
             key = key[2:]&lt;br /&gt;
         self._data[key] = value&lt;br /&gt;
 &lt;br /&gt;
     def fetch(self, key):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Gets configuration value from storage&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             return self._data[key]&lt;br /&gt;
         except KeyError:&lt;br /&gt;
             return None&lt;br /&gt;
 &lt;br /&gt;
 if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
     # Init&lt;br /&gt;
     client = AcmeDnsClient(ACMEDNS_URL)&lt;br /&gt;
     storage = Storage(STORAGE_PATH)&lt;br /&gt;
 &lt;br /&gt;
     # Check if an account already exists in storage&lt;br /&gt;
     account = storage.fetch(DOMAIN)&lt;br /&gt;
     if FORCE_REGISTER or not account:&lt;br /&gt;
         # Create and save the new account&lt;br /&gt;
         account = client.register_account(ALLOW_FROM)&lt;br /&gt;
         storage.put(DOMAIN, account)&lt;br /&gt;
         storage.save()&lt;br /&gt;
 &lt;br /&gt;
         # Display the notification for the user to update the main zone&lt;br /&gt;
         msg = &amp;quot;Please add the following CNAME record to your main DNS zone:\n{}&amp;quot;&lt;br /&gt;
         cname = &amp;quot;{} CNAME {}.&amp;quot;.format(VALIDATION_DOMAIN, account[&amp;quot;fulldomain&amp;quot;])&lt;br /&gt;
         print(msg.format(cname))&lt;br /&gt;
 &lt;br /&gt;
     # Update the TXT record in acme-dns instance&lt;br /&gt;
     client.update_txt_record(account, VALIDATION_TOKEN)&lt;br /&gt;
&lt;br /&gt;
 # chmod +x /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
Usaremos a seguinte instrução para criar nosso certificado:&lt;br /&gt;
 # certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d doh.brasilpeeringforum.org&lt;br /&gt;
 Saving debug log to /var/log/letsencrypt/letsencrypt.log&lt;br /&gt;
 Plugins selected: Authenticator manual, Installer None&lt;br /&gt;
 Cert is due for renewal, auto-renewing...&lt;br /&gt;
 Renewing an existing certificate for doh.brasilpeeringforum.org&lt;br /&gt;
 Performing the following challenges:&lt;br /&gt;
 dns-01 challenge for doh.brasilpeeringforum.org&lt;br /&gt;
 Running manual-auth-hook command: /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
 Output from manual-auth-hook command acme-dns-auth.py:&lt;br /&gt;
 Please add the following CNAME record to your main DNS zone:&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
 &lt;br /&gt;
 Waiting for verification...&lt;br /&gt;
 &lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Challenges loaded. Press continue to submit to CA. Pass &amp;quot;-v&amp;quot; for more info about&lt;br /&gt;
 challenges.&lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Press Enter to Continue&lt;br /&gt;
Nesse momento você cria o registro '''CNAME''' no seu DNS Autoritativo conforme ele solicitou: '''_acme-challenge.doh.brasilpeeringforum.org IN CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.''' e somente depois de criado e checado no DNS, você pressiona o '''Enter''' para continuar. Você pode checar dessa forma:&lt;br /&gt;
 # host -t cname _acme-challenge.doh.brasilpeeringforum.org&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org is an alias for b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
Para que nosso certificado seja automaticamente renovado colocaremos no '''/etc/crontab''' a seguinte linha abaixo:&lt;br /&gt;
 00 00   1 * *   root    /usr/bin/certbot -q renew&lt;br /&gt;
Acima temos a instrução para renovação automática do certificado. Repare que você vai precisar também copiar esse certificado para seus outros servidores, escolha um servidor para manter o certificado sempre atualizado e crie um script que faça a mesma cópia remotamente para os outros servidores. O '''scp''' e o '''rsync''' são seus aliados nisso.&lt;br /&gt;
&lt;br /&gt;
=== Configurando o Unbound ===&lt;br /&gt;
Em nosso '''/etc/unbound/unbound.conf.d/local.conf''', adicionaremos no bloco &amp;quot;'''server:'''&amp;quot; o seguinte:&lt;br /&gt;
 interface: 10.10.10.10@443 &lt;br /&gt;
 interface: 10.10.9.9@443&lt;br /&gt;
 interface: fc00::10:10:10:10@443&lt;br /&gt;
 interface: fc00::10:10:9:9@443&lt;br /&gt;
 interface: 10.10.10.10@853 &lt;br /&gt;
 interface: 10.10.9.9@853&lt;br /&gt;
 interface: fc00::10:10:10:10@853&lt;br /&gt;
 interface: fc00::10:10:9:9@853&lt;br /&gt;
 tls-service-key: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/privkey.pem&amp;quot; &lt;br /&gt;
 tls-service-pem: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/fullchain.pem&amp;quot;&lt;br /&gt;
Para usar o recurso do '''DoH''' você precisará habilitar o recurso no seu navegador e informar a URL. Vou colocar o exemplo do '''Google Chrome''': Digite '''chrome://settings/security?search=dns''' no seu Chrome e ative '''Usar DNS seguro''', selecione '''Personalizado''' e adicione nossa URL:&lt;br /&gt;
[[Arquivo:Doh bpf2.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Finalizando ==&lt;br /&gt;
Aqui finalizamos nosso projeto para uma Rede de DNS(s) Recursivos Anycast com Hyperlocal. Esse projeto é escalável, seguro, resiliente e você entregará muito mais qualidade de Internet para o seu cliente. Pare de entregar o '''8.8.8.8''' para os seus clientes, você está contribuindo para uma Internet mais lenta, sem a qualidade que o seu cliente merece. Investi meu tempo, que é muito pouco, para deixar esse documento para a comunidade, para você melhorar o seu ISP, para dar um UP! nele, então vamos começar 2023 com o pé direito. O que acha?&lt;br /&gt;
&lt;br /&gt;
Como prova de conceito, uma imagem abaixo onde temos uma Rede em produção de DNS(s) Recursivos Anycast e apontando exatamente o momento em que houve alguma situação que fez com que as queries de DNS, convergissem de um node para outro, de forma transparente e automática para o cliente. Podemos notar também que ao ser resolvido o problema, o tráfego retornou para o seu node correto:&lt;br /&gt;
[[Arquivo:Convergencia.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== KINDNS (Stands for Knowledge-Sharing and Instantiating Norms for DNS and Naming Security) ==&lt;br /&gt;
Achou que havia terminado? Agora que você tem a capacidade de montar uma '''Rede de DNS Recursivo''' com todas essas features acima, com todas as ferramentas que foram comentadas, o que acha de certificar o que fez?&lt;br /&gt;
&lt;br /&gt;
Assim como o [https://www.manrs.org/ MANRS] veio para certificar nosso sistema de roteamento na Internet, agora temos o [https://kindns.org/ KINDNS] para certificar que nossos sistemas de DNS estão bem feitos e dentro dos padrões de segurança. Existem '''7 ações''' que podem ser certificadas para nossos DNS Recursivos e estão aqui em https://kindns.org/shared-private-resolvers/. Com essa nossa documentação, se bem aplicada, você pode se candidatar ao KINDNS e ter seu ASN listado aqui https://kindns.org/participants/&lt;br /&gt;
&lt;br /&gt;
Obter e manter o '''MANRS''' e '''KINDNS''' demonstra seu compromisso com as Boas Práticas, contribui para termos uma '''Internet''' mais segura e te abre portas para novos negócios que possam exigir essas conformidades.&lt;br /&gt;
&lt;br /&gt;
Autor: [[Usuário:Gondim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Infraestrutura]]&lt;br /&gt;
__FORCARTDC__&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3942</id>
		<title>DNS Recursivo Anycast Hyperlocal</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3942"/>
		<updated>2025-09-01T18:47:22Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
==Introdução==&lt;br /&gt;
Você sabe como funciona a Internet? Essa é uma pergunta que meu amigo '''Thiago Ayub''' sempre faz aos seus candidatos à vagas de emprego e não importa o quanto tenham de experiência em '''Engenharia de Redes''', todos sempre travam nesse momento. Todos estão sempre prontos e preparados para resolver os problemas mais cabeludos em '''BGP''', '''OSPF''', '''MPLS''', etc mas travam com essa simples pergunta. Para contextualizar e visualizarmos melhor vamos nos atentar à imagem abaixo e uma explicação simplificada de como funciona:&lt;br /&gt;
[[Arquivo:Dns hierarquia.png|esquerda|commoldura]]&lt;br /&gt;
Tudo começa com um usuário sentado confortavelmente e querendo acessar um conteúdo disponível na Internet. Ele digita em seu navegador preferido a URL: '''&amp;lt;nowiki&amp;gt;https://wiki.brasilpeeringforum.org&amp;lt;/nowiki&amp;gt;''',&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;1)&amp;lt;/big&amp;gt;''' &amp;lt;big&amp;gt;O&amp;lt;/big&amp;gt; &amp;lt;big&amp;gt;navegador irá requisitar do '''DNS Recursivo''' utilizado pelo usuário, o '''endereço IP''' que responde pelo nome '''wiki.'''&amp;lt;/big&amp;gt;'''brasilpeeringforum.org'''&amp;lt;big&amp;gt;. Isso porque todos os acessos se dão na Internet através do '''endereço''' '''IP''' e não através do '''nome'''. Imaginem se tivéssemos que decorar os endereços IPs de todos os sites e serviços que quiséssemos acessar na Internet?&amp;lt;/big&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;big&amp;gt;'''2)''' Nosso DNS Recursivo checa se a informação consta em seu cache.&amp;lt;/big&amp;gt; Se a informação existir ela é devolvida ao navegador do usuário e aí este consegue acessar o site.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Do contrário o DNS Recursivo pergunta ao '''Root Server''' quem é o '''TLD (Top Level Domain)''' responsável para atender a requisição. &lt;br /&gt;
&lt;br /&gt;
'''4)''' O '''Root Server''' informa ao DNS Recursivo o endereço do '''TLD responsável'''. No Brasil o '''TLD''' responsável pelo '''.br''' seria o '''Registro.br'''.&lt;br /&gt;
&lt;br /&gt;
'''5)''' O DNS Recursivo pergunta ao '''TLD''' sobre '''wiki.brasilpeeringforum.org''' e este responde com os endereços IP dos '''DNS Autoritativos''' responsáveis pelo domínio '''brasilpeeringforum.org.'''&lt;br /&gt;
&lt;br /&gt;
'''6)''' O DNS Recursivo pergunta aos '''DNS Autoritativos''' pelo '''wiki.brasilpeeringforum.org''' e este responde com o '''endereço IP'''.&lt;br /&gt;
&lt;br /&gt;
'''7)''' Por último o DNS Recursivo devolve a informação para o navegador do usuário.&lt;br /&gt;
&lt;br /&gt;
Como que se dá a comunicação entre os '''DNS(s) Recursivos, Root Servers, TLDs''' e '''Autoritativos'''? Como que o navegador do usuário, após receber o IP do site, consegue chegar no servidor que tem o conteúdo? Isso só é possível devido ao protocolo chamado '''BGP (Border Gateway Protocol)''', todos os caminhos que conhecemos como rotas de destino, são anunciadas por milhares de participantes na '''Internet''' conhecidos como '''AS (Autonomous System)''', esses participantes se interligam para disponibilizar conteúdos e acessos pelo mundo aos milhares de usuários. É uma imensa rede colaborativa formada por Empresas, Universidades, Governos e todos que queiram se interconectar. Percebam que sem o '''BGP''', que serve de caminho para chegarmos nos conteúdos e sem o '''DNS (Domain Name System)''' para traduzir o nome para o endereço IP, a '''Internet''' não funcionaria e por isso precisamos cuidar muito bem desses dois serviços.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Mas não acaba por aí. O '''DNS Recursivo''' tem um papel muito importante para o Provedor de Internet e que envolve segurança, qualidade de acesso à Internet e a disponibilidade do serviço entregue ao cliente. Quando bem configurado acelera as consultas dos acessos graças ao seu cache interno, mas para que isso seja percebido pelo assinante, é necessário que esteja o mais próximo possível do seu cliente.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Um erro que destrói a qualidade do nosso serviço ==&lt;br /&gt;
Um erro muito comum que muitas operadoras cometem é utilizar DNS Recursivo externo, como o '''8.8.8.8''', '''1.1.1.1''' e outros, para seus clientes. Quanto mais próximo dos seus clientes, mais qualidade de serviço estará entregando a eles. Conteúdos serão entregues mais rapidamente pois serão resolvidos e armazenados em caches locais e não consultados remotamente na Internet. Para falar mais sobre isso, te convido leitor desse documento, que assista essa palestra do '''Thiago Ayub''' no '''GTER 51/GTS 37''' (2022) '''8.888 MOTIVOS PARA NÃO USAR DNS RECURSIVO EXTERNO EM SEU AS''': https://www.youtube.com/watch?v=Rsvpu5uF2Io&lt;br /&gt;
&lt;br /&gt;
== Objetivo ==&lt;br /&gt;
O objetivo desta documentação não é te ensinar tudo sobre '''DNS''', '''BGP''', '''OSPF''' e nem tão pouco sobre GNU/Linux e sim te mostrar um exemplo de servidor DNS Recursivo implementado pensando em segurança, qualidade e resiliência. Usaremos em todas as nossas documentações o [https://www.debian.org/ Debian GNU/Linux], por ser uma distribuição que considero uma obra de arte criada por uma enorme comunidade séria, com vasta experiência de anos, qualidade no empacotamento dos programas, estável e com uma equipe de segurança excelente e ativa. Caso você leitor, utilize alguma outra distribuição GNU/Linux, todo conteúdo apresentado aqui pode ser aplicado em outras distros, desde que respeitando as particularidades de cada uma.&lt;br /&gt;
&lt;br /&gt;
Aqui construiremos um sistema do tipo '''Anycast''', ou seja, terás o serviço rodando em diversas localidades da sua Rede utilizando o mesmo endereçamento IP e que atenderá seu cliente mais próximo. Em caso de falhas, seus clientes automaticamente e de forma transparente continuarão consultando o DNS mais próximo deles. Para que ele funcione dessa forma você precisará ter uma '''Rede OSPF''' implementada no seu Provedor Internet ou algum outro protocolo como por exemplo o '''ISIS,''' mas esse documento não irá abordar o '''ISIS'''. Também utilizaremos o '''Hyperlocal''' como recurso adicional para gerar algumas proteções de segurança e velocidade na resposta relacionada aos servidores de DNS Raiz da Internet.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
Para exemplificar nosso servidor de DNS Recursivo, usaremos como base das explicações um diagrama demonstrando o uso do DNS Recursivo em uma Rede fictícia. Adotaremos IPs privados e reservados para demonstrar todo o ambiente do Provedor de Internet.&lt;br /&gt;
[[Arquivo:Diagrama dns recursiv2.png|alt=|esquerda|miniaturadaimagem|695x695px]]&lt;br /&gt;
Nesse diagrama podemos observar alguns detalhes técnicos como por exemplo: existem '''3 servidores de DNS Recursivo''' posicionados em locais diferentes, que poderiam estar em bairros diferentes e até em cidades diferentes. Em cada servidor teremos '''2 loopbacks''' com os IPs:&lt;br /&gt;
&lt;br /&gt;
'''10.10.10.10/32 - fc00::10:10:10:10/128'''&lt;br /&gt;
&lt;br /&gt;
'''10.10.9.9/32 - fc00::10:10:9:9/128'''&lt;br /&gt;
&lt;br /&gt;
Esses IPs serão entregues pelos concentradores '''PPPoE''' ou '''IPoE''' ('''BNG''') para seus clientes como '''DNS primário''' e '''secundário'''. Podemos usar IPs privados como DNS primário e secundário em um ambiente real? Sim podemos, desde que não sejam IPs que possam ter problemas com as redes privadas dos clientes. Ex.: rede do cliente usando '''192.168.0.0/24'''. Se entregarmos o DNS sendo '''192.168.0.10''' e '''192.168.0.20''' teremos problemas e o cliente ficará sem Internet, porque '''192.168.0.10''' e '''192.168.0.20''' fazem parte da rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
Agora entregando '''10.10.10.10,''' '''10.10.9.9, fc00::10:10:10:10 e fc00::10:10:9:9''' não teríamos problemas com a rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
'''Motivos para usarmos IPs privados:'''&lt;br /&gt;
* O principal motivo está relacionado com a segurança, uma vez que sendo um IP privado, não pode sofrer ataques DDoS direcionados diretamente para ele, vindos da Internet.&lt;br /&gt;
* Nem mesmo o cliente da sua rede conhece os '''IPs públicos''' utilizados para recursividade na Internet.&lt;br /&gt;
* Memorizar os IPs '''10.10.10.10''' e '''10.10.9.9''' é tão fácil quanto memorizar o '''8.8.8.8''' e o '''1.1.1.1'''. Mais fácil para o seu técnico guardar essa informação e utilizar onde for necessário.&lt;br /&gt;
Cada servidor DNS Recursivo possui um '''IPv4 público''', aqui representado por '''198.18.x.x/27''' e um '''IPv6 global''' representado por um IP dentro do prefixo '''2001:db8::/32'''. Cada servidor precisa ter os seus próprios IPs e são através destes IPs que as consultas de DNS serão realizadas na Internet.&lt;br /&gt;
&lt;br /&gt;
Nessa topologia usando '''Anycast''', o cliente será sempre atendido pelo '''DNS Recursivo''' mais próximo, desde que os pesos no '''OSPF''' estejam ajustados corretamente.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
== Dados do servidor ==&lt;br /&gt;
Podemos utilizar um sistema virtualizado ou não. Sistemas virtualizados são bem vindos pois são mais simples quando precisamos fazer backups, levantar outros sistemas sem complicações e se precisarmos restaurar rapidamente algum sistema que ficou indisponível por algum motivo. A configuração abaixo tem capacidade para atender algo em torno a '''50.000 assinantes ou mais'''. O DNS Recursivo é um serviço que pode ser utilizado até mesmo em um '''Raspberry Pi''' e atender operações pequenas, nesse caso com o intuito de economizar energia e espaço. Nosso foco aqui é montar uma rede de '''DNS Recursivo Anycast com HyperLocal'''. Como comentei acima o servidor deve ficar o mais próximo dos clientes para termos a '''menor latência possível''' e '''sempre menor que 5ms''' entre o cliente e o servidor.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!CPU&lt;br /&gt;
!Memória&lt;br /&gt;
!Disco&lt;br /&gt;
!Sistema&lt;br /&gt;
|-&lt;br /&gt;
|2.4Ghz 4 cores&lt;br /&gt;
|16G DDR4&lt;br /&gt;
|30G&lt;br /&gt;
|Debian 12 amd64 (Bookworm)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Softwares utilizados ==&lt;br /&gt;
* Debian 12 amd64 (Bookworm) instalação mínima.&lt;br /&gt;
&lt;br /&gt;
* [https://frrouting.org/ FRRouting].&lt;br /&gt;
* Unbound.&lt;br /&gt;
* IRQBalance.&lt;br /&gt;
* Chrony (NTP/NTS).&lt;br /&gt;
* Shell script em bash.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades que teremos ==&lt;br /&gt;
* Sistema em Anycast.&lt;br /&gt;
* Hyperlocal.&lt;br /&gt;
* Controle de acesso por &amp;lt;abbr&amp;gt;ACL&amp;lt;/abbr&amp;gt;.&lt;br /&gt;
* RPZ (Response Policy Zone).&lt;br /&gt;
* Bloqueio de consultas do tipo ANY.&lt;br /&gt;
* QNAME minimization habilitado. (habilitado por default no Unbound)&lt;br /&gt;
* Recursividade em IPv4 e IPv6.&lt;br /&gt;
* DNSSEC habilitado.&lt;br /&gt;
* &amp;lt;abbr&amp;gt;DoH (DNS&amp;lt;/abbr&amp;gt; over HTTPS) habilitado.&lt;br /&gt;
&lt;br /&gt;
== Monitoramento ==&lt;br /&gt;
O monitoramento é algo bem específico e não é o foco deste documento mas é extremamente importante que você monitore seus servidores de DNS por alguma ferramenta como o Zabbix. Aqui mostrarei apenas como enviar as informações para o Zabbix. Algumas coisas que você deveria monitorar nos servidores de DNS Recursivo:&lt;br /&gt;
* Serviço do unbound parou.&lt;br /&gt;
* Perda de pacotes.&lt;br /&gt;
* Latência alta de pacotes.&lt;br /&gt;
* Lentidão na resolução de queries.&lt;br /&gt;
* CPU alta.&lt;br /&gt;
* Load alto.&lt;br /&gt;
* Memória com uso alto.&lt;br /&gt;
* Disco com pouco espaço.&lt;br /&gt;
* Queda brusca nas queries.&lt;br /&gt;
* A recursividade parou de funcionar.&lt;br /&gt;
* A recursividade voltou a funcionar.&lt;br /&gt;
Este abaixo é um exemplo de monitoramento de um sistema de DNS Recursivo que atende 50.000 assinantes:&lt;br /&gt;
[[Arquivo:Grafana dns.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Configurando a Rede ==&lt;br /&gt;
Nossa documentação será baseada no diagrama apresentado acima e por isso configuraremos apenas um dos três servidores, porque os outros serão configurados da mesma forma, só que com dados diferentes. Para tanto assumirei que já temos um sistema Debian instalado com o mínimo de pacotes e somente com sshd, para que possamos acessar remotamente mais tarde. '''Não instale um ambiente gráfico no servidor''', você não deve querer fazer isso por diversos motivos e os principais: primeiro porque não é um Desktop e segundo porque o ambiente gráfico devoraria toda a memória com recursos que não seriam úteis aqui.&lt;br /&gt;
&lt;br /&gt;
Em '''/etc/network/interfaces''' deixaremos assim:&lt;br /&gt;
 # This file describes the network interfaces available on your system&lt;br /&gt;
 # and how to activate them. For more information, see interfaces(5).&lt;br /&gt;
  &lt;br /&gt;
 source /etc/network/interfaces.d/*&lt;br /&gt;
  &lt;br /&gt;
 # The loopback network interface&lt;br /&gt;
 auto lo&lt;br /&gt;
 iface lo inet loopback&lt;br /&gt;
  &lt;br /&gt;
 auto lo:0&lt;br /&gt;
 iface lo:0 inet static&lt;br /&gt;
       address 10.10.10.10/32&lt;br /&gt;
  &lt;br /&gt;
 auto lo:1&lt;br /&gt;
 iface lo:1 inet static&lt;br /&gt;
       address 10.10.9.9/32&lt;br /&gt;
 &lt;br /&gt;
 auto lo:2&lt;br /&gt;
 iface lo:2 inet6 static&lt;br /&gt;
       address fc00::10:10:10:10/128&lt;br /&gt;
 &lt;br /&gt;
 auto lo:3&lt;br /&gt;
 iface lo:3 inet6 static&lt;br /&gt;
       address fc00::10:10:9:9/128&lt;br /&gt;
  &lt;br /&gt;
 # The primary network interface&lt;br /&gt;
 auto ens18&lt;br /&gt;
 iface ens18 inet static&lt;br /&gt;
         address 198.18.1.10/27&lt;br /&gt;
         gateway 198.18.1.1&lt;br /&gt;
  &lt;br /&gt;
 iface ens18 inet6 static&lt;br /&gt;
         address 2001:db8::faca:198:18:1:10/64&lt;br /&gt;
         gateway 2001:db8::faca:198:18:1:1&lt;br /&gt;
  &lt;br /&gt;
 # The secondary network interface&lt;br /&gt;
 auto ens18:0&lt;br /&gt;
 iface ens18:0 inet static&lt;br /&gt;
         address 172.16.0.6/30&lt;br /&gt;
Nesse cenário temos as duas '''loopbacks''' com os IPs '''10.10.10.10''', '''10.10.9.9, fc00::10:10:10:10''' e '''fc00::10:10:9:9''' que serão anunciados via OSPF para a rede e serem entregues aos clientes via BNG. Os IPs '''198.18.1.10''' e '''2001:db8::faca:198:18:1:10''' serão usados para fazerem a recursividade na Internet tanto em IPv4 quanto em IPv6. Esses IPs não devem ser divulgados para clientes; os IPs públicos são dedicados apenas para essa finalidade.&lt;br /&gt;
&lt;br /&gt;
== Configuração dos repositórios Debian ==&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list''' conforme abaixo:&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://security.debian.org/debian-security&amp;lt;/nowiki&amp;gt; bookworm-security main contrib non-free non-free-firmware&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian&amp;lt;/nowiki&amp;gt; bookworm main contrib non-free non-free-firmware&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian&amp;lt;/nowiki&amp;gt; bookworm-updates main contrib non-free non-free-firmware&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian&amp;lt;/nowiki&amp;gt; bookworm-backports main contrib non-free non-free-firmware&lt;br /&gt;
Após a configuração vamos instalar alguns pacotes necessários e outros úteis:&lt;br /&gt;
 # apt update &amp;amp;&amp;amp; apt full-upgrade&lt;br /&gt;
 # apt install net-tools nftables htop iotop sipcalc tcpdump curl gnupg rsync wget host dnsutils mtr-tiny bmon sudo tmux whois ethtool dnstop&lt;br /&gt;
&lt;br /&gt;
== Fazendo algum tuning no sistema ==&lt;br /&gt;
Em '''/etc/sysctl.conf''' adicionamos no final do arquivo essas instruções:&lt;br /&gt;
 net.core.rmem_max = 2147483647&lt;br /&gt;
 net.core.wmem_max = 2147483647&lt;br /&gt;
 net.ipv4.tcp_rmem = 4096 87380 2147483647&lt;br /&gt;
 net.ipv4.tcp_wmem = 4096 65536 2147483647&lt;br /&gt;
 net.netfilter.nf_conntrack_buckets = 512000&lt;br /&gt;
 net.netfilter.nf_conntrack_max = 4096000&lt;br /&gt;
 vm.swappiness=10&lt;br /&gt;
Estamos fazendo algumas melhorias de memória, algumas relacionadas a '''conntrack''' porque se for usar um filtro de pacotes stateful, como o '''Netfilter/IPTables''' ou '''Netfilter/NFTables''', o valor default da tabela é pequeno e dependendo da situação, se estourar essa tabela, as consultas de DNS terão problemas também. O DNS Recursivo não deve ficar aberto para qualquer um na Internet, ele deve ser liberado apenas para seus clientes. Podemos fazer através das ACLs do Unbound e pelo filtro de pacotes. O último parâmetro diz respeito ao uso de swap, por padrão o Debian permite o uso de swap após 40% do uso da memória, nesse caso estamos dizendo para o sistema usar o swap com 90% de uso da memória.&lt;br /&gt;
&lt;br /&gt;
Precisamos adicionar o módulo '''nf_conntrack''' em '''/etc/modules''' para que seja carregado em tempo de boot, senão os parâmetros de '''conntrack''' que colocamos em '''/etc/sysctl.conf''' não serão carregados.&lt;br /&gt;
 # echo nf_conntrack &amp;gt;&amp;gt; /etc/modules&lt;br /&gt;
 # modprobe nf_conntrack&lt;br /&gt;
 # sysctl -p&lt;br /&gt;
&lt;br /&gt;
== Instalando o FRRouting ==&lt;br /&gt;
O FRRouting é o programa que usaremos para fazer os anúncios das nossas loopbacks via OSPF. Nesse documento usaremos a versão 10.x e para isso precisaremos configurar o repositório oficial do FRRouting e instalar os pacotes:&lt;br /&gt;
 # curl -s &amp;lt;nowiki&amp;gt;https://deb.frrouting.org/frr/keys.gpg&amp;lt;/nowiki&amp;gt; | tee /usr/share/keyrings/frrouting.gpg &amp;gt; /dev/null&lt;br /&gt;
 # echo &amp;quot;deb [signed-by=/usr/share/keyrings/frrouting.gpg] &amp;lt;nowiki&amp;gt;https://deb.frrouting.org/frr&amp;lt;/nowiki&amp;gt; bookworm frr-10&amp;quot; &amp;gt; /etc/apt/sources.list.d/frr.list&lt;br /&gt;
 # apt update&lt;br /&gt;
 # apt install frr frr-doc frr-pythontools&lt;br /&gt;
Aconselho depois de instalar os pacotes, marcá-los para não atualizar juntamente com os demais pacotes, isso é para evitar de ocorrer alguma atualização no FRRouting, que torne o serviço instável por algum motivo. Não que isso vá ocorrer, mas é melhor fazer essa atualização quando realmente for necessário.&lt;br /&gt;
 # apt-mark hold frr frr-doc frr-pythontools&lt;br /&gt;
Após esse comando acima, o sistema manterá a instalação original do pacote intacta. Para desbloquear basta executar o comando abaixo:&lt;br /&gt;
 # apt-mark unhold frr frr-doc frr-pythontools&lt;br /&gt;
&lt;br /&gt;
== Removendo o APPARMOR ==&lt;br /&gt;
O '''APPARMOR''' às vezes causa mais problemas que solução e se não for fazer uma completa configuração nele, é melhor desabilitá-lo. Para fazer isso efetivamente, o procedimento é esse abaixo:&lt;br /&gt;
 # mkdir -p /etc/default/grub.d&lt;br /&gt;
 # echo 'GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;$GRUB_CMDLINE_LINUX_DEFAULT apparmor=0&amp;quot;' | tee /etc/default/grub.d/apparmor.cfg&lt;br /&gt;
 # update-grub&lt;br /&gt;
 # reboot&lt;br /&gt;
&lt;br /&gt;
== Instalando o Unbound ==&lt;br /&gt;
Nesse momento ainda não iremos configurar o Unbound, apenas instalar o pacote e acertar o ambiente. Vamos instalar o unbound do backports porque este já possui suporte ao DoH que veremos mais à frente.&lt;br /&gt;
 # apt install unbound dns-root-data&lt;br /&gt;
 # mkdir -p /var/log/unbound&lt;br /&gt;
 # touch /var/log/unbound/unbound.log&lt;br /&gt;
 # chown -R unbound:unbound /var/log/unbound/&lt;br /&gt;
 # systemctl restart unbound&lt;br /&gt;
Configurando o logrotate:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/logrotate.d/unbound&lt;br /&gt;
 /var/log/unbound/unbound.log {&lt;br /&gt;
     rotate 5&lt;br /&gt;
     weekly&lt;br /&gt;
     postrotate&lt;br /&gt;
         unbound-control log_reopen&lt;br /&gt;
     endscript&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
Reiniciando o serviço:&lt;br /&gt;
 # systemctl restart logrotate.service&lt;br /&gt;
&lt;br /&gt;
== Desabilitando THP (Transparente Huge Pages) em arquitetura AMD64 ==&lt;br /&gt;
No Debian o '''THP''' vem habilitado como '''always''' e o '''unbound''' por trabalhar bastante com alterações do cache em memória, isso pode acabar causando um consumo crescente de uso de RAM sem necessidade. É uma boa prática desabilitá-lo com os passos abaixo:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/systemd/system/disable-thp.service&lt;br /&gt;
 [Unit]&lt;br /&gt;
 Description=Desativa Transparent Huge Pages (THP)&lt;br /&gt;
 After=network.target&lt;br /&gt;
 &lt;br /&gt;
 [Service]&lt;br /&gt;
 Type=oneshot&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled&amp;quot;&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/defrag&amp;quot;&lt;br /&gt;
 RemainAfterExit=yes&lt;br /&gt;
 &lt;br /&gt;
 [Install]&lt;br /&gt;
 WantedBy=multi-user.target&lt;br /&gt;
 EOF&lt;br /&gt;
Acima configuramos o serviço '''disable-thp.service''' para desabilitar o '''THP''' e abaixo habilitamos no '''systemd''' e iniciamos:&lt;br /&gt;
 # systemctl daemon-reload&lt;br /&gt;
 # systemctl enable --now disable-thp&lt;br /&gt;
&lt;br /&gt;
== Preparando o monitoramento do seu DNS Recursivo ==&lt;br /&gt;
O monitoramento do seu DNS Recursivo é muito importante e para isso vamos usar um '''template para Zabbix''', que modifiquei juntamente com o seu shell script e que enviará os dados para o seu Zabbix server via '''zabbix-sender'''. O projeto original está aqui '''https://github.com/jeftedelima/Unbound-DNS&amp;lt;nowiki/&amp;gt;.''' O xml alterado está aqui '''https://github.com/gondimcodes/template_zabbix_dns_unbound'''. Embora seja antigo é perfeitamente importável no Zabbix 6.0, por exemplo.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;nowiki/&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Teremos um shell script que você precisará colocar no seu '''/etc/crontab'''. No exemplo abaixo assumi que o shell script está em '''/root/scripts'''. De 5 em 5 minutos os dados serão enviados para o seu Zabbix server.&lt;br /&gt;
 */5 * * * *     root    /root/scripts/unboundSend.sh '''IP_zabbix_server''' '''nome_do_host''' 1&amp;gt; /dev/null&lt;br /&gt;
Na linha acima, troque o '''IP_zabbix_server''' pelo '''IP do seu servidor Zabbix''' e o '''nome_do_host''' pelo '''hostname''' '''do seu DNS Recursivo'''. Você precisará instalar o pacote '''zabbix-sender''' no seu DNS Recursivo pois ele será usado para enviar os dados para o Zabbix server.&lt;br /&gt;
&lt;br /&gt;
Abaixo o '''unboundSend.sh''' também alterado com inclusão de mais dados:&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 #       @Jefte de Lima Ferreira&lt;br /&gt;
 #       jeftedelima at gmail dot com&lt;br /&gt;
 #       CRON Example&lt;br /&gt;
 #       Contributor: Marcelo Gondim - gondim at gmail dot com&lt;br /&gt;
 #       */5   **** root sh /home/dir/unboundSend.sh 192.168.10.1 Unbound 1&amp;gt; /dev/null&lt;br /&gt;
 &lt;br /&gt;
 if [ -z ${1} ] || [ -z ${2} ] ; then&lt;br /&gt;
         echo &amp;quot;You need to specify the IP address of zabbix server and hostname of your DNS Unbound on zabbix&amp;quot;&lt;br /&gt;
         echo &amp;quot;Usage example: ./unboundSend.sh 192.168.10.1 UnboundServer&amp;quot;&lt;br /&gt;
         exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
 # ZABBIX_SERVER IP&lt;br /&gt;
 IP_ZABBIX=$1&lt;br /&gt;
 # NAME Unbound on Zabbix&lt;br /&gt;
 NAME_HOST=$2&lt;br /&gt;
 DIR_TEMP=/var/tmp/&lt;br /&gt;
 FILE=&amp;quot;${DIR_TEMP}dump_unbound_control_stats.txt&amp;quot;&lt;br /&gt;
 unbound-control stats &amp;gt; ${FILE}&lt;br /&gt;
 &lt;br /&gt;
 TOTAL_NUM_QUERIES=$(cat ${FILE} | grep -w 'total.num.queries' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEHITS=$(cat ${FILE} | grep -w 'total.num.cachehits' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEMISS=$(cat ${FILE} | grep -w 'total.num.cachemiss' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_PREFETCH=$(cat ${FILE} | grep -w 'total.num.prefetch' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_RECURSIVEREPLIES=$(cat ${FILE} | grep -w 'total.num.recursivereplies' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 TOTAL_REQ_MAX=$(cat ${FILE} | grep -w 'total.requestlist.max' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_AVG=$(cat ${FILE} | grep -w 'total.requestlist.avg' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_OVERWRITTEN=$(cat ${FILE} | grep -w 'total.requestlist.overwritten' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_EXCEEDED=$(cat ${FILE} | grep -w 'total.requestlist.exceeded' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_ALL=$(cat ${FILE} | grep -w 'total.requestlist.current.all' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_USER=$(cat ${FILE} | grep -w 'total.requestlist.current.user' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 TOTAL_TCPUSAGE=$(cat ${FILE} | grep -w 'total.tcpusage' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 NUM_QUERY_TYPE_A=$(cat ${FILE} | grep -w 'num.query.type.A' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NS=$(cat ${FILE} | grep -w 'num.query.type.NS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_MX=$(cat ${FILE} | grep -w 'num.query.type.MX' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TXT=$(cat ${FILE} | grep -w 'num.query.type.TXT' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_PTR=$(cat ${FILE} | grep -w 'num.query.type.PTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_AAAA=$(cat ${FILE} | grep -w 'num.query.type.AAAA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SRV=$(cat ${FILE} | grep -w 'num.query.type.SRV' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SOA=$(cat ${FILE} | grep -w 'num.query.type.SOA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HTTPS=$(cat ${FILE} | grep -w 'num.query.type.HTTPS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TYPE0=$(cat ${FILE} | grep -w 'num.query.type.TYPE0' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_CNAME=$(cat ${FILE} | grep -w 'num.query.type.CNAME' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_WKS=$(cat ${FILE} | grep -w 'num.query.type.WKS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HINFO=$(cat ${FILE} | grep -w 'num.query.type.HINFO' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_X25=$(cat ${FILE} | grep -w 'num.query.type.X25' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NAPTR=$(cat ${FILE} | grep -w 'num.query.type.NAPTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DS=$(cat ${FILE} | grep -w 'num.query.type.DS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DNSKEY=$(cat ${FILE} | grep -w 'num.query.type.DNSKEY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TLSA=$(cat ${FILE} | grep -w 'num.query.type.TLSA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SVCB=$(cat ${FILE} | grep -w 'num.query.type.SVCB' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SPF=$(cat ${FILE} | grep -w 'num.query.type.SPF' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_ANY=$(cat ${FILE} | grep -w 'num.query.type.ANY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_OTHER=$(cat ${FILE} | grep -w 'num.query.type.other' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 NUM_ANSWER_RCODE_NOERROR=$(cat ${FILE} | grep -w 'num.answer.rcode.NOERROR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_NXDOMAIN=$(cat ${FILE} | grep -w 'num.answer.rcode.NXDOMAIN' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_SERVFAIL=$(cat ${FILE} | grep -w 'num.answer.rcode.SERVFAIL' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_REFUSED=$(cat ${FILE} | grep -w 'num.answer.rcode.REFUSED' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_nodata=$(cat ${FILE} | grep -w 'num.answer.rcode.nodata' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_secure=$(cat ${FILE} | grep -w 'num.answer.secure' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 #       Sending info to zabbix_server, if variables is not empty!&lt;br /&gt;
 [ -z ${TOTAL_NUM_QUERIES} ] ||  zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.queries -o $((TOTAL_NUM_QUERIES/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_CACHEHITS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachehits -o $((TOTAL_NUM_CACHEHITS/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_CACHEMISS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachemiss -o $((TOTAL_NUM_CACHEMISS/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_PREFETCH} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.prefetch -o $((TOTAL_NUM_PREFETCH/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_RECURSIVEREPLIES} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.recursivereplies -o $((TOTAL_NUM_RECURSIVEREPLIES/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${TOTAL_REQ_MAX} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.max -o $((TOTAL_REQ_MAX/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_AVG} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.avg -o $((TOTAL_REQ_AVG/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_OVERWRITTEN} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.overwritten -o $((TOTAL_REQ_OVERWRITTEN/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_EXCEEDED} ] ||  zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.exceeded -o $((TOTAL_REQ_EXCEEDED/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_CURRENT_ALL} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.all -o $((TOTAL_REQ_CURRENT_ALL/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_CURRENT_USER} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.user -o $((TOTAL_REQ_CURRENT_USER/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${TOTAL_TCPUSAGE} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.tcpusage -o $((TOTAL_TCPUSAGE/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_A} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.a -o $((NUM_QUERY_TYPE_A/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_NS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ns -o $((NUM_QUERY_TYPE_NS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_MX} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.mx -o $((NUM_QUERY_TYPE_MX/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_TXT} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.txt -o $((NUM_QUERY_TYPE_TXT/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_PTR} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ptr -o $((NUM_QUERY_TYPE_PTR/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_AAAA} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.aaaa -o $((NUM_QUERY_TYPE_AAAA/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SRV} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.srv -o $((NUM_QUERY_TYPE_SRV/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SOA} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.soa -o $((NUM_QUERY_TYPE_SOA/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_HTTPS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.https -o $((NUM_QUERY_TYPE_HTTPS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_TYPE0} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.type0 -o $((NUM_QUERY_TYPE_TYPE0/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_CNAME} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.cname -o $((NUM_QUERY_TYPE_CNAME/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_WKS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.wks -o $((NUM_QUERY_TYPE_WKS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_HINFO} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.hinfo -o $((NUM_QUERY_TYPE_HINFO/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_X25} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.X25 -o $((NUM_QUERY_TYPE_X25/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_NAPTR} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.naptr -o $((NUM_QUERY_TYPE_NAPTR/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_DS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ds -o $((NUM_QUERY_TYPE_DS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_DNSKEY} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.dnskey -o $((NUM_QUERY_TYPE_DNSKEY/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_TLSA} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.tlsa -o $((NUM_QUERY_TYPE_TLSA/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SVCB} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.svcb -o $((NUM_QUERY_TYPE_SVCB/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SPF} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.spf -o $((NUM_QUERY_TYPE_SPF/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_ANY} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.any -o $((NUM_QUERY_TYPE_ANY/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_OTHER} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.other -o $((NUM_QUERY_TYPE_OTHER/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_NOERROR} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NOERROR -o $((NUM_ANSWER_RCODE_NOERROR/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_NXDOMAIN} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NXDOMAIN -o $((NUM_ANSWER_RCODE_NXDOMAIN/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_SERVFAIL} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.SERVFAIL -o $((NUM_ANSWER_RCODE_SERVFAIL/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_REFUSED} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.REFUSED -o $((NUM_ANSWER_RCODE_REFUSED/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_nodata} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.nodata -o $((NUM_ANSWER_RCODE_nodata/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_secure} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.secure -o $((NUM_ANSWER_secure/300))&lt;br /&gt;
No Zabbix será registrado dados como esses abaixo e posteriormente pode ser montado um Grafana com eles:&lt;br /&gt;
[[Arquivo:Zabbix dns01.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns02.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns03.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns04.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Balanceando o processamento e mantendo a hora certa ==&lt;br /&gt;
Vamos instalar 2 programas agora, o IRQBalance e o Chrony. O primeiro para balancear a carga entre os cores e o segundo para manter a data e hora certas no sistema:&lt;br /&gt;
 # apt install irqbalance&lt;br /&gt;
 # systemctl enable irqbalance&lt;br /&gt;
 # apt install chrony&lt;br /&gt;
Após a instalação do Chrony edite o arquivo /etc/chrony/chrony.conf, comente e a linha abaixo e adicione seus servidores NTP. Caso não tenha servidores NTP, estou colocando os do NIC.br aqui.&lt;br /&gt;
 #pool 2.debian.pool.ntp.org iburst&lt;br /&gt;
 server a.st1.ntp.br iburst nts&lt;br /&gt;
 server b.st1.ntp.br iburst nts&lt;br /&gt;
 server c.st1.ntp.br iburst nts&lt;br /&gt;
 server d.st1.ntp.br iburst nts&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart chronyd.service&lt;br /&gt;
Cheque com o '''chronyc''' se os servidores estão OK:&lt;br /&gt;
 # chronyc sourcestats&lt;br /&gt;
 Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev&lt;br /&gt;
 ==============================================================================&lt;br /&gt;
 a.st1.ntp.br               10   5  155m     -0.027      0.030    -71us    51us&lt;br /&gt;
 b.st1.ntp.br               11   7  344m     +0.068      0.079    +23ms   382us&lt;br /&gt;
 c.st1.ntp.br                6   3  344m     +0.026      0.037   -124us    92us&lt;br /&gt;
 200.20.186.76               9   3  138m     -0.022      0.031   +172us    42us&lt;br /&gt;
&lt;br /&gt;
 # chronyc sources&lt;br /&gt;
 MS Name/IP address         Stratum Poll Reach LastRx Last sample&lt;br /&gt;
 ===============================================================================&lt;br /&gt;
 ^* a.st1.ntp.br                  1  10   377   588   +487us[ +397us] +/-   12ms&lt;br /&gt;
 ^- b.st1.ntp.br                  2  10   377   830    +23ms[  +23ms] +/-   49ms&lt;br /&gt;
 ^+ c.st1.ntp.br                  2  10    21  1038   -147us[ -242us] +/-   17ms&lt;br /&gt;
 ^+ 200.20.186.76                 1  10   377  1032   +381us[ +285us] +/-   15ms&lt;br /&gt;
&lt;br /&gt;
== Configurando o FRRouting ==&lt;br /&gt;
Nesse ponto iremos configurar o '''FRRouting''' para enviar os IPs das '''loopbacks''' e o '''/30''' para o nosso PE do diagrama. Em '''/etc/frr/daemons''' habilite o parâmetro conforme abaixo:&lt;br /&gt;
 ospfd=yes&lt;br /&gt;
Edite o arquivo '''/etc/frr/frr.conf''' e deixe com o conteúdo abaixo, para ficar conforme nosso diagrama do projeto. Apenas troque '''&amp;lt;SENHA&amp;gt;''' por uma senha para fechar o OSPF com mais segurança. Essa senha deve ser usada dos dois lados.&lt;br /&gt;
 frr version 10.2.1&lt;br /&gt;
 frr defaults traditional&lt;br /&gt;
 hostname dns-recursivo-01&lt;br /&gt;
 log syslog informational&lt;br /&gt;
 no ip forwarding&lt;br /&gt;
 no ipv6 forwarding&lt;br /&gt;
 service integrated-vtysh-config&lt;br /&gt;
 !&lt;br /&gt;
 interface ens18&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf message-digest-key 5 md5 &amp;lt;SENHA&amp;gt;&lt;br /&gt;
  ip ospf network point-to-point&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 network point-to-point&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 interface lo&lt;br /&gt;
  description LOOPBACKS&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf passive&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 passive&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf&lt;br /&gt;
  ospf router-id 172.16.0.6&lt;br /&gt;
  area 0.0.0.0 authentication message-digest&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf6&lt;br /&gt;
  ospf6 router-id 172.16.0.6&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart frr.service&lt;br /&gt;
Cheque se está tudo OK com o OSPF e verifique no PE se está recebendo os prefixos anunciados.&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL&lt;br /&gt;
 172.16.0.5     1 Full/-          10m49s            35.310s 172.16.0.5   ens18:172.16.0.6                  0     0     0&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri    DeadTime    State/IfState         Duration I/F[State]&lt;br /&gt;
 172.16.0.5       1    00:00:30     Full/PointToPoint 25d22:53:47 ens18[PointToPoint]&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor detail'&lt;br /&gt;
 &lt;br /&gt;
  Neighbor 172.16.0.5, interface address 172.16.0.5&lt;br /&gt;
     In the area 0.0.0.0 via interface ens18&lt;br /&gt;
     Neighbor priority is 1, State is Full/-, 5 state changes&lt;br /&gt;
     Most recent state change statistics:&lt;br /&gt;
       Progressive change 21w3d15h ago&lt;br /&gt;
     DR is 0.0.0.0, BDR is 0.0.0.0&lt;br /&gt;
     Options 18 *|-|-|EA|-|-|E|-&lt;br /&gt;
     Dead timer due in 34.685s&lt;br /&gt;
     Database Summary List 0&lt;br /&gt;
     Link State Request List 0&lt;br /&gt;
     Link State Retransmission List 0&lt;br /&gt;
     Thread Inactivity Timer on&lt;br /&gt;
     Thread Database Description Retransmision off&lt;br /&gt;
     Thread Link State Request Retransmission on&lt;br /&gt;
     Thread Link State Update Retransmission on&lt;br /&gt;
 &lt;br /&gt;
     Graceful restart Helper info:&lt;br /&gt;
       Graceful Restart HELPER Status : None&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor detail'&lt;br /&gt;
  Neighbor 172.16.0.5%ens18&lt;br /&gt;
     Area 0.0.0.0 via interface ens18 (ifindex 4)&lt;br /&gt;
     His IfIndex: 60 Link-local address: fe80::469b:c1ff:fed6:43ee&lt;br /&gt;
     State Full for a duration of 25d22:57:14&lt;br /&gt;
     His choice of DR/BDR 0.0.0.0/0.0.0.0, Priority 1&lt;br /&gt;
     DbDesc status: Master SeqNum: 0xb94b0000&lt;br /&gt;
     Summary-List: 0 LSAs&lt;br /&gt;
     Request-List: 0 LSAs&lt;br /&gt;
     Retrans-List: 0 LSAs&lt;br /&gt;
     0 Pending LSAs for DbDesc in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSReq in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSAck in Time 00:00:00 [thread off]&lt;br /&gt;
     Authentication header not present&lt;br /&gt;
&lt;br /&gt;
== Configurando o Unbound ==&lt;br /&gt;
Abaixo a configuração que usaremos nos servidores atentando para o detalhe do '''num-threads''', esse deve ter o valor igual ao número de CPUs do servidor.&lt;br /&gt;
&lt;br /&gt;
Também os IPs utilizados em '''outgoing-interface''' que serão diferentes em cada servidor, esses serão os IPs usados para '''recursividade'''. Consulte o manual do Unbound para obter mais informações sobre cada parâmetro listado na configuração.&lt;br /&gt;
&lt;br /&gt;
O tuning no Unbound pode ser alterado conforme abaixo:&lt;br /&gt;
 num-threads = nº CPUs&lt;br /&gt;
 so-reuseport = yes&lt;br /&gt;
 *-slabs = potência de 2 próximo ao num-threads&lt;br /&gt;
 msg-cache-size = 1g (quantidade de memória pra usar de cache)&lt;br /&gt;
 rrset-cache-size = 2 * msg-cache-size&lt;br /&gt;
 outgoing-range = 8192&lt;br /&gt;
 num-queries-per-thread = 4096&lt;br /&gt;
 so-rcvbuf e so-sndbuf = 4m ou 8m para servidores com muita requisição&lt;br /&gt;
Agora vamos criar nosso arquivo de configuração base em '''/etc/unbound/unbound.conf.d/local.conf''':&lt;br /&gt;
 server:&lt;br /&gt;
         verbosity: 1&lt;br /&gt;
         statistics-interval: 0&lt;br /&gt;
         statistics-cumulative: no&lt;br /&gt;
         extended-statistics: yes&lt;br /&gt;
         num-threads: 4&lt;br /&gt;
         serve-expired: yes&lt;br /&gt;
         interface: 127.0.0.1&lt;br /&gt;
         interface: 10.10.10.10&lt;br /&gt;
         interface: 10.10.9.9&lt;br /&gt;
         interface: 172.16.0.6&lt;br /&gt;
         interface: fc00::10:10:10:10&lt;br /&gt;
         interface: fc00::10:10:9:9&lt;br /&gt;
         interface: ::1&lt;br /&gt;
         interface-automatic: no&lt;br /&gt;
         outgoing-interface: 198.18.1.10&lt;br /&gt;
         outgoing-interface: 2001:db8::faca:198:18:1:10&lt;br /&gt;
         outgoing-range: 8192&lt;br /&gt;
         outgoing-num-tcp: 1024&lt;br /&gt;
         incoming-num-tcp: 2048&lt;br /&gt;
         so-rcvbuf: 4m&lt;br /&gt;
         so-sndbuf: 4m&lt;br /&gt;
         so-reuseport: yes&lt;br /&gt;
         edns-buffer-size: 1232&lt;br /&gt;
         msg-cache-size: 1g&lt;br /&gt;
         msg-cache-slabs: 4&lt;br /&gt;
         num-queries-per-thread: 4096&lt;br /&gt;
         rrset-cache-size: 2g&lt;br /&gt;
         rrset-cache-slabs: 4&lt;br /&gt;
         infra-cache-slabs: 4&lt;br /&gt;
         do-ip4: yes&lt;br /&gt;
         do-ip6: yes&lt;br /&gt;
         do-udp: yes&lt;br /&gt;
         do-tcp: yes&lt;br /&gt;
         chroot: &amp;quot;&amp;quot;&lt;br /&gt;
         username: &amp;quot;unbound&amp;quot;&lt;br /&gt;
         directory: &amp;quot;/etc/unbound&amp;quot;&lt;br /&gt;
         logfile: &amp;quot;/var/log/unbound/unbound.log&amp;quot;&lt;br /&gt;
         use-syslog: no&lt;br /&gt;
         log-time-ascii: yes&lt;br /&gt;
         log-queries: no&lt;br /&gt;
         pidfile: &amp;quot;/var/run/unbound.pid&amp;quot;&lt;br /&gt;
         root-hints: &amp;quot;/usr/share/dns/root.hints&amp;quot;&lt;br /&gt;
         hide-identity: yes&lt;br /&gt;
         hide-version: yes&lt;br /&gt;
         unwanted-reply-threshold: 10000000&lt;br /&gt;
         prefetch: yes&lt;br /&gt;
         prefetch-key: yes&lt;br /&gt;
         rrset-roundrobin: yes&lt;br /&gt;
         minimal-responses: yes&lt;br /&gt;
         module-config: &amp;quot;respip validator iterator&amp;quot;&lt;br /&gt;
         val-clean-additional: yes&lt;br /&gt;
         val-log-level: 1&lt;br /&gt;
         key-cache-slabs: 4&lt;br /&gt;
         deny-any: yes&lt;br /&gt;
         cache-min-ttl: 60&lt;br /&gt;
         key-cache-size: 128m&lt;br /&gt;
         neg-cache-size: 64m&lt;br /&gt;
         cache-max-ttl: 86400&lt;br /&gt;
         infra-cache-numhosts: 100000&lt;br /&gt;
         access-control: 198.18.0.0/22 allow&lt;br /&gt;
         access-control: 2001:db8::/32 allow&lt;br /&gt;
  &lt;br /&gt;
 rpz:&lt;br /&gt;
   name: rpz.block.host.local.zone&lt;br /&gt;
   zonefile: /etc/unbound/rpz.block.hosts.zone&lt;br /&gt;
   rpz-action-override: nxdomain&lt;br /&gt;
  &lt;br /&gt;
 python:&lt;br /&gt;
  &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;.&amp;quot;&lt;br /&gt;
     master: &amp;quot;b.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;c.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;d.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;f.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;g.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;k.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/root.zone&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;arpa.&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/arpa.zone&amp;quot;&lt;br /&gt;
No parâmetro '''interface''' colocamos os IPs que serão usados para consulta dos clientes como o '''10.10.10.10''', '''10.10.9.9, fc00::10:10:10:10 e fc00::10:10:9:9'''. Ali repare que coloquei também o IP privado '''172.16.0.6''', isso porque cada servidor terá o seu IP privado e este deve ser usado pelo seu sistema de monitoramento para checar cada servidor. No '''outgoing-interface''' teremos os IPs, tanto '''IPv4''' quanto '''IPv6''', para que seja feita a recursividade na Internet utilizando eles. Não tem '''IPv6''' ainda na sua rede? Dê uma olhada nesse artigo. Outro parâmetro importante é o '''access-control''' e é através dele que liberamos os prefixos IP para consultarem no nosso DNS Recursivo. No exemplo estou liberando todo o prefixo '''198.18.0.0/22''' e o prefixo '''2001:db8::/32'''. Além da ACL no Unbound, recomendo que crie um filtro de pacotes com iptables ou nftables protegendo seu sistema e liberando as portas '''53/UDP''', '''53/TCP,'''  '''443/TCP e 853/TCP''' apenas para seus clientes. Falarei sobre a '''443/TCP e 853/TCP''' mais para frente nessa mesma documentação.&lt;br /&gt;
&lt;br /&gt;
Agora criaremos o arquivo '''RPZ''' ('''Response Policy Zones'''). Esse arquivo contém os sites que serão bloqueados via '''&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; Recursivo'''. São aqueles sites que às vezes você recebe um Ofício da Justiça solicitando o bloqueio deles. Não entrarei no mérito da efetividade desses bloqueios, porque muitos de vocês sabem que tecnicamente, existem formas de se fazer um bypass através desses bloqueios. Contudo vamos deixar nosso ambiente preparado para esses bloqueios e por isso crie o arquivo '''/etc/unbound/rpz.block.hosts.zone''' com esse conteúdo de exemplo:&lt;br /&gt;
 $TTL 2h&lt;br /&gt;
 @ IN SOA localhost. root.localhost. (2 6h 1h 1w 2h)&lt;br /&gt;
   IN NS  localhost.&lt;br /&gt;
 ; RPZ manual block hosts&lt;br /&gt;
 *.josedascoves.com CNAME .&lt;br /&gt;
 josedascoves.com CNAME .&lt;br /&gt;
No exemplo acima estamos bloqueando qualquer consulta de DNS para '''josedascoves.com''' ou qualquer coisa '''.josedascoves.com'''.&lt;br /&gt;
&lt;br /&gt;
Para testar podemos fazer assim do próprio servidor:&lt;br /&gt;
 # host josedascoves.com ::1&lt;br /&gt;
 Using domain server:&lt;br /&gt;
 Name: ::1&lt;br /&gt;
 Address: ::1#53&lt;br /&gt;
 Aliases:&lt;br /&gt;
 &lt;br /&gt;
 Host josedascoves.com not found: 3(NXDOMAIN)&lt;br /&gt;
Se a resposta for '''NXDOMAIN''' então está funcionando o bloqueio. Para incluir novos bloqueios basta adicionar os domínios, um abaixo do outro, conforme o exemplo que coloquei no arquivo RPZ.&lt;br /&gt;
&lt;br /&gt;
== Acertando o resolv.conf ==&lt;br /&gt;
Vamos modificar nosso /etc/resolv.conf para utilizar DNS externo. Sim você deve estar se perguntando em qual situação isso seria utilizado. Primeiro entenda que o Unbound não irá utilizar o DNS externo para fazer as consultas na Internet e sim, qualquer teste que você faça do servidor precisará apontar para o Unbound usando os IPs '''127.0.0.1''' ou '''::1'''. Faremos isso pela seguinte situação: imagine que o daemon unbound morreu mas você ainda continua com conectividade na Internet. Você conseguiria acessar qualquer local na Internet através do IP mas não através do hostname porque não conseguiria resolver nomes, seu unbound estaria fora do ar. Imagine ainda que você gostaria que seu servidor te avisasse do problema via Telegram ou e-mail. Por isso estamos utilizando um DNS externo no '''/etc/resolv.conf''', apenas para essas situações. Se você não quiser utilizar desse recurso, pode usar o '''127.0.0.1''' e '''::1''' no lugar.&lt;br /&gt;
 nameserver 8.8.8.8&lt;br /&gt;
 nameserver 8.8.4.4&lt;br /&gt;
 nameserver 2001:4860:4860::8888&lt;br /&gt;
&lt;br /&gt;
== Script de teste de recursividade ==&lt;br /&gt;
Estamos montando uma '''Rede de DNS Recursivo Anycast''', então é muito importante que você monitore essa rede para saber se algum node morreu e iniciar o troubleshooting, resolver o problema e levantar o sistema novamente. Tudo isso é importante mas o cliente não deve ficar esperando até você resolver o problema, seu sistema precisa ser inteligente o suficiente para se remover da Rede quando tiver um problema e se inserir novamente, quando o problema estiver sido solucionado. Se você montar uma Rede de DNS e um dos nodes apresentar algum problema, todos os clientes atendidos por aquele node migrarão automaticamente e transparentemente para outro '''DNS Recursivo Anycast''' mais próximo. Isso se chama '''disponibilidade'''.&lt;br /&gt;
&lt;br /&gt;
O script '''/root/scripts/checa_dns.sh''' abaixo tem a função de fazer os testes de recursividade e checar se o daemon do unbound continua rodando. Se algo acontecer, ele para o anúncio do '''10.10.10.10''' e '''10.10.9.9''' e retorna eles quando tudo estiver resolvido.&lt;br /&gt;
 # mkdir /root/scripts&lt;br /&gt;
&lt;br /&gt;
 #!/usr/bin/env bash&lt;br /&gt;
 #Script para teste de DNS v2.1&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 #Informe um domínio por linha:&lt;br /&gt;
 dominios_testar=(&lt;br /&gt;
 www.google.com&lt;br /&gt;
 www.terra.com.br&lt;br /&gt;
 www.uol.com.br&lt;br /&gt;
 www.globo.com&lt;br /&gt;
 www.facebook.com&lt;br /&gt;
 www.youtube.com&lt;br /&gt;
 www.twitch.com&lt;br /&gt;
 www.discord.com&lt;br /&gt;
 www.debian.org&lt;br /&gt;
 www.redhat.com&lt;br /&gt;
 )&lt;br /&gt;
 corte_taxa_falha=100 #Porcentagem de falha para executar uma ação&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 remove_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; != &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no description' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME morreu!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 adiciona_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; == &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'description LOOPBACKS' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME retornou do inferno!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
 if [ $? -ne 0 ]; then&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME morreu DNS mas tentando levantar!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    systemctl restart unbound&lt;br /&gt;
    systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
    if [ $? -ne 0 ]; then&lt;br /&gt;
       remove_ospf&lt;br /&gt;
       exit&lt;br /&gt;
    fi&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME servico DNS voltou mas tinha morrido!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 qt_falhas=0&lt;br /&gt;
 qt_total=&amp;quot;${#dominios_testar[@]}&amp;quot;&lt;br /&gt;
 echo &amp;quot;total_dominios: $qt_total&amp;quot;&lt;br /&gt;
 for site in &amp;quot;${dominios_testar[@]}&amp;quot;&lt;br /&gt;
 do&lt;br /&gt;
   unbound-control flush $site &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   resolver=&amp;quot;127.0.0.1&amp;quot;&lt;br /&gt;
   echo -e &amp;quot; - dominio $site - $resolver - \c&amp;quot;&lt;br /&gt;
   host $site $resolver &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   if [ $? -ne 0 ]; then&lt;br /&gt;
      ((qt_falhas++))&lt;br /&gt;
      echo -e &amp;quot;[Falhou]&amp;quot;&lt;br /&gt;
   else&lt;br /&gt;
      echo -e &amp;quot;[OK]&amp;quot;&lt;br /&gt;
   fi&lt;br /&gt;
 done&lt;br /&gt;
  &lt;br /&gt;
 taxa_falha=$((qt_falhas*100/qt_total))&lt;br /&gt;
 echo &amp;quot;Falhas $qt_falhas/$qt_total ($taxa_falha%)&amp;quot;&lt;br /&gt;
  &lt;br /&gt;
 if [ &amp;quot;$taxa_falha&amp;quot; -ge &amp;quot;$corte_taxa_falha&amp;quot; ]; then&lt;br /&gt;
    remove_ospf&lt;br /&gt;
    exit&lt;br /&gt;
 fi&lt;br /&gt;
 adiciona_ospf&lt;br /&gt;
Se rodarmos o script manualmente veremos isto:&lt;br /&gt;
 # /root/scripts/checa_dns.sh&lt;br /&gt;
 total_dominios: 10&lt;br /&gt;
  - dominio www.google.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.terra.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.uol.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.globo.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.facebook.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.youtube.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.twitch.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.discord.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.debian.org - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.redhat.com - 127.0.0.1 - [OK]&lt;br /&gt;
 Falhas 0/10 (0%)&lt;br /&gt;
Se acontecer 100% de falhas o script irá remover os anúncios do OSPF. Se o daemon do unbound morrer, ele tentará reiniciá-lo. Se tudo normalizar o script irá retornar os anúncios para o OSPF. Deixei comentado no script as partes que enviariam uma notificação para o Telegram. Existem diversas documentações sobre isso na Internet, eu mesmo tenho uma. Assim que eu publicar aqui, atualizo essa documentação e sinta-se à vontade de modificar como desejar.&lt;br /&gt;
 # chmod 700 /root/scripts/checa_dns.sh&lt;br /&gt;
Adicione a linha abaixo em seu '''/etc/crontab''':&lt;br /&gt;
 */1 *   * * *   root    /root/scripts/checa_dns.sh&lt;br /&gt;
&lt;br /&gt;
== Habilitando o DoH (&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; over HTTPS) e DoT (DNS over TLS) - opcional ==&lt;br /&gt;
Para habilitar o '''DoH''' e o '''DoT''' no Unbound é bem simples. O recurso do '''DoH''' e '''DoT''' vem para trazer mais segurança e privacidade para o usuário. É um recurso muito pouco utilizado ainda mas que seu cliente pode vir a pedir algum dia.&lt;br /&gt;
&lt;br /&gt;
Você precisará gerar certificados SSL legítimos e para isso você poderá usar o '''Let's Encrypt''' só que de uma forma não tão convencional.&lt;br /&gt;
&lt;br /&gt;
Na sequência vamos instalar o Let's Encrypt para gerarmos nosso certificado SSL:&lt;br /&gt;
 # apt install letsencrypt&lt;br /&gt;
Escolha um '''hostname''' para ser usado no nosso '''DoH''' e aponte ele no seu DNS Autoritativo para seus IPs 10.10.10.10 e 10.10.9.9. Aqui vamos usar o seguinte como exemplo: '''doh.brasilpeeringforum.org'''. Para gerarmos nosso certificado iremos usar o tipo '''DNS-01''', ele não necessita que tenhamos um servidor web rodando no servidor e nem tão pouco levanta um serviço na porta 80 para checar o hostname. Ele utiliza o DNS como validador e vai te solicitar que crie um registro '''CNAME''' no seu '''DNS Autoritativo''' para provar que você tem o controle sobre aquele hostname. Antes disso vamos instalar um programa em Python para podermos automatizar nossa renovação de certificado no futuro. Esse programa se encontra '''[https://github.com/joohoi/acme-dns-certbot-joohoi/raw/master/acme-dns-auth.py aqui]''' mas vou deixá-lo abaixo já modificado o interpretador.&lt;br /&gt;
&lt;br /&gt;
Crie o arquivo '''/etc/letsencrypt/acme-dns-auth.py''' com o conteúdo abaixo:&lt;br /&gt;
 #!/usr/bin/env python3&lt;br /&gt;
 import json&lt;br /&gt;
 import os&lt;br /&gt;
 import requests&lt;br /&gt;
 import sys&lt;br /&gt;
 &lt;br /&gt;
 ### EDIT THESE: Configuration values ###&lt;br /&gt;
 &lt;br /&gt;
 # URL to acme-dns instance&lt;br /&gt;
 ACMEDNS_URL = &amp;quot;&amp;lt;nowiki&amp;gt;https://auth.acme-dns.io&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
 # Path for acme-dns credential storage&lt;br /&gt;
 STORAGE_PATH = &amp;quot;/etc/letsencrypt/acmedns.json&amp;quot;&lt;br /&gt;
 # Whitelist for address ranges to allow the updates from&lt;br /&gt;
 # Example: ALLOW_FROM = [&amp;quot;192.168.10.0/24&amp;quot;, &amp;quot;::1/128&amp;quot;]&lt;br /&gt;
 ALLOW_FROM = []&lt;br /&gt;
 # Force re-registration. Overwrites the already existing acme-dns accounts.&lt;br /&gt;
 FORCE_REGISTER = False&lt;br /&gt;
 &lt;br /&gt;
 ###   DO NOT EDIT BELOW THIS POINT   ###&lt;br /&gt;
 ###         HERE BE DRAGONS          ###&lt;br /&gt;
 &lt;br /&gt;
 DOMAIN = os.environ[&amp;quot;CERTBOT_DOMAIN&amp;quot;]&lt;br /&gt;
 if DOMAIN.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
     DOMAIN = DOMAIN[2:]&lt;br /&gt;
 VALIDATION_DOMAIN = &amp;quot;_acme-challenge.&amp;quot;+DOMAIN&lt;br /&gt;
 VALIDATION_TOKEN = os.environ[&amp;quot;CERTBOT_VALIDATION&amp;quot;]&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 class AcmeDnsClient(object):&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
     Handles the communication with ACME-DNS API&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
     def __init__(self, acmedns_url):&lt;br /&gt;
         self.acmedns_url = acmedns_url&lt;br /&gt;
 &lt;br /&gt;
     def register_account(self, allowfrom):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Registers a new ACME-DNS account&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
         if allowfrom:&lt;br /&gt;
             # Include whitelisted networks to the registration call&lt;br /&gt;
             reg_data = {&amp;quot;allowfrom&amp;quot;: allowfrom}&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;,&lt;br /&gt;
                                 data=json.dumps(reg_data))&lt;br /&gt;
         else:&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;)&lt;br /&gt;
         if res.status_code == 201:&lt;br /&gt;
             # The request was successful&lt;br /&gt;
             return res.json()&lt;br /&gt;
         else:&lt;br /&gt;
             # Encountered an error&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to register a new acme-dns &amp;quot;&lt;br /&gt;
                    &amp;quot;account. HTTP status {}, Response body: {}&amp;quot;)&lt;br /&gt;
             print(msg.format(res.status_code, res.text))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def update_txt_record(self, account, txt):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Updates the TXT challenge record to ACME-DNS subdomain.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         update = {&amp;quot;subdomain&amp;quot;: account['subdomain'], &amp;quot;txt&amp;quot;: txt}&lt;br /&gt;
         headers = {&amp;quot;X-Api-User&amp;quot;: account['username'],&lt;br /&gt;
                    &amp;quot;X-Api-Key&amp;quot;: account['password'],&lt;br /&gt;
                    &amp;quot;Content-Type&amp;quot;: &amp;quot;application/json&amp;quot;}&lt;br /&gt;
         res = requests.post(self.acmedns_url+&amp;quot;/update&amp;quot;,&lt;br /&gt;
                             headers=headers,&lt;br /&gt;
                             data=json.dumps(update))&lt;br /&gt;
         if res.status_code == 200:&lt;br /&gt;
             # Successful update&lt;br /&gt;
             return&lt;br /&gt;
         else:&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to update TXT record in &amp;quot;&lt;br /&gt;
                    &amp;quot;acme-dns. \n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request headers:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request body:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response HTTP status: {}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response body: {}&amp;quot;)&lt;br /&gt;
             s_headers = json.dumps(headers, indent=2, sort_keys=True)&lt;br /&gt;
             s_update = json.dumps(update, indent=2, sort_keys=True)&lt;br /&gt;
             s_body = json.dumps(res.json(), indent=2, sort_keys=True)&lt;br /&gt;
             print(msg.format(s_headers, s_update, res.status_code, s_body))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
 class Storage(object):&lt;br /&gt;
     def __init__(self, storagepath):&lt;br /&gt;
         self.storagepath = storagepath&lt;br /&gt;
         self._data = self.load()&lt;br /&gt;
 &lt;br /&gt;
     def load(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Reads the storage content from the disk to a dict structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         data = dict()&lt;br /&gt;
         filedata = &amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             with open(self.storagepath, 'r') as fh:&lt;br /&gt;
                 filedata = fh.read()&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             if os.path.isfile(self.storagepath):&lt;br /&gt;
                 # Only error out if file exists, but cannot be read&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage file exists but cannot be read&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         try:&lt;br /&gt;
             data = json.loads(filedata)&lt;br /&gt;
         except ValueError:&lt;br /&gt;
             if len(filedata) &amp;gt; 0:&lt;br /&gt;
                 # Storage file is corrupted&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage JSON is corrupted&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         return data&lt;br /&gt;
 &lt;br /&gt;
     def save(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Saves the storage content to disk&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         serialized = json.dumps(self._data)&lt;br /&gt;
         try:&lt;br /&gt;
             with os.fdopen(os.open(self.storagepath,&lt;br /&gt;
                                    os.O_WRONLY | os.O_CREAT, 0o600), 'w') as fh:&lt;br /&gt;
                 fh.truncate()&lt;br /&gt;
                 fh.write(serialized)&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             print(&amp;quot;ERROR: Could not write storage file.&amp;quot;)&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def put(self, key, value):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Puts the configuration value to storage and sanitize it&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         # If wildcard domain, remove the wildcard part as this will use the&lt;br /&gt;
         # same validation record name as the base domain&lt;br /&gt;
         if key.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
             key = key[2:]&lt;br /&gt;
         self._data[key] = value&lt;br /&gt;
 &lt;br /&gt;
     def fetch(self, key):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Gets configuration value from storage&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             return self._data[key]&lt;br /&gt;
         except KeyError:&lt;br /&gt;
             return None&lt;br /&gt;
 &lt;br /&gt;
 if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
     # Init&lt;br /&gt;
     client = AcmeDnsClient(ACMEDNS_URL)&lt;br /&gt;
     storage = Storage(STORAGE_PATH)&lt;br /&gt;
 &lt;br /&gt;
     # Check if an account already exists in storage&lt;br /&gt;
     account = storage.fetch(DOMAIN)&lt;br /&gt;
     if FORCE_REGISTER or not account:&lt;br /&gt;
         # Create and save the new account&lt;br /&gt;
         account = client.register_account(ALLOW_FROM)&lt;br /&gt;
         storage.put(DOMAIN, account)&lt;br /&gt;
         storage.save()&lt;br /&gt;
 &lt;br /&gt;
         # Display the notification for the user to update the main zone&lt;br /&gt;
         msg = &amp;quot;Please add the following CNAME record to your main DNS zone:\n{}&amp;quot;&lt;br /&gt;
         cname = &amp;quot;{} CNAME {}.&amp;quot;.format(VALIDATION_DOMAIN, account[&amp;quot;fulldomain&amp;quot;])&lt;br /&gt;
         print(msg.format(cname))&lt;br /&gt;
 &lt;br /&gt;
     # Update the TXT record in acme-dns instance&lt;br /&gt;
     client.update_txt_record(account, VALIDATION_TOKEN)&lt;br /&gt;
&lt;br /&gt;
 # chmod +x /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
Usaremos a seguinte instrução para criar nosso certificado:&lt;br /&gt;
 # certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d doh.brasilpeeringforum.org&lt;br /&gt;
 Saving debug log to /var/log/letsencrypt/letsencrypt.log&lt;br /&gt;
 Plugins selected: Authenticator manual, Installer None&lt;br /&gt;
 Cert is due for renewal, auto-renewing...&lt;br /&gt;
 Renewing an existing certificate for doh.brasilpeeringforum.org&lt;br /&gt;
 Performing the following challenges:&lt;br /&gt;
 dns-01 challenge for doh.brasilpeeringforum.org&lt;br /&gt;
 Running manual-auth-hook command: /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
 Output from manual-auth-hook command acme-dns-auth.py:&lt;br /&gt;
 Please add the following CNAME record to your main DNS zone:&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
 &lt;br /&gt;
 Waiting for verification...&lt;br /&gt;
 &lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Challenges loaded. Press continue to submit to CA. Pass &amp;quot;-v&amp;quot; for more info about&lt;br /&gt;
 challenges.&lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Press Enter to Continue&lt;br /&gt;
Nesse momento você cria o registro '''CNAME''' no seu DNS Autoritativo conforme ele solicitou: '''_acme-challenge.doh.brasilpeeringforum.org IN CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.''' e somente depois de criado e checado no DNS, você pressiona o '''Enter''' para continuar. Você pode checar dessa forma:&lt;br /&gt;
 # host -t cname _acme-challenge.doh.brasilpeeringforum.org&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org is an alias for b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
Para que nosso certificado seja automaticamente renovado colocaremos no '''/etc/crontab''' a seguinte linha abaixo:&lt;br /&gt;
 00 00   1 * *   root    /usr/bin/certbot -q renew&lt;br /&gt;
Acima temos a instrução para renovação automática do certificado. Repare que você vai precisar também copiar esse certificado para seus outros servidores, escolha um servidor para manter o certificado sempre atualizado e crie um script que faça a mesma cópia remotamente para os outros servidores. O '''scp''' e o '''rsync''' são seus aliados nisso.&lt;br /&gt;
&lt;br /&gt;
=== Configurando o Unbound ===&lt;br /&gt;
Em nosso '''/etc/unbound/unbound.conf.d/local.conf''', adicionaremos no bloco &amp;quot;'''server:'''&amp;quot; o seguinte:&lt;br /&gt;
 interface: 10.10.10.10@443 &lt;br /&gt;
 interface: 10.10.9.9@443&lt;br /&gt;
 interface: fc00::10:10:10:10@443&lt;br /&gt;
 interface: fc00::10:10:9:9@443&lt;br /&gt;
 interface: 10.10.10.10@853 &lt;br /&gt;
 interface: 10.10.9.9@853&lt;br /&gt;
 interface: fc00::10:10:10:10@853&lt;br /&gt;
 interface: fc00::10:10:9:9@853&lt;br /&gt;
 tls-service-key: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/privkey.pem&amp;quot; &lt;br /&gt;
 tls-service-pem: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/fullchain.pem&amp;quot;&lt;br /&gt;
Para usar o recurso do '''DoH''' você precisará habilitar o recurso no seu navegador e informar a URL. Vou colocar o exemplo do '''Google Chrome''': Digite '''chrome://settings/security?search=dns''' no seu Chrome e ative '''Usar DNS seguro''', selecione '''Personalizado''' e adicione nossa URL:&lt;br /&gt;
[[Arquivo:Doh bpf2.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Finalizando ==&lt;br /&gt;
Aqui finalizamos nosso projeto para uma Rede de DNS(s) Recursivos Anycast com Hyperlocal. Esse projeto é escalável, seguro, resiliente e você entregará muito mais qualidade de Internet para o seu cliente. Pare de entregar o '''8.8.8.8''' para os seus clientes, você está contribuindo para uma Internet mais lenta, sem a qualidade que o seu cliente merece. Investi meu tempo, que é muito pouco, para deixar esse documento para a comunidade, para você melhorar o seu ISP, para dar um UP! nele, então vamos começar 2023 com o pé direito. O que acha?&lt;br /&gt;
&lt;br /&gt;
Como prova de conceito, uma imagem abaixo onde temos uma Rede em produção de DNS(s) Recursivos Anycast e apontando exatamente o momento em que houve alguma situação que fez com que as queries de DNS, convergissem de um node para outro, de forma transparente e automática para o cliente. Podemos notar também que ao ser resolvido o problema, o tráfego retornou para o seu node correto:&lt;br /&gt;
[[Arquivo:Convergencia.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== KINDNS (Stands for Knowledge-Sharing and Instantiating Norms for DNS and Naming Security) ==&lt;br /&gt;
Achou que havia terminado? Agora que você tem a capacidade de montar uma '''Rede de DNS Recursivo''' com todas essas features acima, com todas as ferramentas que foram comentadas, o que acha de certificar o que fez?&lt;br /&gt;
&lt;br /&gt;
Assim como o [https://www.manrs.org/ MANRS] veio para certificar nosso sistema de roteamento na Internet, agora temos o [https://kindns.org/ KINDNS] para certificar que nossos sistemas de DNS estão bem feitos e dentro dos padrões de segurança. Existem '''7 ações''' que podem ser certificadas para nossos DNS Recursivos e estão aqui em https://kindns.org/shared-private-resolvers/. Com essa nossa documentação, se bem aplicada, você pode se candidatar ao KINDNS e ter seu ASN listado aqui https://kindns.org/participants/&lt;br /&gt;
&lt;br /&gt;
Obter e manter o '''MANRS''' e '''KINDNS''' demonstra seu compromisso com as Boas Práticas, contribui para termos uma '''Internet''' mais segura e te abre portas para novos negócios que possam exigir essas conformidades.&lt;br /&gt;
&lt;br /&gt;
Autor: [[Usuário:Gondim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Infraestrutura]]&lt;br /&gt;
__FORCARTDC__&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3926</id>
		<title>DNS Recursivo Anycast Hyperlocal</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3926"/>
		<updated>2025-07-19T20:23:42Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
==Introdução==&lt;br /&gt;
Você sabe como funciona a Internet? Essa é uma pergunta que meu amigo '''Thiago Ayub''' sempre faz aos seus candidatos à vagas de emprego e não importa o quanto tenham de experiência em '''Engenharia de Redes''', todos sempre travam nesse momento. Todos estão sempre prontos e preparados para resolver os problemas mais cabeludos em '''BGP''', '''OSPF''', '''MPLS''', etc mas travam com essa simples pergunta. Para contextualizar e visualizarmos melhor vamos nos atentar à imagem abaixo e uma explicação simplificada de como funciona:&lt;br /&gt;
[[Arquivo:Dns hierarquia.png|esquerda|commoldura]]&lt;br /&gt;
Tudo começa com um usuário sentado confortavelmente e querendo acessar um conteúdo disponível na Internet. Ele digita em seu navegador preferido a URL: '''&amp;lt;nowiki&amp;gt;https://wiki.brasilpeeringforum.org&amp;lt;/nowiki&amp;gt;''',&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;1)&amp;lt;/big&amp;gt;''' &amp;lt;big&amp;gt;O&amp;lt;/big&amp;gt; &amp;lt;big&amp;gt;navegador irá requisitar do '''DNS Recursivo''' utilizado pelo usuário, o '''endereço IP''' que responde pelo nome '''wiki.'''&amp;lt;/big&amp;gt;'''brasilpeeringforum.org'''&amp;lt;big&amp;gt;. Isso porque todos os acessos se dão na Internet através do '''endereço''' '''IP''' e não através do '''nome'''. Imaginem se tivéssemos que decorar os endereços IPs de todos os sites e serviços que quiséssemos acessar na Internet?&amp;lt;/big&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;big&amp;gt;'''2)''' Nosso DNS Recursivo checa se a informação consta em seu cache.&amp;lt;/big&amp;gt; Se a informação existir ela é devolvida ao navegador do usuário e aí este consegue acessar o site.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Do contrário o DNS Recursivo pergunta ao '''Root Server''' quem é o '''TLD (Top Level Domain)''' responsável para atender a requisição. &lt;br /&gt;
&lt;br /&gt;
'''4)''' O '''Root Server''' informa ao DNS Recursivo o endereço do '''TLD responsável'''. No Brasil o '''TLD''' responsável pelo '''.br''' seria o '''Registro.br'''.&lt;br /&gt;
&lt;br /&gt;
'''5)''' O DNS Recursivo pergunta ao '''TLD''' sobre '''wiki.brasilpeeringforum.org''' e este responde com os endereços IP dos '''DNS Autoritativos''' responsáveis pelo domínio '''brasilpeeringforum.org.'''&lt;br /&gt;
&lt;br /&gt;
'''6)''' O DNS Recursivo pergunta aos '''DNS Autoritativos''' pelo '''wiki.brasilpeeringforum.org''' e este responde com o '''endereço IP'''.&lt;br /&gt;
&lt;br /&gt;
'''7)''' Por último o DNS Recursivo devolve a informação para o navegador do usuário.&lt;br /&gt;
&lt;br /&gt;
Como que se dá a comunicação entre os '''DNS(s) Recursivos, Root Servers, TLDs''' e '''Autoritativos'''? Como que o navegador do usuário, após receber o IP do site, consegue chegar no servidor que tem o conteúdo? Isso só é possível devido ao protocolo chamado '''BGP (Border Gateway Protocol)''', todos os caminhos que conhecemos como rotas de destino, são anunciadas por milhares de participantes na '''Internet''' conhecidos como '''AS (Autonomous System)''', esses participantes se interligam para disponibilizar conteúdos e acessos pelo mundo aos milhares de usuários. É uma imensa rede colaborativa formada por Empresas, Universidades, Governos e todos que queiram se interconectar. Percebam que sem o '''BGP''', que serve de caminho para chegarmos nos conteúdos e sem o '''DNS (Domain Name System)''' para traduzir o nome para o endereço IP, a '''Internet''' não funcionaria e por isso precisamos cuidar muito bem desses dois serviços.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Mas não acaba por aí. O '''DNS Recursivo''' tem um papel muito importante para o Provedor de Internet e que envolve segurança, qualidade de acesso à Internet e a disponibilidade do serviço entregue ao cliente. Quando bem configurado acelera as consultas dos acessos graças ao seu cache interno, mas para que isso seja percebido pelo assinante, é necessário que esteja o mais próximo possível do seu cliente.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Um erro que destrói a qualidade do nosso serviço ==&lt;br /&gt;
Um erro muito comum que muitas operadoras cometem é utilizar DNS Recursivo externo, como o '''8.8.8.8''', '''1.1.1.1''' e outros, para seus clientes. Quanto mais próximo dos seus clientes, mais qualidade de serviço estará entregando a eles. Conteúdos serão entregues mais rapidamente pois serão resolvidos e armazenados em caches locais e não consultados remotamente na Internet. Para falar mais sobre isso, te convido leitor desse documento, que assista essa palestra do '''Thiago Ayub''' no '''GTER 51/GTS 37''' (2022) '''8.888 MOTIVOS PARA NÃO USAR DNS RECURSIVO EXTERNO EM SEU AS''': https://www.youtube.com/watch?v=Rsvpu5uF2Io&lt;br /&gt;
&lt;br /&gt;
== Objetivo ==&lt;br /&gt;
O objetivo desta documentação não é te ensinar tudo sobre '''DNS''', '''BGP''', '''OSPF''' e nem tão pouco sobre GNU/Linux e sim te mostrar um exemplo de servidor DNS Recursivo implementado pensando em segurança, qualidade e resiliência. Usaremos em todas as nossas documentações o [https://www.debian.org/ Debian GNU/Linux], por ser uma distribuição que considero uma obra de arte criada por uma enorme comunidade séria, com vasta experiência de anos, qualidade no empacotamento dos programas, estável e com uma equipe de segurança excelente e ativa. Caso você leitor, utilize alguma outra distribuição GNU/Linux, todo conteúdo apresentado aqui pode ser aplicado em outras distros, desde que respeitando as particularidades de cada uma.&lt;br /&gt;
&lt;br /&gt;
Aqui construiremos um sistema do tipo '''Anycast''', ou seja, terás o serviço rodando em diversas localidades da sua Rede utilizando o mesmo endereçamento IP e que atenderá seu cliente mais próximo. Em caso de falhas, seus clientes automaticamente e de forma transparente continuarão consultando o DNS mais próximo deles. Para que ele funcione dessa forma você precisará ter uma '''Rede OSPF''' implementada no seu Provedor Internet ou algum outro protocolo como por exemplo o '''ISIS,''' mas esse documento não irá abordar o '''ISIS'''. Também utilizaremos o '''Hyperlocal''' como recurso adicional para gerar algumas proteções de segurança e velocidade na resposta relacionada aos servidores de DNS Raiz da Internet.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
Para exemplificar nosso servidor de DNS Recursivo, usaremos como base das explicações um diagrama demonstrando o uso do DNS Recursivo em uma Rede fictícia. Adotaremos IPs privados e reservados para demonstrar todo o ambiente do Provedor de Internet.&lt;br /&gt;
[[Arquivo:Diagrama dns recursiv2.png|alt=|esquerda|miniaturadaimagem|695x695px]]&lt;br /&gt;
Nesse diagrama podemos observar alguns detalhes técnicos como por exemplo: existem '''3 servidores de DNS Recursivo''' posicionados em locais diferentes, que poderiam estar em bairros diferentes e até em cidades diferentes. Em cada servidor teremos '''2 loopbacks''' com os IPs:&lt;br /&gt;
&lt;br /&gt;
'''10.10.10.10/32 - fc00::10:10:10:10/128'''&lt;br /&gt;
&lt;br /&gt;
'''10.10.9.9/32 - fc00::10:10:9:9/128'''&lt;br /&gt;
&lt;br /&gt;
Esses IPs serão entregues pelos concentradores '''PPPoE''' ou '''IPoE''' ('''BNG''') para seus clientes como '''DNS primário''' e '''secundário'''. Podemos usar IPs privados como DNS primário e secundário em um ambiente real? Sim podemos, desde que não sejam IPs que possam ter problemas com as redes privadas dos clientes. Ex.: rede do cliente usando '''192.168.0.0/24'''. Se entregarmos o DNS sendo '''192.168.0.10''' e '''192.168.0.20''' teremos problemas e o cliente ficará sem Internet, porque '''192.168.0.10''' e '''192.168.0.20''' fazem parte da rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
Agora entregando '''10.10.10.10,''' '''10.10.9.9, fc00::10:10:10:10 e fc00::10:10:9:9''' não teríamos problemas com a rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
'''Motivos para usarmos IPs privados:'''&lt;br /&gt;
* O principal motivo está relacionado com a segurança, uma vez que sendo um IP privado, não pode sofrer ataques DDoS direcionados diretamente para ele, vindos da Internet.&lt;br /&gt;
* Nem mesmo o cliente da sua rede conhece os '''IPs públicos''' utilizados para recursividade na Internet.&lt;br /&gt;
* Memorizar os IPs '''10.10.10.10''' e '''10.10.9.9''' é tão fácil quanto memorizar o '''8.8.8.8''' e o '''1.1.1.1'''. Mais fácil para o seu técnico guardar essa informação e utilizar onde for necessário.&lt;br /&gt;
Cada servidor DNS Recursivo possui um '''IPv4 público''', aqui representado por '''198.18.x.x/27''' e um '''IPv6 global''' representado por um IP dentro do prefixo '''2001:db8::/32'''. Cada servidor precisa ter os seus próprios IPs e são através destes IPs que as consultas de DNS serão realizadas na Internet.&lt;br /&gt;
&lt;br /&gt;
Nessa topologia usando '''Anycast''', o cliente será sempre atendido pelo '''DNS Recursivo''' mais próximo, desde que os pesos no '''OSPF''' estejam ajustados corretamente.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
== Dados do servidor ==&lt;br /&gt;
Podemos utilizar um sistema virtualizado ou não. Sistemas virtualizados são bem vindos pois são mais simples quando precisamos fazer backups, levantar outros sistemas sem complicações e se precisarmos restaurar rapidamente algum sistema que ficou indisponível por algum motivo. A configuração abaixo tem capacidade para atender algo em torno a '''50.000 assinantes ou mais'''. O DNS Recursivo é um serviço que pode ser utilizado até mesmo em um '''Raspberry Pi''' e atender operações pequenas, nesse caso com o intuito de economizar energia e espaço. Nosso foco aqui é montar uma rede de '''DNS Recursivo Anycast com HyperLocal'''. Como comentei acima o servidor deve ficar o mais próximo dos clientes para termos a '''menor latência possível''' e '''sempre menor que 5ms''' entre o cliente e o servidor.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!CPU&lt;br /&gt;
!Memória&lt;br /&gt;
!Disco&lt;br /&gt;
!Sistema&lt;br /&gt;
|-&lt;br /&gt;
|2.4Ghz 4 cores&lt;br /&gt;
|16G DDR4&lt;br /&gt;
|30G&lt;br /&gt;
|Debian 12 amd64 (Bookworm)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Softwares utilizados ==&lt;br /&gt;
* Debian 12 amd64 (Bookworm) instalação mínima.&lt;br /&gt;
&lt;br /&gt;
* [https://frrouting.org/ FRRouting].&lt;br /&gt;
* Unbound.&lt;br /&gt;
* IRQBalance.&lt;br /&gt;
* Chrony (NTP/NTS).&lt;br /&gt;
* Shell script em bash.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades que teremos ==&lt;br /&gt;
* Sistema em Anycast.&lt;br /&gt;
* Hyperlocal.&lt;br /&gt;
* Controle de acesso por &amp;lt;abbr&amp;gt;ACL&amp;lt;/abbr&amp;gt;.&lt;br /&gt;
* RPZ (Response Policy Zone).&lt;br /&gt;
* Bloqueio de consultas do tipo ANY.&lt;br /&gt;
* QNAME minimization habilitado. (habilitado por default no Unbound)&lt;br /&gt;
* Recursividade em IPv4 e IPv6.&lt;br /&gt;
* DNSSEC habilitado.&lt;br /&gt;
* &amp;lt;abbr&amp;gt;DoH (DNS&amp;lt;/abbr&amp;gt; over HTTPS) habilitado.&lt;br /&gt;
&lt;br /&gt;
== Monitoramento ==&lt;br /&gt;
O monitoramento é algo bem específico e não é o foco deste documento mas é extremamente importante que você monitore seus servidores de DNS por alguma ferramenta como o Zabbix. Aqui mostrarei apenas como enviar as informações para o Zabbix. Algumas coisas que você deveria monitorar nos servidores de DNS Recursivo:&lt;br /&gt;
* Serviço do unbound parou.&lt;br /&gt;
* Perda de pacotes.&lt;br /&gt;
* Latência alta de pacotes.&lt;br /&gt;
* Lentidão na resolução de queries.&lt;br /&gt;
* CPU alta.&lt;br /&gt;
* Load alto.&lt;br /&gt;
* Memória com uso alto.&lt;br /&gt;
* Disco com pouco espaço.&lt;br /&gt;
* Queda brusca nas queries.&lt;br /&gt;
* A recursividade parou de funcionar.&lt;br /&gt;
* A recursividade voltou a funcionar.&lt;br /&gt;
Este abaixo é um exemplo de monitoramento de um sistema de DNS Recursivo que atende 50.000 assinantes:&lt;br /&gt;
[[Arquivo:Grafana dns.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Configurando a Rede ==&lt;br /&gt;
Nossa documentação será baseada no diagrama apresentado acima e por isso configuraremos apenas um dos três servidores, porque os outros serão configurados da mesma forma, só que com dados diferentes. Para tanto assumirei que já temos um sistema Debian instalado com o mínimo de pacotes e somente com sshd, para que possamos acessar remotamente mais tarde. '''Não instale um ambiente gráfico no servidor''', você não deve querer fazer isso por diversos motivos e os principais: primeiro porque não é um Desktop e segundo porque o ambiente gráfico devoraria toda a memória com recursos que não seriam úteis aqui.&lt;br /&gt;
&lt;br /&gt;
Em '''/etc/network/interfaces''' deixaremos assim:&lt;br /&gt;
 # This file describes the network interfaces available on your system&lt;br /&gt;
 # and how to activate them. For more information, see interfaces(5).&lt;br /&gt;
  &lt;br /&gt;
 source /etc/network/interfaces.d/*&lt;br /&gt;
  &lt;br /&gt;
 # The loopback network interface&lt;br /&gt;
 auto lo&lt;br /&gt;
 iface lo inet loopback&lt;br /&gt;
  &lt;br /&gt;
 auto lo:0&lt;br /&gt;
 iface lo:0 inet static&lt;br /&gt;
       address 10.10.10.10/32&lt;br /&gt;
  &lt;br /&gt;
 auto lo:1&lt;br /&gt;
 iface lo:1 inet static&lt;br /&gt;
       address 10.10.9.9/32&lt;br /&gt;
 &lt;br /&gt;
 auto lo:2&lt;br /&gt;
 iface lo:2 inet6 static&lt;br /&gt;
       address fc00::10:10:10:10/128&lt;br /&gt;
 &lt;br /&gt;
 auto lo:3&lt;br /&gt;
 iface lo:3 inet6 static&lt;br /&gt;
       address fc00::10:10:9:9/128&lt;br /&gt;
  &lt;br /&gt;
 # The primary network interface&lt;br /&gt;
 auto ens18&lt;br /&gt;
 iface ens18 inet static&lt;br /&gt;
         address 198.18.1.10/27&lt;br /&gt;
         gateway 198.18.1.1&lt;br /&gt;
  &lt;br /&gt;
 iface ens18 inet6 static&lt;br /&gt;
         address 2001:db8::faca:198:18:1:10/64&lt;br /&gt;
         gateway 2001:db8::faca:198:18:1:1&lt;br /&gt;
  &lt;br /&gt;
 # The secondary network interface&lt;br /&gt;
 auto ens18:0&lt;br /&gt;
 iface ens18:0 inet static&lt;br /&gt;
         address 172.16.0.6/30&lt;br /&gt;
Nesse cenário temos as duas '''loopbacks''' com os IPs '''10.10.10.10''', '''10.10.9.9, fc00::10:10:10:10''' e '''fc00::10:10:9:9''' que serão anunciados via OSPF para a rede e serem entregues aos clientes via BNG. Os IPs '''198.18.1.10''' e '''2001:db8::faca:198:18:1:10''' serão usados para fazerem a recursividade na Internet tanto em IPv4 quanto em IPv6. Esses IPs não devem ser divulgados para clientes; os IPs públicos são dedicados apenas para essa finalidade.&lt;br /&gt;
&lt;br /&gt;
== Configuração dos repositórios Debian ==&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list''' conforme abaixo:&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://security.debian.org/debian-security&amp;lt;/nowiki&amp;gt; bookworm-security main contrib non-free non-free-firmware&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian&amp;lt;/nowiki&amp;gt; bookworm main contrib non-free non-free-firmware&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian&amp;lt;/nowiki&amp;gt; bookworm-updates main contrib non-free non-free-firmware&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian&amp;lt;/nowiki&amp;gt; bookworm-backports main contrib non-free non-free-firmware&lt;br /&gt;
Após a configuração vamos instalar alguns pacotes necessários e outros úteis:&lt;br /&gt;
 # apt update &amp;amp;&amp;amp; apt full-upgrade&lt;br /&gt;
 # apt install net-tools nftables htop iotop sipcalc tcpdump curl gnupg rsync wget host dnsutils mtr-tiny bmon sudo tmux whois ethtool dnstop&lt;br /&gt;
&lt;br /&gt;
== Fazendo algum tuning no sistema ==&lt;br /&gt;
Em '''/etc/sysctl.conf''' adicionamos no final do arquivo essas instruções:&lt;br /&gt;
 net.core.rmem_max = 2147483647&lt;br /&gt;
 net.core.wmem_max = 2147483647&lt;br /&gt;
 net.ipv4.tcp_rmem = 4096 87380 2147483647&lt;br /&gt;
 net.ipv4.tcp_wmem = 4096 65536 2147483647&lt;br /&gt;
 net.netfilter.nf_conntrack_buckets = 512000&lt;br /&gt;
 net.netfilter.nf_conntrack_max = 4096000&lt;br /&gt;
 vm.swappiness=10&lt;br /&gt;
Estamos fazendo algumas melhorias de memória, algumas relacionadas a '''conntrack''' porque se for usar um filtro de pacotes stateful, como o '''Netfilter/IPTables''' ou '''Netfilter/NFTables''', o valor default da tabela é pequeno e dependendo da situação, se estourar essa tabela, as consultas de DNS terão problemas também. O DNS Recursivo não deve ficar aberto para qualquer um na Internet, ele deve ser liberado apenas para seus clientes. Podemos fazer através das ACLs do Unbound e pelo filtro de pacotes. O último parâmetro diz respeito ao uso de swap, por padrão o Debian permite o uso de swap após 40% do uso da memória, nesse caso estamos dizendo para o sistema usar o swap com 90% de uso da memória.&lt;br /&gt;
&lt;br /&gt;
Precisamos adicionar o módulo '''nf_conntrack''' em '''/etc/modules''' para que seja carregado em tempo de boot, senão os parâmetros de '''conntrack''' que colocamos em '''/etc/sysctl.conf''' não serão carregados.&lt;br /&gt;
 # echo nf_conntrack &amp;gt;&amp;gt; /etc/modules&lt;br /&gt;
 # modprobe nf_conntrack&lt;br /&gt;
 # sysctl -p&lt;br /&gt;
&lt;br /&gt;
== Instalando o FRRouting ==&lt;br /&gt;
O FRRouting é o programa que usaremos para fazer os anúncios das nossas loopbacks via OSPF. Nesse documento usaremos a versão 10.x e para isso precisaremos configurar o repositório oficial do FRRouting e instalar os pacotes:&lt;br /&gt;
 # curl -s &amp;lt;nowiki&amp;gt;https://deb.frrouting.org/frr/keys.gpg&amp;lt;/nowiki&amp;gt; | tee /usr/share/keyrings/frrouting.gpg &amp;gt; /dev/null&lt;br /&gt;
 # echo &amp;quot;deb [signed-by=/usr/share/keyrings/frrouting.gpg] &amp;lt;nowiki&amp;gt;https://deb.frrouting.org/frr&amp;lt;/nowiki&amp;gt; bookworm frr-10&amp;quot; &amp;gt; /etc/apt/sources.list.d/frr.list&lt;br /&gt;
 # apt update&lt;br /&gt;
 # apt install frr frr-doc frr-pythontools&lt;br /&gt;
Aconselho depois de instalar os pacotes, marcá-los para não atualizar juntamente com os demais pacotes, isso é para evitar de ocorrer alguma atualização no FRRouting, que torne o serviço instável por algum motivo. Não que isso vá ocorrer, mas é melhor fazer essa atualização quando realmente for necessário.&lt;br /&gt;
 # apt-mark hold frr frr-doc frr-pythontools&lt;br /&gt;
Após esse comando acima, o sistema manterá a instalação original do pacote intacta. Para desbloquear basta executar o comando abaixo:&lt;br /&gt;
 # apt-mark unhold frr frr-doc frr-pythontools&lt;br /&gt;
&lt;br /&gt;
== Removendo o APPARMOR ==&lt;br /&gt;
O '''APPARMOR''' às vezes causa mais problemas que solução e se não for fazer uma completa configuração nele, é melhor desabilitá-lo. Para fazer isso efetivamente, o procedimento é esse abaixo:&lt;br /&gt;
 # mkdir -p /etc/default/grub.d&lt;br /&gt;
 # echo 'GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;$GRUB_CMDLINE_LINUX_DEFAULT apparmor=0&amp;quot;' | tee /etc/default/grub.d/apparmor.cfg&lt;br /&gt;
 # update-grub&lt;br /&gt;
 # reboot&lt;br /&gt;
&lt;br /&gt;
== Instalando o Unbound ==&lt;br /&gt;
Nesse momento ainda não iremos configurar o Unbound, apenas instalar o pacote e acertar o ambiente. Vamos instalar o unbound do backports porque este já possui suporte ao DoH que veremos mais à frente.&lt;br /&gt;
 # apt install unbound dns-root-data&lt;br /&gt;
 # mkdir -p /var/log/unbound&lt;br /&gt;
 # touch /var/log/unbound/unbound.log&lt;br /&gt;
 # chown -R unbound:unbound /var/log/unbound/&lt;br /&gt;
 # systemctl restart unbound&lt;br /&gt;
Configurando o logrotate:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/logrotate.d/unbound&lt;br /&gt;
 /var/log/unbound/unbound.log {&lt;br /&gt;
     rotate 5&lt;br /&gt;
     weekly&lt;br /&gt;
     postrotate&lt;br /&gt;
         unbound-control log_reopen&lt;br /&gt;
     endscript&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
Reiniciando o serviço:&lt;br /&gt;
 # systemctl restart logrotate.service&lt;br /&gt;
&lt;br /&gt;
== Desabilitando THP (Transparente Huge Pages) em arquitetura AMD64 ==&lt;br /&gt;
No Debian o '''THP''' vem habilitado como '''always''' e o '''unbound''' por trabalhar bastante com alterações do cache em memória, isso pode acabar causando um consumo crescente de uso de RAM sem necessidade. É uma boa prática desabilitá-lo com os passos abaixo:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/systemd/system/disable-thp.service&lt;br /&gt;
 [Unit]&lt;br /&gt;
 Description=Desativa Transparent Huge Pages (THP)&lt;br /&gt;
 After=network.target&lt;br /&gt;
 &lt;br /&gt;
 [Service]&lt;br /&gt;
 Type=oneshot&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled&amp;quot;&lt;br /&gt;
 ExecStart=/bin/sh -c &amp;quot;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/defrag&amp;quot;&lt;br /&gt;
 RemainAfterExit=yes&lt;br /&gt;
 &lt;br /&gt;
 [Install]&lt;br /&gt;
 WantedBy=multi-user.target&lt;br /&gt;
 EOF&lt;br /&gt;
Acima configuramos o serviço '''disable-thp.service''' para desabilitar o '''THP''' e abaixo habilitamos no '''systemd''' e iniciamos:&lt;br /&gt;
 # systemctl daemon-reload&lt;br /&gt;
 # systemctl enable --now disable-thp&lt;br /&gt;
&lt;br /&gt;
== Preparando o monitoramento do seu DNS Recursivo ==&lt;br /&gt;
O monitoramento do seu DNS Recursivo é muito importante e para isso vamos usar um '''template para Zabbix''', que modifiquei juntamente com o seu shell script e que enviará os dados para o seu Zabbix server via '''zabbix-sender'''. O projeto original está aqui '''https://github.com/jeftedelima/Unbound-DNS&amp;lt;nowiki/&amp;gt;.''' O xml alterado está aqui '''https://github.com/gondimcodes/template_zabbix_dns_unbound'''. Embora seja antigo é perfeitamente importável no Zabbix 6.0, por exemplo.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;nowiki/&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Teremos um shell script que você precisará colocar no seu '''/etc/crontab'''. No exemplo abaixo assumi que o shell script está em '''/root/scripts'''. De 5 em 5 minutos os dados serão enviados para o seu Zabbix server.&lt;br /&gt;
 */5 * * * *     root    /root/scripts/unboundSend.sh '''IP_zabbix_server''' '''nome_do_host''' 1&amp;gt; /dev/null&lt;br /&gt;
Na linha acima, troque o '''IP_zabbix_server''' pelo '''IP do seu servidor Zabbix''' e o '''nome_do_host''' pelo '''hostname''' '''do seu DNS Recursivo'''. Você precisará instalar o pacote '''zabbix-sender''' no seu DNS Recursivo pois ele será usado para enviar os dados para o Zabbix server.&lt;br /&gt;
&lt;br /&gt;
Abaixo o '''unboundSend.sh''' também alterado com inclusão de mais dados:&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 #       @Jefte de Lima Ferreira&lt;br /&gt;
 #       jeftedelima at gmail dot com&lt;br /&gt;
 #       CRON Example&lt;br /&gt;
 #       Contributor: Marcelo Gondim - gondim at gmail dot com&lt;br /&gt;
 #       */5   **** root sh /home/dir/unboundSend.sh 192.168.10.1 Unbound 1&amp;gt; /dev/null&lt;br /&gt;
 &lt;br /&gt;
 if [ -z ${1} ] || [ -z ${2} ] ; then&lt;br /&gt;
         echo &amp;quot;You need to specify the IP address of zabbix server and hostname of your DNS Unbound on zabbix&amp;quot;&lt;br /&gt;
         echo &amp;quot;Usage example: ./unboundSend.sh 192.168.10.1 UnboundServer&amp;quot;&lt;br /&gt;
         exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
 # ZABBIX_SERVER IP&lt;br /&gt;
 IP_ZABBIX=$1&lt;br /&gt;
 # NAME Unbound on Zabbix&lt;br /&gt;
 NAME_HOST=$2&lt;br /&gt;
 DIR_TEMP=/var/tmp/&lt;br /&gt;
 FILE=&amp;quot;${DIR_TEMP}dump_unbound_control_stats.txt&amp;quot;&lt;br /&gt;
 unbound-control stats &amp;gt; ${FILE}&lt;br /&gt;
 &lt;br /&gt;
 TOTAL_NUM_QUERIES=$(cat ${FILE} | grep -w 'total.num.queries' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEHITS=$(cat ${FILE} | grep -w 'total.num.cachehits' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEMISS=$(cat ${FILE} | grep -w 'total.num.cachemiss' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_PREFETCH=$(cat ${FILE} | grep -w 'total.num.prefetch' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_RECURSIVEREPLIES=$(cat ${FILE} | grep -w 'total.num.recursivereplies' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 TOTAL_REQ_MAX=$(cat ${FILE} | grep -w 'total.requestlist.max' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_AVG=$(cat ${FILE} | grep -w 'total.requestlist.avg' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_OVERWRITTEN=$(cat ${FILE} | grep -w 'total.requestlist.overwritten' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_EXCEEDED=$(cat ${FILE} | grep -w 'total.requestlist.exceeded' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_ALL=$(cat ${FILE} | grep -w 'total.requestlist.current.all' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_USER=$(cat ${FILE} | grep -w 'total.requestlist.current.user' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 TOTAL_TCPUSAGE=$(cat ${FILE} | grep -w 'total.tcpusage' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 NUM_QUERY_TYPE_A=$(cat ${FILE} | grep -w 'num.query.type.A' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NS=$(cat ${FILE} | grep -w 'num.query.type.NS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_MX=$(cat ${FILE} | grep -w 'num.query.type.MX' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TXT=$(cat ${FILE} | grep -w 'num.query.type.TXT' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_PTR=$(cat ${FILE} | grep -w 'num.query.type.PTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_AAAA=$(cat ${FILE} | grep -w 'num.query.type.AAAA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SRV=$(cat ${FILE} | grep -w 'num.query.type.SRV' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SOA=$(cat ${FILE} | grep -w 'num.query.type.SOA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HTTPS=$(cat ${FILE} | grep -w 'num.query.type.HTTPS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TYPE0=$(cat ${FILE} | grep -w 'num.query.type.TYPE0' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_CNAME=$(cat ${FILE} | grep -w 'num.query.type.CNAME' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_WKS=$(cat ${FILE} | grep -w 'num.query.type.WKS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HINFO=$(cat ${FILE} | grep -w 'num.query.type.HINFO' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_X25=$(cat ${FILE} | grep -w 'num.query.type.X25' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NAPTR=$(cat ${FILE} | grep -w 'num.query.type.NAPTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DS=$(cat ${FILE} | grep -w 'num.query.type.DS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DNSKEY=$(cat ${FILE} | grep -w 'num.query.type.DNSKEY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TLSA=$(cat ${FILE} | grep -w 'num.query.type.TLSA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SVCB=$(cat ${FILE} | grep -w 'num.query.type.SVCB' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SPF=$(cat ${FILE} | grep -w 'num.query.type.SPF' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_ANY=$(cat ${FILE} | grep -w 'num.query.type.ANY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_OTHER=$(cat ${FILE} | grep -w 'num.query.type.other' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 NUM_ANSWER_RCODE_NOERROR=$(cat ${FILE} | grep -w 'num.answer.rcode.NOERROR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_NXDOMAIN=$(cat ${FILE} | grep -w 'num.answer.rcode.NXDOMAIN' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_SERVFAIL=$(cat ${FILE} | grep -w 'num.answer.rcode.SERVFAIL' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_REFUSED=$(cat ${FILE} | grep -w 'num.answer.rcode.REFUSED' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_nodata=$(cat ${FILE} | grep -w 'num.answer.rcode.nodata' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_secure=$(cat ${FILE} | grep -w 'num.answer.secure' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 #       Sending info to zabbix_server, if variables is not empty!&lt;br /&gt;
 [ -z ${TOTAL_NUM_QUERIES} ] ||  zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.queries -o $((TOTAL_NUM_QUERIES/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_CACHEHITS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachehits -o $((TOTAL_NUM_CACHEHITS/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_CACHEMISS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachemiss -o $((TOTAL_NUM_CACHEMISS/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_PREFETCH} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.prefetch -o $((TOTAL_NUM_PREFETCH/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_RECURSIVEREPLIES} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.recursivereplies -o $((TOTAL_NUM_RECURSIVEREPLIES/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${TOTAL_REQ_MAX} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.max -o $((TOTAL_REQ_MAX/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_AVG} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.avg -o $((TOTAL_REQ_AVG/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_OVERWRITTEN} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.overwritten -o $((TOTAL_REQ_OVERWRITTEN/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_EXCEEDED} ] ||  zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.exceeded -o $((TOTAL_REQ_EXCEEDED/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_CURRENT_ALL} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.all -o $((TOTAL_REQ_CURRENT_ALL/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_CURRENT_USER} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.user -o $((TOTAL_REQ_CURRENT_USER/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${TOTAL_TCPUSAGE} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.tcpusage -o $((TOTAL_TCPUSAGE/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_A} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.a -o $((NUM_QUERY_TYPE_A/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_NS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ns -o $((NUM_QUERY_TYPE_NS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_MX} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.mx -o $((NUM_QUERY_TYPE_MX/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_TXT} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.txt -o $((NUM_QUERY_TYPE_TXT/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_PTR} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ptr -o $((NUM_QUERY_TYPE_PTR/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_AAAA} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.aaaa -o $((NUM_QUERY_TYPE_AAAA/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SRV} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.srv -o $((NUM_QUERY_TYPE_SRV/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SOA} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.soa -o $((NUM_QUERY_TYPE_SOA/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_HTTPS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.https -o $((NUM_QUERY_TYPE_HTTPS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_TYPE0} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.type0 -o $((NUM_QUERY_TYPE_TYPE0/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_CNAME} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.cname -o $((NUM_QUERY_TYPE_CNAME/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_WKS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.wks -o $((NUM_QUERY_TYPE_WKS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_HINFO} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.hinfo -o $((NUM_QUERY_TYPE_HINFO/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_X25} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.X25 -o $((NUM_QUERY_TYPE_X25/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_NAPTR} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.naptr -o $((NUM_QUERY_TYPE_NAPTR/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_DS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ds -o $((NUM_QUERY_TYPE_DS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_DNSKEY} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.dnskey -o $((NUM_QUERY_TYPE_DNSKEY/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_TLSA} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.tlsa -o $((NUM_QUERY_TYPE_TLSA/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SVCB} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.svcb -o $((NUM_QUERY_TYPE_SVCB/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SPF} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.spf -o $((NUM_QUERY_TYPE_SPF/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_ANY} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.any -o $((NUM_QUERY_TYPE_ANY/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_OTHER} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.other -o $((NUM_QUERY_TYPE_OTHER/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_NOERROR} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NOERROR -o $((NUM_ANSWER_RCODE_NOERROR/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_NXDOMAIN} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NXDOMAIN -o $((NUM_ANSWER_RCODE_NXDOMAIN/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_SERVFAIL} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.SERVFAIL -o $((NUM_ANSWER_RCODE_SERVFAIL/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_REFUSED} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.REFUSED -o $((NUM_ANSWER_RCODE_REFUSED/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_nodata} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.nodata -o $((NUM_ANSWER_RCODE_nodata/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_secure} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.secure -o $((NUM_ANSWER_secure/300))&lt;br /&gt;
No Zabbix será registrado dados como esses abaixo e posteriormente pode ser montado um Grafana com eles:&lt;br /&gt;
[[Arquivo:Zabbix dns01.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns02.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns03.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns04.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Balanceando o processamento e mantendo a hora certa ==&lt;br /&gt;
Vamos instalar 2 programas agora, o IRQBalance e o Chrony. O primeiro para balancear a carga entre os cores e o segundo para manter a data e hora certas no sistema:&lt;br /&gt;
 # apt install irqbalance&lt;br /&gt;
 # systemctl enable irqbalance&lt;br /&gt;
 # apt install chrony&lt;br /&gt;
Após a instalação do Chrony edite o arquivo /etc/chrony/chrony.conf, comente e a linha abaixo e adicione seus servidores NTP. Caso não tenha servidores NTP, estou colocando os do NIC.br aqui.&lt;br /&gt;
 #pool 2.debian.pool.ntp.org iburst&lt;br /&gt;
 server a.st1.ntp.br iburst nts&lt;br /&gt;
 server b.st1.ntp.br iburst nts&lt;br /&gt;
 server c.st1.ntp.br iburst nts&lt;br /&gt;
 server d.st1.ntp.br iburst nts&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart chronyd.service&lt;br /&gt;
Cheque com o '''chronyc''' se os servidores estão OK:&lt;br /&gt;
 # chronyc sourcestats&lt;br /&gt;
 Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev&lt;br /&gt;
 ==============================================================================&lt;br /&gt;
 a.st1.ntp.br               10   5  155m     -0.027      0.030    -71us    51us&lt;br /&gt;
 b.st1.ntp.br               11   7  344m     +0.068      0.079    +23ms   382us&lt;br /&gt;
 c.st1.ntp.br                6   3  344m     +0.026      0.037   -124us    92us&lt;br /&gt;
 200.20.186.76               9   3  138m     -0.022      0.031   +172us    42us&lt;br /&gt;
&lt;br /&gt;
 # chronyc sources&lt;br /&gt;
 MS Name/IP address         Stratum Poll Reach LastRx Last sample&lt;br /&gt;
 ===============================================================================&lt;br /&gt;
 ^* a.st1.ntp.br                  1  10   377   588   +487us[ +397us] +/-   12ms&lt;br /&gt;
 ^- b.st1.ntp.br                  2  10   377   830    +23ms[  +23ms] +/-   49ms&lt;br /&gt;
 ^+ c.st1.ntp.br                  2  10    21  1038   -147us[ -242us] +/-   17ms&lt;br /&gt;
 ^+ 200.20.186.76                 1  10   377  1032   +381us[ +285us] +/-   15ms&lt;br /&gt;
&lt;br /&gt;
== Configurando o FRRouting ==&lt;br /&gt;
Nesse ponto iremos configurar o '''FRRouting''' para enviar os IPs das '''loopbacks''' e o '''/30''' para o nosso PE do diagrama. Em '''/etc/frr/daemons''' habilite o parâmetro conforme abaixo:&lt;br /&gt;
 ospfd=yes&lt;br /&gt;
Edite o arquivo '''/etc/frr/frr.conf''' e deixe com o conteúdo abaixo, para ficar conforme nosso diagrama do projeto. Apenas troque '''&amp;lt;SENHA&amp;gt;''' por uma senha para fechar o OSPF com mais segurança. Essa senha deve ser usada dos dois lados.&lt;br /&gt;
 frr version 10.2.1&lt;br /&gt;
 frr defaults traditional&lt;br /&gt;
 hostname dns-recursivo-01&lt;br /&gt;
 log syslog informational&lt;br /&gt;
 no ip forwarding&lt;br /&gt;
 no ipv6 forwarding&lt;br /&gt;
 service integrated-vtysh-config&lt;br /&gt;
 !&lt;br /&gt;
 interface ens18&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf message-digest-key 5 md5 &amp;lt;SENHA&amp;gt;&lt;br /&gt;
  ip ospf network point-to-point&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 network point-to-point&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 interface lo&lt;br /&gt;
  description LOOPBACKS&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf passive&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 passive&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf&lt;br /&gt;
  ospf router-id 172.16.0.6&lt;br /&gt;
  area 0.0.0.0 authentication message-digest&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf6&lt;br /&gt;
  ospf6 router-id 172.16.0.6&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart frr.service&lt;br /&gt;
Cheque se está tudo OK com o OSPF e verifique no PE se está recebendo os prefixos anunciados.&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL&lt;br /&gt;
 172.16.0.5     1 Full/-          10m49s            35.310s 172.16.0.5   ens18:172.16.0.6                  0     0     0&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri    DeadTime    State/IfState         Duration I/F[State]&lt;br /&gt;
 172.16.0.5       1    00:00:30     Full/PointToPoint 25d22:53:47 ens18[PointToPoint]&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor detail'&lt;br /&gt;
 &lt;br /&gt;
  Neighbor 172.16.0.5, interface address 172.16.0.5&lt;br /&gt;
     In the area 0.0.0.0 via interface ens18&lt;br /&gt;
     Neighbor priority is 1, State is Full/-, 5 state changes&lt;br /&gt;
     Most recent state change statistics:&lt;br /&gt;
       Progressive change 21w3d15h ago&lt;br /&gt;
     DR is 0.0.0.0, BDR is 0.0.0.0&lt;br /&gt;
     Options 18 *|-|-|EA|-|-|E|-&lt;br /&gt;
     Dead timer due in 34.685s&lt;br /&gt;
     Database Summary List 0&lt;br /&gt;
     Link State Request List 0&lt;br /&gt;
     Link State Retransmission List 0&lt;br /&gt;
     Thread Inactivity Timer on&lt;br /&gt;
     Thread Database Description Retransmision off&lt;br /&gt;
     Thread Link State Request Retransmission on&lt;br /&gt;
     Thread Link State Update Retransmission on&lt;br /&gt;
 &lt;br /&gt;
     Graceful restart Helper info:&lt;br /&gt;
       Graceful Restart HELPER Status : None&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor detail'&lt;br /&gt;
  Neighbor 172.16.0.5%ens18&lt;br /&gt;
     Area 0.0.0.0 via interface ens18 (ifindex 4)&lt;br /&gt;
     His IfIndex: 60 Link-local address: fe80::469b:c1ff:fed6:43ee&lt;br /&gt;
     State Full for a duration of 25d22:57:14&lt;br /&gt;
     His choice of DR/BDR 0.0.0.0/0.0.0.0, Priority 1&lt;br /&gt;
     DbDesc status: Master SeqNum: 0xb94b0000&lt;br /&gt;
     Summary-List: 0 LSAs&lt;br /&gt;
     Request-List: 0 LSAs&lt;br /&gt;
     Retrans-List: 0 LSAs&lt;br /&gt;
     0 Pending LSAs for DbDesc in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSReq in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSAck in Time 00:00:00 [thread off]&lt;br /&gt;
     Authentication header not present&lt;br /&gt;
&lt;br /&gt;
== Configurando o Unbound ==&lt;br /&gt;
Abaixo a configuração que usaremos nos servidores atentando para o detalhe do '''num-threads''', esse deve ter o valor igual ao número de CPUs do servidor.&lt;br /&gt;
&lt;br /&gt;
Também os IPs utilizados em '''outgoing-interface''' que serão diferentes em cada servidor, esses serão os IPs usados para '''recursividade'''. Consulte o manual do Unbound para obter mais informações sobre cada parâmetro listado na configuração.&lt;br /&gt;
&lt;br /&gt;
O tuning no Unbound pode ser alterado conforme abaixo:&lt;br /&gt;
 num-threads = nº CPUs&lt;br /&gt;
 so-reuseport = yes&lt;br /&gt;
 *-slabs = potência de 2 próximo ao num-threads&lt;br /&gt;
 msg-cache-size = 1g (quantidade de memória pra usar de cache)&lt;br /&gt;
 rrset-cache-size = 2 * msg-cache-size&lt;br /&gt;
 outgoing-range = 8192&lt;br /&gt;
 num-queries-per-thread = 4096&lt;br /&gt;
 so-rcvbuf e so-sndbuf = 4m ou 8m para servidores com muita requisição&lt;br /&gt;
Agora vamos criar nosso arquivo de configuração base em '''/etc/unbound/unbound.conf.d/local.conf''':&lt;br /&gt;
 server:&lt;br /&gt;
         verbosity: 1&lt;br /&gt;
         statistics-interval: 0&lt;br /&gt;
         statistics-cumulative: no&lt;br /&gt;
         extended-statistics: yes&lt;br /&gt;
         num-threads: 4&lt;br /&gt;
         serve-expired: yes&lt;br /&gt;
         interface: 127.0.0.1&lt;br /&gt;
         interface: 10.10.10.10&lt;br /&gt;
         interface: 10.10.9.9&lt;br /&gt;
         interface: 172.16.0.6&lt;br /&gt;
         interface: fc00::10:10:10:10&lt;br /&gt;
         interface: fc00::10:10:9:9&lt;br /&gt;
         interface: ::1&lt;br /&gt;
         interface-automatic: no&lt;br /&gt;
         outgoing-interface: 198.18.1.10&lt;br /&gt;
         outgoing-interface: 2001:db8::faca:198:18:1:10&lt;br /&gt;
         outgoing-range: 8192&lt;br /&gt;
         outgoing-num-tcp: 1024&lt;br /&gt;
         incoming-num-tcp: 2048&lt;br /&gt;
         so-rcvbuf: 4m&lt;br /&gt;
         so-sndbuf: 4m&lt;br /&gt;
         so-reuseport: yes&lt;br /&gt;
         edns-buffer-size: 1232&lt;br /&gt;
         msg-cache-size: 1g&lt;br /&gt;
         msg-cache-slabs: 4&lt;br /&gt;
         num-queries-per-thread: 4096&lt;br /&gt;
         rrset-cache-size: 2g&lt;br /&gt;
         rrset-cache-slabs: 4&lt;br /&gt;
         infra-cache-slabs: 4&lt;br /&gt;
         do-ip4: yes&lt;br /&gt;
         do-ip6: yes&lt;br /&gt;
         do-udp: yes&lt;br /&gt;
         do-tcp: yes&lt;br /&gt;
         chroot: &amp;quot;&amp;quot;&lt;br /&gt;
         username: &amp;quot;unbound&amp;quot;&lt;br /&gt;
         directory: &amp;quot;/etc/unbound&amp;quot;&lt;br /&gt;
         logfile: &amp;quot;/var/log/unbound/unbound.log&amp;quot;&lt;br /&gt;
         use-syslog: no&lt;br /&gt;
         log-time-ascii: yes&lt;br /&gt;
         log-queries: no&lt;br /&gt;
         pidfile: &amp;quot;/var/run/unbound.pid&amp;quot;&lt;br /&gt;
         root-hints: &amp;quot;/usr/share/dns/root.hints&amp;quot;&lt;br /&gt;
         hide-identity: yes&lt;br /&gt;
         hide-version: yes&lt;br /&gt;
         unwanted-reply-threshold: 10000000&lt;br /&gt;
         prefetch: yes&lt;br /&gt;
         prefetch-key: yes&lt;br /&gt;
         rrset-roundrobin: yes&lt;br /&gt;
         minimal-responses: yes&lt;br /&gt;
         module-config: &amp;quot;respip validator iterator&amp;quot;&lt;br /&gt;
         val-clean-additional: yes&lt;br /&gt;
         val-log-level: 1&lt;br /&gt;
         key-cache-slabs: 4&lt;br /&gt;
         deny-any: yes&lt;br /&gt;
         cache-min-ttl: 60&lt;br /&gt;
         key-cache-size: 128m&lt;br /&gt;
         neg-cache-size: 64m&lt;br /&gt;
         cache-max-ttl: 86400&lt;br /&gt;
         infra-cache-numhosts: 100000&lt;br /&gt;
         access-control: 198.18.0.0/22 allow&lt;br /&gt;
         access-control: 2001:db8::/32 allow&lt;br /&gt;
  &lt;br /&gt;
 rpz:&lt;br /&gt;
   name: rpz.block.host.local.zone&lt;br /&gt;
   zonefile: /etc/unbound/rpz.block.hosts.zone&lt;br /&gt;
   rpz-action-override: nxdomain&lt;br /&gt;
  &lt;br /&gt;
 python:&lt;br /&gt;
  &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;.&amp;quot;&lt;br /&gt;
     master: &amp;quot;b.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;c.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;d.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;f.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;g.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;k.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/root.zone&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;arpa.&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/arpa.zone&amp;quot;&lt;br /&gt;
No parâmetro '''interface''' colocamos os IPs que serão usados para consulta dos clientes como o '''10.10.10.10''', '''10.10.9.9, fc00::10:10:10:10 e fc00::10:10:9:9'''. Ali repare que coloquei também o IP privado '''172.16.0.6''', isso porque cada servidor terá o seu IP privado e este deve ser usado pelo seu sistema de monitoramento para checar cada servidor. No '''outgoing-interface''' teremos os IPs, tanto '''IPv4''' quanto '''IPv6''', para que seja feita a recursividade na Internet utilizando eles. Não tem '''IPv6''' ainda na sua rede? Dê uma olhada nesse artigo. Outro parâmetro importante é o '''access-control''' e é através dele que liberamos os prefixos IP para consultarem no nosso DNS Recursivo. No exemplo estou liberando todo o prefixo '''198.18.0.0/22''' e o prefixo '''2001:db8::/32'''. Além da ACL no Unbound, recomendo que crie um filtro de pacotes com iptables ou nftables protegendo seu sistema e liberando as portas '''53/UDP''', '''53/TCP,'''  '''443/TCP e 853/TCP''' apenas para seus clientes. Falarei sobre a '''443/TCP e 853/TCP''' mais para frente nessa mesma documentação.&lt;br /&gt;
&lt;br /&gt;
Agora criaremos o arquivo '''RPZ''' ('''Response Policy Zones'''). Esse arquivo contém os sites que serão bloqueados via '''&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; Recursivo'''. São aqueles sites que às vezes você recebe um Ofício da Justiça solicitando o bloqueio deles. Não entrarei no mérito da efetividade desses bloqueios, porque muitos de vocês sabem que tecnicamente, existem formas de se fazer um bypass através desses bloqueios. Contudo vamos deixar nosso ambiente preparado para esses bloqueios e por isso crie o arquivo '''/etc/unbound/rpz.block.hosts.zone''' com esse conteúdo de exemplo:&lt;br /&gt;
 $TTL 2h&lt;br /&gt;
 @ IN SOA localhost. root.localhost. (2 6h 1h 1w 2h)&lt;br /&gt;
   IN NS  localhost.&lt;br /&gt;
 ; RPZ manual block hosts&lt;br /&gt;
 *.josedascoves.com CNAME .&lt;br /&gt;
 josedascoves.com CNAME .&lt;br /&gt;
No exemplo acima estamos bloqueando qualquer consulta de DNS para '''josedascoves.com''' ou qualquer coisa '''.josedascoves.com'''.&lt;br /&gt;
&lt;br /&gt;
Para testar podemos fazer assim do próprio servidor:&lt;br /&gt;
 # host josedascoves.com ::1&lt;br /&gt;
 Using domain server:&lt;br /&gt;
 Name: ::1&lt;br /&gt;
 Address: ::1#53&lt;br /&gt;
 Aliases:&lt;br /&gt;
 &lt;br /&gt;
 Host josedascoves.com not found: 3(NXDOMAIN)&lt;br /&gt;
Se a resposta for '''NXDOMAIN''' então está funcionando o bloqueio. Para incluir novos bloqueios basta adicionar os domínios, um abaixo do outro, conforme o exemplo que coloquei no arquivo RPZ.&lt;br /&gt;
&lt;br /&gt;
== Acertando o resolv.conf ==&lt;br /&gt;
Vamos modificar nosso /etc/resolv.conf para utilizar DNS externo. Sim você deve estar se perguntando em qual situação isso seria utilizado. Primeiro entenda que o Unbound não irá utilizar o DNS externo para fazer as consultas na Internet e sim, qualquer teste que você faça do servidor precisará apontar para o Unbound usando os IPs '''127.0.0.1''' ou '''::1'''. Faremos isso pela seguinte situação: imagine que o daemon unbound morreu mas você ainda continua com conectividade na Internet. Você conseguiria acessar qualquer local na Internet através do IP mas não através do hostname porque não conseguiria resolver nomes, seu unbound estaria fora do ar. Imagine ainda que você gostaria que seu servidor te avisasse do problema via Telegram ou e-mail. Por isso estamos utilizando um DNS externo no '''/etc/resolv.conf''', apenas para essas situações. Se você não quiser utilizar desse recurso, pode usar o '''127.0.0.1''' e '''::1''' no lugar.&lt;br /&gt;
 nameserver 8.8.8.8&lt;br /&gt;
 nameserver 8.8.4.4&lt;br /&gt;
 nameserver 2001:4860:4860::8888&lt;br /&gt;
&lt;br /&gt;
== Script de teste de recursividade ==&lt;br /&gt;
Estamos montando uma '''Rede de DNS Recursivo Anycast''', então é muito importante que você monitore essa rede para saber se algum node morreu e iniciar o troubleshooting, resolver o problema e levantar o sistema novamente. Tudo isso é importante mas o cliente não deve ficar esperando até você resolver o problema, seu sistema precisa ser inteligente o suficiente para se remover da Rede quando tiver um problema e se inserir novamente, quando o problema estiver sido solucionado. Se você montar uma Rede de DNS e um dos nodes apresentar algum problema, todos os clientes atendidos por aquele node migrarão automaticamente e transparentemente para outro '''DNS Recursivo Anycast''' mais próximo. Isso se chama '''disponibilidade'''.&lt;br /&gt;
&lt;br /&gt;
O script '''/root/scripts/checa_dns.sh''' abaixo tem a função de fazer os testes de recursividade e checar se o daemon do unbound continua rodando. Se algo acontecer, ele para o anúncio do '''10.10.10.10''' e '''10.10.9.9''' e retorna eles quando tudo estiver resolvido.&lt;br /&gt;
 # mkdir /root/scripts&lt;br /&gt;
&lt;br /&gt;
 #!/usr/bin/env bash&lt;br /&gt;
 #Script para teste de DNS v2.1&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 #Informe um domínio por linha:&lt;br /&gt;
 dominios_testar=(&lt;br /&gt;
 www.google.com&lt;br /&gt;
 www.terra.com.br&lt;br /&gt;
 www.uol.com.br&lt;br /&gt;
 www.globo.com&lt;br /&gt;
 www.facebook.com&lt;br /&gt;
 www.youtube.com&lt;br /&gt;
 www.twitch.com&lt;br /&gt;
 www.discord.com&lt;br /&gt;
 www.debian.org&lt;br /&gt;
 www.redhat.com&lt;br /&gt;
 )&lt;br /&gt;
 corte_taxa_falha=100 #Porcentagem de falha para executar uma ação&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 remove_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; != &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no description' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME morreu!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 adiciona_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; == &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'description LOOPBACKS' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME retornou do inferno!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
 if [ $? -ne 0 ]; then&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME morreu DNS mas tentando levantar!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    systemctl restart unbound&lt;br /&gt;
    systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
    if [ $? -ne 0 ]; then&lt;br /&gt;
       remove_ospf&lt;br /&gt;
       exit&lt;br /&gt;
    fi&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME servico DNS voltou mas tinha morrido!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 qt_falhas=0&lt;br /&gt;
 qt_total=&amp;quot;${#dominios_testar[@]}&amp;quot;&lt;br /&gt;
 echo &amp;quot;total_dominios: $qt_total&amp;quot;&lt;br /&gt;
 for site in &amp;quot;${dominios_testar[@]}&amp;quot;&lt;br /&gt;
 do&lt;br /&gt;
   resolver=&amp;quot;127.0.0.1&amp;quot;&lt;br /&gt;
   echo -e &amp;quot; - dominio $site - $resolver - \c&amp;quot;&lt;br /&gt;
   host $site $resolver &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   if [ $? -ne 0 ]; then&lt;br /&gt;
      ((qt_falhas++))&lt;br /&gt;
      echo -e &amp;quot;[Falhou]&amp;quot;&lt;br /&gt;
   else&lt;br /&gt;
      echo -e &amp;quot;[OK]&amp;quot;&lt;br /&gt;
   fi&lt;br /&gt;
 done&lt;br /&gt;
  &lt;br /&gt;
 taxa_falha=$((qt_falhas*100/qt_total))&lt;br /&gt;
 echo &amp;quot;Falhas $qt_falhas/$qt_total ($taxa_falha%)&amp;quot;&lt;br /&gt;
  &lt;br /&gt;
 if [ &amp;quot;$taxa_falha&amp;quot; -ge &amp;quot;$corte_taxa_falha&amp;quot; ]; then&lt;br /&gt;
    remove_ospf&lt;br /&gt;
    exit&lt;br /&gt;
 fi&lt;br /&gt;
 adiciona_ospf&lt;br /&gt;
Se rodarmos o script manualmente veremos isto:&lt;br /&gt;
 # /root/scripts/checa_dns.sh&lt;br /&gt;
 total_dominios: 10&lt;br /&gt;
  - dominio www.google.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.terra.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.uol.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.globo.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.facebook.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.youtube.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.twitch.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.discord.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.debian.org - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.redhat.com - 127.0.0.1 - [OK]&lt;br /&gt;
 Falhas 0/10 (0%)&lt;br /&gt;
Se acontecer 100% de falhas o script irá remover os anúncios do OSPF. Se o daemon do unbound morrer, ele tentará reiniciá-lo. Se tudo normalizar o script irá retornar os anúncios para o OSPF. Deixei comentado no script as partes que enviariam uma notificação para o Telegram. Existem diversas documentações sobre isso na Internet, eu mesmo tenho uma. Assim que eu publicar aqui, atualizo essa documentação e sinta-se à vontade de modificar como desejar.&lt;br /&gt;
 # chmod 700 /root/scripts/checa_dns.sh&lt;br /&gt;
Adicione a linha abaixo em seu '''/etc/crontab''':&lt;br /&gt;
 */1 *   * * *   root    /root/scripts/checa_dns.sh&lt;br /&gt;
&lt;br /&gt;
== Habilitando o DoH (&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; over HTTPS) e DoT (DNS over TLS) - opcional ==&lt;br /&gt;
Para habilitar o '''DoH''' e o '''DoT''' no Unbound é bem simples. O recurso do '''DoH''' e '''DoT''' vem para trazer mais segurança e privacidade para o usuário. É um recurso muito pouco utilizado ainda mas que seu cliente pode vir a pedir algum dia.&lt;br /&gt;
&lt;br /&gt;
Você precisará gerar certificados SSL legítimos e para isso você poderá usar o '''Let's Encrypt''' só que de uma forma não tão convencional.&lt;br /&gt;
&lt;br /&gt;
Na sequência vamos instalar o Let's Encrypt para gerarmos nosso certificado SSL:&lt;br /&gt;
 # apt install letsencrypt&lt;br /&gt;
Escolha um '''hostname''' para ser usado no nosso '''DoH''' e aponte ele no seu DNS Autoritativo para seus IPs 10.10.10.10 e 10.10.9.9. Aqui vamos usar o seguinte como exemplo: '''doh.brasilpeeringforum.org'''. Para gerarmos nosso certificado iremos usar o tipo '''DNS-01''', ele não necessita que tenhamos um servidor web rodando no servidor e nem tão pouco levanta um serviço na porta 80 para checar o hostname. Ele utiliza o DNS como validador e vai te solicitar que crie um registro '''CNAME''' no seu '''DNS Autoritativo''' para provar que você tem o controle sobre aquele hostname. Antes disso vamos instalar um programa em Python para podermos automatizar nossa renovação de certificado no futuro. Esse programa se encontra '''[https://github.com/joohoi/acme-dns-certbot-joohoi/raw/master/acme-dns-auth.py aqui]''' mas vou deixá-lo abaixo já modificado o interpretador.&lt;br /&gt;
&lt;br /&gt;
Crie o arquivo '''/etc/letsencrypt/acme-dns-auth.py''' com o conteúdo abaixo:&lt;br /&gt;
 #!/usr/bin/env python3&lt;br /&gt;
 import json&lt;br /&gt;
 import os&lt;br /&gt;
 import requests&lt;br /&gt;
 import sys&lt;br /&gt;
 &lt;br /&gt;
 ### EDIT THESE: Configuration values ###&lt;br /&gt;
 &lt;br /&gt;
 # URL to acme-dns instance&lt;br /&gt;
 ACMEDNS_URL = &amp;quot;&amp;lt;nowiki&amp;gt;https://auth.acme-dns.io&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
 # Path for acme-dns credential storage&lt;br /&gt;
 STORAGE_PATH = &amp;quot;/etc/letsencrypt/acmedns.json&amp;quot;&lt;br /&gt;
 # Whitelist for address ranges to allow the updates from&lt;br /&gt;
 # Example: ALLOW_FROM = [&amp;quot;192.168.10.0/24&amp;quot;, &amp;quot;::1/128&amp;quot;]&lt;br /&gt;
 ALLOW_FROM = []&lt;br /&gt;
 # Force re-registration. Overwrites the already existing acme-dns accounts.&lt;br /&gt;
 FORCE_REGISTER = False&lt;br /&gt;
 &lt;br /&gt;
 ###   DO NOT EDIT BELOW THIS POINT   ###&lt;br /&gt;
 ###         HERE BE DRAGONS          ###&lt;br /&gt;
 &lt;br /&gt;
 DOMAIN = os.environ[&amp;quot;CERTBOT_DOMAIN&amp;quot;]&lt;br /&gt;
 if DOMAIN.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
     DOMAIN = DOMAIN[2:]&lt;br /&gt;
 VALIDATION_DOMAIN = &amp;quot;_acme-challenge.&amp;quot;+DOMAIN&lt;br /&gt;
 VALIDATION_TOKEN = os.environ[&amp;quot;CERTBOT_VALIDATION&amp;quot;]&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 class AcmeDnsClient(object):&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
     Handles the communication with ACME-DNS API&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
     def __init__(self, acmedns_url):&lt;br /&gt;
         self.acmedns_url = acmedns_url&lt;br /&gt;
 &lt;br /&gt;
     def register_account(self, allowfrom):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Registers a new ACME-DNS account&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
         if allowfrom:&lt;br /&gt;
             # Include whitelisted networks to the registration call&lt;br /&gt;
             reg_data = {&amp;quot;allowfrom&amp;quot;: allowfrom}&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;,&lt;br /&gt;
                                 data=json.dumps(reg_data))&lt;br /&gt;
         else:&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;)&lt;br /&gt;
         if res.status_code == 201:&lt;br /&gt;
             # The request was successful&lt;br /&gt;
             return res.json()&lt;br /&gt;
         else:&lt;br /&gt;
             # Encountered an error&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to register a new acme-dns &amp;quot;&lt;br /&gt;
                    &amp;quot;account. HTTP status {}, Response body: {}&amp;quot;)&lt;br /&gt;
             print(msg.format(res.status_code, res.text))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def update_txt_record(self, account, txt):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Updates the TXT challenge record to ACME-DNS subdomain.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         update = {&amp;quot;subdomain&amp;quot;: account['subdomain'], &amp;quot;txt&amp;quot;: txt}&lt;br /&gt;
         headers = {&amp;quot;X-Api-User&amp;quot;: account['username'],&lt;br /&gt;
                    &amp;quot;X-Api-Key&amp;quot;: account['password'],&lt;br /&gt;
                    &amp;quot;Content-Type&amp;quot;: &amp;quot;application/json&amp;quot;}&lt;br /&gt;
         res = requests.post(self.acmedns_url+&amp;quot;/update&amp;quot;,&lt;br /&gt;
                             headers=headers,&lt;br /&gt;
                             data=json.dumps(update))&lt;br /&gt;
         if res.status_code == 200:&lt;br /&gt;
             # Successful update&lt;br /&gt;
             return&lt;br /&gt;
         else:&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to update TXT record in &amp;quot;&lt;br /&gt;
                    &amp;quot;acme-dns. \n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request headers:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request body:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response HTTP status: {}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response body: {}&amp;quot;)&lt;br /&gt;
             s_headers = json.dumps(headers, indent=2, sort_keys=True)&lt;br /&gt;
             s_update = json.dumps(update, indent=2, sort_keys=True)&lt;br /&gt;
             s_body = json.dumps(res.json(), indent=2, sort_keys=True)&lt;br /&gt;
             print(msg.format(s_headers, s_update, res.status_code, s_body))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
 class Storage(object):&lt;br /&gt;
     def __init__(self, storagepath):&lt;br /&gt;
         self.storagepath = storagepath&lt;br /&gt;
         self._data = self.load()&lt;br /&gt;
 &lt;br /&gt;
     def load(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Reads the storage content from the disk to a dict structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         data = dict()&lt;br /&gt;
         filedata = &amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             with open(self.storagepath, 'r') as fh:&lt;br /&gt;
                 filedata = fh.read()&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             if os.path.isfile(self.storagepath):&lt;br /&gt;
                 # Only error out if file exists, but cannot be read&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage file exists but cannot be read&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         try:&lt;br /&gt;
             data = json.loads(filedata)&lt;br /&gt;
         except ValueError:&lt;br /&gt;
             if len(filedata) &amp;gt; 0:&lt;br /&gt;
                 # Storage file is corrupted&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage JSON is corrupted&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         return data&lt;br /&gt;
 &lt;br /&gt;
     def save(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Saves the storage content to disk&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         serialized = json.dumps(self._data)&lt;br /&gt;
         try:&lt;br /&gt;
             with os.fdopen(os.open(self.storagepath,&lt;br /&gt;
                                    os.O_WRONLY | os.O_CREAT, 0o600), 'w') as fh:&lt;br /&gt;
                 fh.truncate()&lt;br /&gt;
                 fh.write(serialized)&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             print(&amp;quot;ERROR: Could not write storage file.&amp;quot;)&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def put(self, key, value):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Puts the configuration value to storage and sanitize it&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         # If wildcard domain, remove the wildcard part as this will use the&lt;br /&gt;
         # same validation record name as the base domain&lt;br /&gt;
         if key.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
             key = key[2:]&lt;br /&gt;
         self._data[key] = value&lt;br /&gt;
 &lt;br /&gt;
     def fetch(self, key):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Gets configuration value from storage&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             return self._data[key]&lt;br /&gt;
         except KeyError:&lt;br /&gt;
             return None&lt;br /&gt;
 &lt;br /&gt;
 if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
     # Init&lt;br /&gt;
     client = AcmeDnsClient(ACMEDNS_URL)&lt;br /&gt;
     storage = Storage(STORAGE_PATH)&lt;br /&gt;
 &lt;br /&gt;
     # Check if an account already exists in storage&lt;br /&gt;
     account = storage.fetch(DOMAIN)&lt;br /&gt;
     if FORCE_REGISTER or not account:&lt;br /&gt;
         # Create and save the new account&lt;br /&gt;
         account = client.register_account(ALLOW_FROM)&lt;br /&gt;
         storage.put(DOMAIN, account)&lt;br /&gt;
         storage.save()&lt;br /&gt;
 &lt;br /&gt;
         # Display the notification for the user to update the main zone&lt;br /&gt;
         msg = &amp;quot;Please add the following CNAME record to your main DNS zone:\n{}&amp;quot;&lt;br /&gt;
         cname = &amp;quot;{} CNAME {}.&amp;quot;.format(VALIDATION_DOMAIN, account[&amp;quot;fulldomain&amp;quot;])&lt;br /&gt;
         print(msg.format(cname))&lt;br /&gt;
 &lt;br /&gt;
     # Update the TXT record in acme-dns instance&lt;br /&gt;
     client.update_txt_record(account, VALIDATION_TOKEN)&lt;br /&gt;
&lt;br /&gt;
 # chmod +x /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
Usaremos a seguinte instrução para criar nosso certificado:&lt;br /&gt;
 # certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d doh.brasilpeeringforum.org&lt;br /&gt;
 Saving debug log to /var/log/letsencrypt/letsencrypt.log&lt;br /&gt;
 Plugins selected: Authenticator manual, Installer None&lt;br /&gt;
 Cert is due for renewal, auto-renewing...&lt;br /&gt;
 Renewing an existing certificate for doh.brasilpeeringforum.org&lt;br /&gt;
 Performing the following challenges:&lt;br /&gt;
 dns-01 challenge for doh.brasilpeeringforum.org&lt;br /&gt;
 Running manual-auth-hook command: /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
 Output from manual-auth-hook command acme-dns-auth.py:&lt;br /&gt;
 Please add the following CNAME record to your main DNS zone:&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
 &lt;br /&gt;
 Waiting for verification...&lt;br /&gt;
 &lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Challenges loaded. Press continue to submit to CA. Pass &amp;quot;-v&amp;quot; for more info about&lt;br /&gt;
 challenges.&lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Press Enter to Continue&lt;br /&gt;
Nesse momento você cria o registro '''CNAME''' no seu DNS Autoritativo conforme ele solicitou: '''_acme-challenge.doh.brasilpeeringforum.org IN CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.''' e somente depois de criado e checado no DNS, você pressiona o '''Enter''' para continuar. Você pode checar dessa forma:&lt;br /&gt;
 # host -t cname _acme-challenge.doh.brasilpeeringforum.org&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org is an alias for b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
Para que nosso certificado seja automaticamente renovado colocaremos no '''/etc/crontab''' a seguinte linha abaixo:&lt;br /&gt;
 00 00   1 * *   root    /usr/bin/certbot -q renew&lt;br /&gt;
Acima temos a instrução para renovação automática do certificado. Repare que você vai precisar também copiar esse certificado para seus outros servidores, escolha um servidor para manter o certificado sempre atualizado e crie um script que faça a mesma cópia remotamente para os outros servidores. O '''scp''' e o '''rsync''' são seus aliados nisso.&lt;br /&gt;
&lt;br /&gt;
=== Configurando o Unbound ===&lt;br /&gt;
Em nosso '''/etc/unbound/unbound.conf.d/local.conf''', adicionaremos no bloco &amp;quot;'''server:'''&amp;quot; o seguinte:&lt;br /&gt;
 interface: 10.10.10.10@443 &lt;br /&gt;
 interface: 10.10.9.9@443&lt;br /&gt;
 interface: fc00::10:10:10:10@443&lt;br /&gt;
 interface: fc00::10:10:9:9@443&lt;br /&gt;
 interface: 10.10.10.10@853 &lt;br /&gt;
 interface: 10.10.9.9@853&lt;br /&gt;
 interface: fc00::10:10:10:10@853&lt;br /&gt;
 interface: fc00::10:10:9:9@853&lt;br /&gt;
 tls-service-key: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/privkey.pem&amp;quot; &lt;br /&gt;
 tls-service-pem: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/fullchain.pem&amp;quot;&lt;br /&gt;
Para usar o recurso do '''DoH''' você precisará habilitar o recurso no seu navegador e informar a URL. Vou colocar o exemplo do '''Google Chrome''': Digite '''chrome://settings/security?search=dns''' no seu Chrome e ative '''Usar DNS seguro''', selecione '''Personalizado''' e adicione nossa URL:&lt;br /&gt;
[[Arquivo:Doh bpf2.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Finalizando ==&lt;br /&gt;
Aqui finalizamos nosso projeto para uma Rede de DNS(s) Recursivos Anycast com Hyperlocal. Esse projeto é escalável, seguro, resiliente e você entregará muito mais qualidade de Internet para o seu cliente. Pare de entregar o '''8.8.8.8''' para os seus clientes, você está contribuindo para uma Internet mais lenta, sem a qualidade que o seu cliente merece. Investi meu tempo, que é muito pouco, para deixar esse documento para a comunidade, para você melhorar o seu ISP, para dar um UP! nele, então vamos começar 2023 com o pé direito. O que acha?&lt;br /&gt;
&lt;br /&gt;
Como prova de conceito, uma imagem abaixo onde temos uma Rede em produção de DNS(s) Recursivos Anycast e apontando exatamente o momento em que houve alguma situação que fez com que as queries de DNS, convergissem de um node para outro, de forma transparente e automática para o cliente. Podemos notar também que ao ser resolvido o problema, o tráfego retornou para o seu node correto:&lt;br /&gt;
[[Arquivo:Convergencia.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== KINDNS (Stands for Knowledge-Sharing and Instantiating Norms for DNS and Naming Security) ==&lt;br /&gt;
Achou que havia terminado? Agora que você tem a capacidade de montar uma '''Rede de DNS Recursivo''' com todas essas features acima, com todas as ferramentas que foram comentadas, o que acha de certificar o que fez?&lt;br /&gt;
&lt;br /&gt;
Assim como o [https://www.manrs.org/ MANRS] veio para certificar nosso sistema de roteamento na Internet, agora temos o [https://kindns.org/ KINDNS] para certificar que nossos sistemas de DNS estão bem feitos e dentro dos padrões de segurança. Existem '''7 ações''' que podem ser certificadas para nossos DNS Recursivos e estão aqui em https://kindns.org/shared-private-resolvers/. Com essa nossa documentação, se bem aplicada, você pode se candidatar ao KINDNS e ter seu ASN listado aqui https://kindns.org/participants/&lt;br /&gt;
&lt;br /&gt;
Obter e manter o '''MANRS''' e '''KINDNS''' demonstra seu compromisso com as Boas Práticas, contribui para termos uma '''Internet''' mais segura e te abre portas para novos negócios que possam exigir essas conformidades.&lt;br /&gt;
&lt;br /&gt;
Autor: [[Usuário:Gondim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Infraestrutura]]&lt;br /&gt;
__FORCARTDC__&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
	<entry>
		<id>https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3925</id>
		<title>DNS Recursivo Anycast Hyperlocal</title>
		<link rel="alternate" type="text/html" href="https://wiki.brasilpeeringforum.org/index.php?title=DNS_Recursivo_Anycast_Hyperlocal&amp;diff=3925"/>
		<updated>2025-07-18T02:49:55Z</updated>

		<summary type="html">&lt;p&gt;Gondim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
==Introdução==&lt;br /&gt;
Você sabe como funciona a Internet? Essa é uma pergunta que meu amigo '''Thiago Ayub''' sempre faz aos seus candidatos à vagas de emprego e não importa o quanto tenham de experiência em '''Engenharia de Redes''', todos sempre travam nesse momento. Todos estão sempre prontos e preparados para resolver os problemas mais cabeludos em '''BGP''', '''OSPF''', '''MPLS''', etc mas travam com essa simples pergunta. Para contextualizar e visualizarmos melhor vamos nos atentar à imagem abaixo e uma explicação simplificada de como funciona:&lt;br /&gt;
[[Arquivo:Dns hierarquia.png|esquerda|commoldura]]&lt;br /&gt;
Tudo começa com um usuário sentado confortavelmente e querendo acessar um conteúdo disponível na Internet. Ele digita em seu navegador preferido a URL: '''&amp;lt;nowiki&amp;gt;https://wiki.brasilpeeringforum.org&amp;lt;/nowiki&amp;gt;''',&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;big&amp;gt;1)&amp;lt;/big&amp;gt;''' &amp;lt;big&amp;gt;O&amp;lt;/big&amp;gt; &amp;lt;big&amp;gt;navegador irá requisitar do '''DNS Recursivo''' utilizado pelo usuário, o '''endereço IP''' que responde pelo nome '''wiki.'''&amp;lt;/big&amp;gt;'''brasilpeeringforum.org'''&amp;lt;big&amp;gt;. Isso porque todos os acessos se dão na Internet através do '''endereço''' '''IP''' e não através do '''nome'''. Imaginem se tivéssemos que decorar os endereços IPs de todos os sites e serviços que quiséssemos acessar na Internet?&amp;lt;/big&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;big&amp;gt;'''2)''' Nosso DNS Recursivo checa se a informação consta em seu cache.&amp;lt;/big&amp;gt; Se a informação existir ela é devolvida ao navegador do usuário e aí este consegue acessar o site.&lt;br /&gt;
&lt;br /&gt;
'''3)''' Do contrário o DNS Recursivo pergunta ao '''Root Server''' quem é o '''TLD (Top Level Domain)''' responsável para atender a requisição. &lt;br /&gt;
&lt;br /&gt;
'''4)''' O '''Root Server''' informa ao DNS Recursivo o endereço do '''TLD responsável'''. No Brasil o '''TLD''' responsável pelo '''.br''' seria o '''Registro.br'''.&lt;br /&gt;
&lt;br /&gt;
'''5)''' O DNS Recursivo pergunta ao '''TLD''' sobre '''wiki.brasilpeeringforum.org''' e este responde com os endereços IP dos '''DNS Autoritativos''' responsáveis pelo domínio '''brasilpeeringforum.org.'''&lt;br /&gt;
&lt;br /&gt;
'''6)''' O DNS Recursivo pergunta aos '''DNS Autoritativos''' pelo '''wiki.brasilpeeringforum.org''' e este responde com o '''endereço IP'''.&lt;br /&gt;
&lt;br /&gt;
'''7)''' Por último o DNS Recursivo devolve a informação para o navegador do usuário.&lt;br /&gt;
&lt;br /&gt;
Como que se dá a comunicação entre os '''DNS(s) Recursivos, Root Servers, TLDs''' e '''Autoritativos'''? Como que o navegador do usuário, após receber o IP do site, consegue chegar no servidor que tem o conteúdo? Isso só é possível devido ao protocolo chamado '''BGP (Border Gateway Protocol)''', todos os caminhos que conhecemos como rotas de destino, são anunciadas por milhares de participantes na '''Internet''' conhecidos como '''AS (Autonomous System)''', esses participantes se interligam para disponibilizar conteúdos e acessos pelo mundo aos milhares de usuários. É uma imensa rede colaborativa formada por Empresas, Universidades, Governos e todos que queiram se interconectar. Percebam que sem o '''BGP''', que serve de caminho para chegarmos nos conteúdos e sem o '''DNS (Domain Name System)''' para traduzir o nome para o endereço IP, a '''Internet''' não funcionaria e por isso precisamos cuidar muito bem desses dois serviços.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Mas não acaba por aí. O '''DNS Recursivo''' tem um papel muito importante para o Provedor de Internet e que envolve segurança, qualidade de acesso à Internet e a disponibilidade do serviço entregue ao cliente. Quando bem configurado acelera as consultas dos acessos graças ao seu cache interno, mas para que isso seja percebido pelo assinante, é necessário que esteja o mais próximo possível do seu cliente.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Um erro que destrói a qualidade do nosso serviço ==&lt;br /&gt;
Um erro muito comum que muitas operadoras cometem é utilizar DNS Recursivo externo, como o '''8.8.8.8''', '''1.1.1.1''' e outros, para seus clientes. Quanto mais próximo dos seus clientes, mais qualidade de serviço estará entregando a eles. Conteúdos serão entregues mais rapidamente pois serão resolvidos e armazenados em caches locais e não consultados remotamente na Internet. Para falar mais sobre isso, te convido leitor desse documento, que assista essa palestra do '''Thiago Ayub''' no '''GTER 51/GTS 37''' (2022) '''8.888 MOTIVOS PARA NÃO USAR DNS RECURSIVO EXTERNO EM SEU AS''': https://www.youtube.com/watch?v=Rsvpu5uF2Io&lt;br /&gt;
&lt;br /&gt;
== Objetivo ==&lt;br /&gt;
O objetivo desta documentação não é te ensinar tudo sobre '''DNS''', '''BGP''', '''OSPF''' e nem tão pouco sobre GNU/Linux e sim te mostrar um exemplo de servidor DNS Recursivo implementado pensando em segurança, qualidade e resiliência. Usaremos em todas as nossas documentações o [https://www.debian.org/ Debian GNU/Linux], por ser uma distribuição que considero uma obra de arte criada por uma enorme comunidade séria, com vasta experiência de anos, qualidade no empacotamento dos programas, estável e com uma equipe de segurança excelente e ativa. Caso você leitor, utilize alguma outra distribuição GNU/Linux, todo conteúdo apresentado aqui pode ser aplicado em outras distros, desde que respeitando as particularidades de cada uma.&lt;br /&gt;
&lt;br /&gt;
Aqui construiremos um sistema do tipo '''Anycast''', ou seja, terás o serviço rodando em diversas localidades da sua Rede utilizando o mesmo endereçamento IP e que atenderá seu cliente mais próximo. Em caso de falhas, seus clientes automaticamente e de forma transparente continuarão consultando o DNS mais próximo deles. Para que ele funcione dessa forma você precisará ter uma '''Rede OSPF''' implementada no seu Provedor Internet ou algum outro protocolo como por exemplo o '''ISIS,''' mas esse documento não irá abordar o '''ISIS'''. Também utilizaremos o '''Hyperlocal''' como recurso adicional para gerar algumas proteções de segurança e velocidade na resposta relacionada aos servidores de DNS Raiz da Internet.&lt;br /&gt;
&lt;br /&gt;
== Diagrama ==&lt;br /&gt;
Para exemplificar nosso servidor de DNS Recursivo, usaremos como base das explicações um diagrama demonstrando o uso do DNS Recursivo em uma Rede fictícia. Adotaremos IPs privados e reservados para demonstrar todo o ambiente do Provedor de Internet.&lt;br /&gt;
[[Arquivo:Diagrama dns recursiv2.png|alt=|esquerda|miniaturadaimagem|695x695px]]&lt;br /&gt;
Nesse diagrama podemos observar alguns detalhes técnicos como por exemplo: existem '''3 servidores de DNS Recursivo''' posicionados em locais diferentes, que poderiam estar em bairros diferentes e até em cidades diferentes. Em cada servidor teremos '''2 loopbacks''' com os IPs:&lt;br /&gt;
&lt;br /&gt;
'''10.10.10.10/32 - fc00::10:10:10:10/128'''&lt;br /&gt;
&lt;br /&gt;
'''10.10.9.9/32 - fc00::10:10:9:9/128'''&lt;br /&gt;
&lt;br /&gt;
Esses IPs serão entregues pelos concentradores '''PPPoE''' ou '''IPoE''' ('''BNG''') para seus clientes como '''DNS primário''' e '''secundário'''. Podemos usar IPs privados como DNS primário e secundário em um ambiente real? Sim podemos, desde que não sejam IPs que possam ter problemas com as redes privadas dos clientes. Ex.: rede do cliente usando '''192.168.0.0/24'''. Se entregarmos o DNS sendo '''192.168.0.10''' e '''192.168.0.20''' teremos problemas e o cliente ficará sem Internet, porque '''192.168.0.10''' e '''192.168.0.20''' fazem parte da rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
Agora entregando '''10.10.10.10,''' '''10.10.9.9, fc00::10:10:10:10 e fc00::10:10:9:9''' não teríamos problemas com a rede '''192.168.0.0/24'''.&lt;br /&gt;
&lt;br /&gt;
'''Motivos para usarmos IPs privados:'''&lt;br /&gt;
* O principal motivo está relacionado com a segurança, uma vez que sendo um IP privado, não pode sofrer ataques DDoS direcionados diretamente para ele, vindos da Internet.&lt;br /&gt;
* Nem mesmo o cliente da sua rede conhece os '''IPs públicos''' utilizados para recursividade na Internet.&lt;br /&gt;
* Memorizar os IPs '''10.10.10.10''' e '''10.10.9.9''' é tão fácil quanto memorizar o '''8.8.8.8''' e o '''1.1.1.1'''. Mais fácil para o seu técnico guardar essa informação e utilizar onde for necessário.&lt;br /&gt;
Cada servidor DNS Recursivo possui um '''IPv4 público''', aqui representado por '''198.18.x.x/27''' e um '''IPv6 global''' representado por um IP dentro do prefixo '''2001:db8::/32'''. Cada servidor precisa ter os seus próprios IPs e são através destes IPs que as consultas de DNS serão realizadas na Internet.&lt;br /&gt;
&lt;br /&gt;
Nessa topologia usando '''Anycast''', o cliente será sempre atendido pelo '''DNS Recursivo''' mais próximo, desde que os pesos no '''OSPF''' estejam ajustados corretamente.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
== Dados do servidor ==&lt;br /&gt;
Podemos utilizar um sistema virtualizado ou não. Sistemas virtualizados são bem vindos pois são mais simples quando precisamos fazer backups, levantar outros sistemas sem complicações e se precisarmos restaurar rapidamente algum sistema que ficou indisponível por algum motivo. A configuração abaixo tem capacidade para atender algo em torno a '''50.000 assinantes ou mais'''. O DNS Recursivo é um serviço que pode ser utilizado até mesmo em um '''Raspberry Pi''' e atender operações pequenas, nesse caso com o intuito de economizar energia e espaço. Nosso foco aqui é montar uma rede de '''DNS Recursivo Anycast com HyperLocal'''. Como comentei acima o servidor deve ficar o mais próximo dos clientes para termos a '''menor latência possível''' e '''sempre menor que 5ms''' entre o cliente e o servidor.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!CPU&lt;br /&gt;
!Memória&lt;br /&gt;
!Disco&lt;br /&gt;
!Sistema&lt;br /&gt;
|-&lt;br /&gt;
|2.4Ghz 4 cores&lt;br /&gt;
|16G DDR4&lt;br /&gt;
|30G&lt;br /&gt;
|Debian 12 amd64 (Bookworm)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Softwares utilizados ==&lt;br /&gt;
* Debian 12 amd64 (Bookworm) instalação mínima.&lt;br /&gt;
&lt;br /&gt;
* [https://frrouting.org/ FRRouting].&lt;br /&gt;
* Unbound.&lt;br /&gt;
* IRQBalance.&lt;br /&gt;
* Chrony (NTP/NTS).&lt;br /&gt;
* Shell script em bash.&lt;br /&gt;
&lt;br /&gt;
== Funcionalidades que teremos ==&lt;br /&gt;
* Sistema em Anycast.&lt;br /&gt;
* Hyperlocal.&lt;br /&gt;
* Controle de acesso por &amp;lt;abbr&amp;gt;ACL&amp;lt;/abbr&amp;gt;.&lt;br /&gt;
* RPZ (Response Policy Zone).&lt;br /&gt;
* Bloqueio de consultas do tipo ANY.&lt;br /&gt;
* QNAME minimization habilitado. (habilitado por default no Unbound)&lt;br /&gt;
* Recursividade em IPv4 e IPv6.&lt;br /&gt;
* DNSSEC habilitado.&lt;br /&gt;
* &amp;lt;abbr&amp;gt;DoH (DNS&amp;lt;/abbr&amp;gt; over HTTPS) habilitado.&lt;br /&gt;
&lt;br /&gt;
== Monitoramento ==&lt;br /&gt;
O monitoramento é algo bem específico e não é o foco deste documento mas é extremamente importante que você monitore seus servidores de DNS por alguma ferramenta como o Zabbix. Aqui mostrarei apenas como enviar as informações para o Zabbix. Algumas coisas que você deveria monitorar nos servidores de DNS Recursivo:&lt;br /&gt;
* Serviço do unbound parou.&lt;br /&gt;
* Perda de pacotes.&lt;br /&gt;
* Latência alta de pacotes.&lt;br /&gt;
* Lentidão na resolução de queries.&lt;br /&gt;
* CPU alta.&lt;br /&gt;
* Load alto.&lt;br /&gt;
* Memória com uso alto.&lt;br /&gt;
* Disco com pouco espaço.&lt;br /&gt;
* Queda brusca nas queries.&lt;br /&gt;
* A recursividade parou de funcionar.&lt;br /&gt;
* A recursividade voltou a funcionar.&lt;br /&gt;
Este abaixo é um exemplo de monitoramento de um sistema de DNS Recursivo que atende 50.000 assinantes:&lt;br /&gt;
[[Arquivo:Grafana dns.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Configurando a Rede ==&lt;br /&gt;
Nossa documentação será baseada no diagrama apresentado acima e por isso configuraremos apenas um dos três servidores, porque os outros serão configurados da mesma forma, só que com dados diferentes. Para tanto assumirei que já temos um sistema Debian instalado com o mínimo de pacotes e somente com sshd, para que possamos acessar remotamente mais tarde. '''Não instale um ambiente gráfico no servidor''', você não deve querer fazer isso por diversos motivos e os principais: primeiro porque não é um Desktop e segundo porque o ambiente gráfico devoraria toda a memória com recursos que não seriam úteis aqui.&lt;br /&gt;
&lt;br /&gt;
Em '''/etc/network/interfaces''' deixaremos assim:&lt;br /&gt;
 # This file describes the network interfaces available on your system&lt;br /&gt;
 # and how to activate them. For more information, see interfaces(5).&lt;br /&gt;
  &lt;br /&gt;
 source /etc/network/interfaces.d/*&lt;br /&gt;
  &lt;br /&gt;
 # The loopback network interface&lt;br /&gt;
 auto lo&lt;br /&gt;
 iface lo inet loopback&lt;br /&gt;
  &lt;br /&gt;
 auto lo:0&lt;br /&gt;
 iface lo:0 inet static&lt;br /&gt;
       address 10.10.10.10/32&lt;br /&gt;
  &lt;br /&gt;
 auto lo:1&lt;br /&gt;
 iface lo:1 inet static&lt;br /&gt;
       address 10.10.9.9/32&lt;br /&gt;
 &lt;br /&gt;
 auto lo:2&lt;br /&gt;
 iface lo:2 inet6 static&lt;br /&gt;
       address fc00::10:10:10:10/128&lt;br /&gt;
 &lt;br /&gt;
 auto lo:3&lt;br /&gt;
 iface lo:3 inet6 static&lt;br /&gt;
       address fc00::10:10:9:9/128&lt;br /&gt;
  &lt;br /&gt;
 # The primary network interface&lt;br /&gt;
 auto ens18&lt;br /&gt;
 iface ens18 inet static&lt;br /&gt;
         address 198.18.1.10/27&lt;br /&gt;
         gateway 198.18.1.1&lt;br /&gt;
  &lt;br /&gt;
 iface ens18 inet6 static&lt;br /&gt;
         address 2001:db8::faca:198:18:1:10/64&lt;br /&gt;
         gateway 2001:db8::faca:198:18:1:1&lt;br /&gt;
  &lt;br /&gt;
 # The secondary network interface&lt;br /&gt;
 auto ens18:0&lt;br /&gt;
 iface ens18:0 inet static&lt;br /&gt;
         address 172.16.0.6/30&lt;br /&gt;
Nesse cenário temos as duas '''loopbacks''' com os IPs '''10.10.10.10''', '''10.10.9.9, fc00::10:10:10:10''' e '''fc00::10:10:9:9''' que serão anunciados via OSPF para a rede e serem entregues aos clientes via BNG. Os IPs '''198.18.1.10''' e '''2001:db8::faca:198:18:1:10''' serão usados para fazerem a recursividade na Internet tanto em IPv4 quanto em IPv6. Esses IPs não devem ser divulgados para clientes; os IPs públicos são dedicados apenas para essa finalidade.&lt;br /&gt;
&lt;br /&gt;
== Configuração dos repositórios Debian ==&lt;br /&gt;
Deixe o arquivo '''/etc/apt/sources.list''' conforme abaixo:&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://security.debian.org/debian-security&amp;lt;/nowiki&amp;gt; bookworm-security main contrib non-free non-free-firmware&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian&amp;lt;/nowiki&amp;gt; bookworm main contrib non-free non-free-firmware&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian&amp;lt;/nowiki&amp;gt; bookworm-updates main contrib non-free non-free-firmware&lt;br /&gt;
 deb &amp;lt;nowiki&amp;gt;http://deb.debian.org/debian&amp;lt;/nowiki&amp;gt; bookworm-backports main contrib non-free non-free-firmware&lt;br /&gt;
Após a configuração vamos instalar alguns pacotes necessários e outros úteis:&lt;br /&gt;
 # apt update &amp;amp;&amp;amp; apt full-upgrade&lt;br /&gt;
 # apt install net-tools nftables htop iotop sipcalc tcpdump curl gnupg rsync wget host dnsutils mtr-tiny bmon sudo tmux whois ethtool dnstop&lt;br /&gt;
&lt;br /&gt;
== Fazendo algum tuning no sistema ==&lt;br /&gt;
Em '''/etc/sysctl.conf''' adicionamos no final do arquivo essas instruções:&lt;br /&gt;
 net.core.rmem_max = 2147483647&lt;br /&gt;
 net.core.wmem_max = 2147483647&lt;br /&gt;
 net.ipv4.tcp_rmem = 4096 87380 2147483647&lt;br /&gt;
 net.ipv4.tcp_wmem = 4096 65536 2147483647&lt;br /&gt;
 net.netfilter.nf_conntrack_buckets = 512000&lt;br /&gt;
 net.netfilter.nf_conntrack_max = 4096000&lt;br /&gt;
 vm.swappiness=10&lt;br /&gt;
Estamos fazendo algumas melhorias de memória, algumas relacionadas a '''conntrack''' porque se for usar um filtro de pacotes stateful, como o '''Netfilter/IPTables''' ou '''Netfilter/NFTables''', o valor default da tabela é pequeno e dependendo da situação, se estourar essa tabela, as consultas de DNS terão problemas também. O DNS Recursivo não deve ficar aberto para qualquer um na Internet, ele deve ser liberado apenas para seus clientes. Podemos fazer através das ACLs do Unbound e pelo filtro de pacotes. O último parâmetro diz respeito ao uso de swap, por padrão o Debian permite o uso de swap após 40% do uso da memória, nesse caso estamos dizendo para o sistema usar o swap com 90% de uso da memória.&lt;br /&gt;
&lt;br /&gt;
Precisamos adicionar o módulo '''nf_conntrack''' em '''/etc/modules''' para que seja carregado em tempo de boot, senão os parâmetros de '''conntrack''' que colocamos em '''/etc/sysctl.conf''' não serão carregados.&lt;br /&gt;
 # echo nf_conntrack &amp;gt;&amp;gt; /etc/modules&lt;br /&gt;
 # modprobe nf_conntrack&lt;br /&gt;
 # sysctl -p&lt;br /&gt;
&lt;br /&gt;
== Instalando o FRRouting ==&lt;br /&gt;
O FRRouting é o programa que usaremos para fazer os anúncios das nossas loopbacks via OSPF. Nesse documento usaremos a versão 10.x e para isso precisaremos configurar o repositório oficial do FRRouting e instalar os pacotes:&lt;br /&gt;
 # curl -s &amp;lt;nowiki&amp;gt;https://deb.frrouting.org/frr/keys.gpg&amp;lt;/nowiki&amp;gt; | tee /usr/share/keyrings/frrouting.gpg &amp;gt; /dev/null&lt;br /&gt;
 # echo &amp;quot;deb [signed-by=/usr/share/keyrings/frrouting.gpg] &amp;lt;nowiki&amp;gt;https://deb.frrouting.org/frr&amp;lt;/nowiki&amp;gt; bookworm frr-10&amp;quot; &amp;gt; /etc/apt/sources.list.d/frr.list&lt;br /&gt;
 # apt update&lt;br /&gt;
 # apt install frr frr-doc frr-pythontools&lt;br /&gt;
Aconselho depois de instalar os pacotes, marcá-los para não atualizar juntamente com os demais pacotes, isso é para evitar de ocorrer alguma atualização no FRRouting, que torne o serviço instável por algum motivo. Não que isso vá ocorrer, mas é melhor fazer essa atualização quando realmente for necessário.&lt;br /&gt;
 # apt-mark hold frr frr-doc frr-pythontools&lt;br /&gt;
Após esse comando acima, o sistema manterá a instalação original do pacote intacta. Para desbloquear basta executar o comando abaixo:&lt;br /&gt;
 # apt-mark unhold frr frr-doc frr-pythontools&lt;br /&gt;
&lt;br /&gt;
== Removendo o APPARMOR ==&lt;br /&gt;
O '''APPARMOR''' às vezes causa mais problemas que solução e se não for fazer uma completa configuração nele, é melhor desabilitá-lo. Para fazer isso efetivamente, o procedimento é esse abaixo:&lt;br /&gt;
 # mkdir -p /etc/default/grub.d&lt;br /&gt;
 # echo 'GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;$GRUB_CMDLINE_LINUX_DEFAULT apparmor=0&amp;quot;' | tee /etc/default/grub.d/apparmor.cfg&lt;br /&gt;
 # update-grub&lt;br /&gt;
 # reboot&lt;br /&gt;
&lt;br /&gt;
== Instalando o Unbound ==&lt;br /&gt;
Nesse momento ainda não iremos configurar o Unbound, apenas instalar o pacote e acertar o ambiente. Vamos instalar o unbound do backports porque este já possui suporte ao DoH que veremos mais à frente.&lt;br /&gt;
 # apt install unbound dns-root-data&lt;br /&gt;
 # mkdir -p /var/log/unbound&lt;br /&gt;
 # touch /var/log/unbound/unbound.log&lt;br /&gt;
 # chown -R unbound:unbound /var/log/unbound/&lt;br /&gt;
 # systemctl restart unbound&lt;br /&gt;
Configurando o logrotate:&lt;br /&gt;
 cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/logrotate.d/unbound&lt;br /&gt;
 /var/log/unbound/unbound.log {&lt;br /&gt;
     rotate 5&lt;br /&gt;
     weekly&lt;br /&gt;
     postrotate&lt;br /&gt;
         unbound-control log_reopen&lt;br /&gt;
     endscript&lt;br /&gt;
 }&lt;br /&gt;
 EOF&lt;br /&gt;
Reiniciando o serviço:&lt;br /&gt;
 # systemctl restart logrotate.service&lt;br /&gt;
&lt;br /&gt;
== Preparando o monitoramento do seu DNS Recursivo ==&lt;br /&gt;
O monitoramento do seu DNS Recursivo é muito importante e para isso vamos usar um '''template para Zabbix''', que modifiquei juntamente com o seu shell script e que enviará os dados para o seu Zabbix server via '''zabbix-sender'''. O projeto original está aqui '''https://github.com/jeftedelima/Unbound-DNS&amp;lt;nowiki/&amp;gt;.''' O xml alterado está aqui '''https://github.com/gondimcodes/template_zabbix_dns_unbound'''. Embora seja antigo é perfeitamente importável no Zabbix 6.0, por exemplo.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;nowiki/&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Teremos um shell script que você precisará colocar no seu '''/etc/crontab'''. No exemplo abaixo assumi que o shell script está em '''/root/scripts'''. De 5 em 5 minutos os dados serão enviados para o seu Zabbix server.&lt;br /&gt;
 */5 * * * *     root    /root/scripts/unboundSend.sh '''IP_zabbix_server''' '''nome_do_host''' 1&amp;gt; /dev/null&lt;br /&gt;
Na linha acima, troque o '''IP_zabbix_server''' pelo '''IP do seu servidor Zabbix''' e o '''nome_do_host''' pelo '''hostname''' '''do seu DNS Recursivo'''. Você precisará instalar o pacote '''zabbix-sender''' no seu DNS Recursivo pois ele será usado para enviar os dados para o Zabbix server.&lt;br /&gt;
&lt;br /&gt;
Abaixo o '''unboundSend.sh''' também alterado com inclusão de mais dados:&lt;br /&gt;
 #!/bin/bash&lt;br /&gt;
 #       @Jefte de Lima Ferreira&lt;br /&gt;
 #       jeftedelima at gmail dot com&lt;br /&gt;
 #       CRON Example&lt;br /&gt;
 #       Contributor: Marcelo Gondim - gondim at gmail dot com&lt;br /&gt;
 #       */5   **** root sh /home/dir/unboundSend.sh 192.168.10.1 Unbound 1&amp;gt; /dev/null&lt;br /&gt;
 &lt;br /&gt;
 if [ -z ${1} ] || [ -z ${2} ] ; then&lt;br /&gt;
         echo &amp;quot;You need to specify the IP address of zabbix server and hostname of your DNS Unbound on zabbix&amp;quot;&lt;br /&gt;
         echo &amp;quot;Usage example: ./unboundSend.sh 192.168.10.1 UnboundServer&amp;quot;&lt;br /&gt;
         exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
 # ZABBIX_SERVER IP&lt;br /&gt;
 IP_ZABBIX=$1&lt;br /&gt;
 # NAME Unbound on Zabbix&lt;br /&gt;
 NAME_HOST=$2&lt;br /&gt;
 DIR_TEMP=/var/tmp/&lt;br /&gt;
 FILE=&amp;quot;${DIR_TEMP}dump_unbound_control_stats.txt&amp;quot;&lt;br /&gt;
 unbound-control stats &amp;gt; ${FILE}&lt;br /&gt;
 &lt;br /&gt;
 TOTAL_NUM_QUERIES=$(cat ${FILE} | grep -w 'total.num.queries' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEHITS=$(cat ${FILE} | grep -w 'total.num.cachehits' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_CACHEMISS=$(cat ${FILE} | grep -w 'total.num.cachemiss' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_PREFETCH=$(cat ${FILE} | grep -w 'total.num.prefetch' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_NUM_RECURSIVEREPLIES=$(cat ${FILE} | grep -w 'total.num.recursivereplies' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 TOTAL_REQ_MAX=$(cat ${FILE} | grep -w 'total.requestlist.max' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_AVG=$(cat ${FILE} | grep -w 'total.requestlist.avg' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_OVERWRITTEN=$(cat ${FILE} | grep -w 'total.requestlist.overwritten' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_EXCEEDED=$(cat ${FILE} | grep -w 'total.requestlist.exceeded' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_ALL=$(cat ${FILE} | grep -w 'total.requestlist.current.all' | cut -d '=' -f2)&lt;br /&gt;
 TOTAL_REQ_CURRENT_USER=$(cat ${FILE} | grep -w 'total.requestlist.current.user' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 TOTAL_TCPUSAGE=$(cat ${FILE} | grep -w 'total.tcpusage' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 NUM_QUERY_TYPE_A=$(cat ${FILE} | grep -w 'num.query.type.A' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NS=$(cat ${FILE} | grep -w 'num.query.type.NS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_MX=$(cat ${FILE} | grep -w 'num.query.type.MX' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TXT=$(cat ${FILE} | grep -w 'num.query.type.TXT' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_PTR=$(cat ${FILE} | grep -w 'num.query.type.PTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_AAAA=$(cat ${FILE} | grep -w 'num.query.type.AAAA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SRV=$(cat ${FILE} | grep -w 'num.query.type.SRV' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SOA=$(cat ${FILE} | grep -w 'num.query.type.SOA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HTTPS=$(cat ${FILE} | grep -w 'num.query.type.HTTPS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TYPE0=$(cat ${FILE} | grep -w 'num.query.type.TYPE0' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_CNAME=$(cat ${FILE} | grep -w 'num.query.type.CNAME' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_WKS=$(cat ${FILE} | grep -w 'num.query.type.WKS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_HINFO=$(cat ${FILE} | grep -w 'num.query.type.HINFO' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_X25=$(cat ${FILE} | grep -w 'num.query.type.X25' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_NAPTR=$(cat ${FILE} | grep -w 'num.query.type.NAPTR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DS=$(cat ${FILE} | grep -w 'num.query.type.DS' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_DNSKEY=$(cat ${FILE} | grep -w 'num.query.type.DNSKEY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_TLSA=$(cat ${FILE} | grep -w 'num.query.type.TLSA' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SVCB=$(cat ${FILE} | grep -w 'num.query.type.SVCB' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_SPF=$(cat ${FILE} | grep -w 'num.query.type.SPF' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_ANY=$(cat ${FILE} | grep -w 'num.query.type.ANY' | cut -d '=' -f2)&lt;br /&gt;
 NUM_QUERY_TYPE_OTHER=$(cat ${FILE} | grep -w 'num.query.type.other' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 NUM_ANSWER_RCODE_NOERROR=$(cat ${FILE} | grep -w 'num.answer.rcode.NOERROR' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_NXDOMAIN=$(cat ${FILE} | grep -w 'num.answer.rcode.NXDOMAIN' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_SERVFAIL=$(cat ${FILE} | grep -w 'num.answer.rcode.SERVFAIL' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_REFUSED=$(cat ${FILE} | grep -w 'num.answer.rcode.REFUSED' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_RCODE_nodata=$(cat ${FILE} | grep -w 'num.answer.rcode.nodata' | cut -d '=' -f2)&lt;br /&gt;
 NUM_ANSWER_secure=$(cat ${FILE} | grep -w 'num.answer.secure' | cut -d '=' -f2)&lt;br /&gt;
 &lt;br /&gt;
 #       Sending info to zabbix_server, if variables is not empty!&lt;br /&gt;
 [ -z ${TOTAL_NUM_QUERIES} ] ||  zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.queries -o $((TOTAL_NUM_QUERIES/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_CACHEHITS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachehits -o $((TOTAL_NUM_CACHEHITS/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_CACHEMISS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.cachemiss -o $((TOTAL_NUM_CACHEMISS/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_PREFETCH} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.prefetch -o $((TOTAL_NUM_PREFETCH/300))&lt;br /&gt;
 [ -z ${TOTAL_NUM_RECURSIVEREPLIES} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.num.recursivereplies -o $((TOTAL_NUM_RECURSIVEREPLIES/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${TOTAL_REQ_MAX} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.max -o $((TOTAL_REQ_MAX/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_AVG} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.avg -o $((TOTAL_REQ_AVG/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_OVERWRITTEN} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.overwritten -o $((TOTAL_REQ_OVERWRITTEN/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_EXCEEDED} ] ||  zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.exceeded -o $((TOTAL_REQ_EXCEEDED/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_CURRENT_ALL} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.all -o $((TOTAL_REQ_CURRENT_ALL/300))&lt;br /&gt;
 [ -z ${TOTAL_REQ_CURRENT_USER} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.requestlist.current.user -o $((TOTAL_REQ_CURRENT_USER/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${TOTAL_TCPUSAGE} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k total.tcpusage -o $((TOTAL_TCPUSAGE/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_A} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.a -o $((NUM_QUERY_TYPE_A/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_NS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ns -o $((NUM_QUERY_TYPE_NS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_MX} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.mx -o $((NUM_QUERY_TYPE_MX/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_TXT} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.txt -o $((NUM_QUERY_TYPE_TXT/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_PTR} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ptr -o $((NUM_QUERY_TYPE_PTR/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_AAAA} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.aaaa -o $((NUM_QUERY_TYPE_AAAA/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SRV} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.srv -o $((NUM_QUERY_TYPE_SRV/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SOA} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.soa -o $((NUM_QUERY_TYPE_SOA/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_HTTPS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.https -o $((NUM_QUERY_TYPE_HTTPS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_TYPE0} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.type0 -o $((NUM_QUERY_TYPE_TYPE0/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_CNAME} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.cname -o $((NUM_QUERY_TYPE_CNAME/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_WKS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.wks -o $((NUM_QUERY_TYPE_WKS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_HINFO} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.hinfo -o $((NUM_QUERY_TYPE_HINFO/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_X25} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.X25 -o $((NUM_QUERY_TYPE_X25/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_NAPTR} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.naptr -o $((NUM_QUERY_TYPE_NAPTR/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_DS} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.ds -o $((NUM_QUERY_TYPE_DS/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_DNSKEY} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.dnskey -o $((NUM_QUERY_TYPE_DNSKEY/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_TLSA} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.tlsa -o $((NUM_QUERY_TYPE_TLSA/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SVCB} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.svcb -o $((NUM_QUERY_TYPE_SVCB/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_SPF} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.spf -o $((NUM_QUERY_TYPE_SPF/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_ANY} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.any -o $((NUM_QUERY_TYPE_ANY/300))&lt;br /&gt;
 [ -z ${NUM_QUERY_TYPE_OTHER} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.query.other -o $((NUM_QUERY_TYPE_OTHER/300))&lt;br /&gt;
 &lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_NOERROR} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NOERROR -o $((NUM_ANSWER_RCODE_NOERROR/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_NXDOMAIN} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.NXDOMAIN -o $((NUM_ANSWER_RCODE_NXDOMAIN/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_SERVFAIL} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.SERVFAIL -o $((NUM_ANSWER_RCODE_SERVFAIL/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_REFUSED} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.REFUSED -o $((NUM_ANSWER_RCODE_REFUSED/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_RCODE_nodata} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.rcode.nodata -o $((NUM_ANSWER_RCODE_nodata/300))&lt;br /&gt;
 [ -z ${NUM_ANSWER_secure} ] || zabbix_sender -z ${IP_ZABBIX} -s ${NAME_HOST} -k num.answer.secure -o $((NUM_ANSWER_secure/300))&lt;br /&gt;
No Zabbix será registrado dados como esses abaixo e posteriormente pode ser montado um Grafana com eles:&lt;br /&gt;
[[Arquivo:Zabbix dns01.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns02.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns03.png|nenhum|commoldura]]&lt;br /&gt;
[[Arquivo:Zabbix dns04.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Balanceando o processamento e mantendo a hora certa ==&lt;br /&gt;
Vamos instalar 2 programas agora, o IRQBalance e o Chrony. O primeiro para balancear a carga entre os cores e o segundo para manter a data e hora certas no sistema:&lt;br /&gt;
 # apt install irqbalance&lt;br /&gt;
 # systemctl enable irqbalance&lt;br /&gt;
 # apt install chrony&lt;br /&gt;
Após a instalação do Chrony edite o arquivo /etc/chrony/chrony.conf, comente e a linha abaixo e adicione seus servidores NTP. Caso não tenha servidores NTP, estou colocando os do NIC.br aqui.&lt;br /&gt;
 #pool 2.debian.pool.ntp.org iburst&lt;br /&gt;
 server a.st1.ntp.br iburst nts&lt;br /&gt;
 server b.st1.ntp.br iburst nts&lt;br /&gt;
 server c.st1.ntp.br iburst nts&lt;br /&gt;
 server d.st1.ntp.br iburst nts&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart chronyd.service&lt;br /&gt;
Cheque com o '''chronyc''' se os servidores estão OK:&lt;br /&gt;
 # chronyc sourcestats&lt;br /&gt;
 Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev&lt;br /&gt;
 ==============================================================================&lt;br /&gt;
 a.st1.ntp.br               10   5  155m     -0.027      0.030    -71us    51us&lt;br /&gt;
 b.st1.ntp.br               11   7  344m     +0.068      0.079    +23ms   382us&lt;br /&gt;
 c.st1.ntp.br                6   3  344m     +0.026      0.037   -124us    92us&lt;br /&gt;
 200.20.186.76               9   3  138m     -0.022      0.031   +172us    42us&lt;br /&gt;
&lt;br /&gt;
 # chronyc sources&lt;br /&gt;
 MS Name/IP address         Stratum Poll Reach LastRx Last sample&lt;br /&gt;
 ===============================================================================&lt;br /&gt;
 ^* a.st1.ntp.br                  1  10   377   588   +487us[ +397us] +/-   12ms&lt;br /&gt;
 ^- b.st1.ntp.br                  2  10   377   830    +23ms[  +23ms] +/-   49ms&lt;br /&gt;
 ^+ c.st1.ntp.br                  2  10    21  1038   -147us[ -242us] +/-   17ms&lt;br /&gt;
 ^+ 200.20.186.76                 1  10   377  1032   +381us[ +285us] +/-   15ms&lt;br /&gt;
&lt;br /&gt;
== Configurando o FRRouting ==&lt;br /&gt;
Nesse ponto iremos configurar o '''FRRouting''' para enviar os IPs das '''loopbacks''' e o '''/30''' para o nosso PE do diagrama. Em '''/etc/frr/daemons''' habilite o parâmetro conforme abaixo:&lt;br /&gt;
 ospfd=yes&lt;br /&gt;
Edite o arquivo '''/etc/frr/frr.conf''' e deixe com o conteúdo abaixo, para ficar conforme nosso diagrama do projeto. Apenas troque '''&amp;lt;SENHA&amp;gt;''' por uma senha para fechar o OSPF com mais segurança. Essa senha deve ser usada dos dois lados.&lt;br /&gt;
 frr version 10.2.1&lt;br /&gt;
 frr defaults traditional&lt;br /&gt;
 hostname dns-recursivo-01&lt;br /&gt;
 log syslog informational&lt;br /&gt;
 no ip forwarding&lt;br /&gt;
 no ipv6 forwarding&lt;br /&gt;
 service integrated-vtysh-config&lt;br /&gt;
 !&lt;br /&gt;
 interface ens18&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf message-digest-key 5 md5 &amp;lt;SENHA&amp;gt;&lt;br /&gt;
  ip ospf network point-to-point&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 network point-to-point&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 interface lo&lt;br /&gt;
  description LOOPBACKS&lt;br /&gt;
  ip ospf area 0.0.0.0&lt;br /&gt;
  ip ospf passive&lt;br /&gt;
  ipv6 ospf6 area 0.0.0.0&lt;br /&gt;
  ipv6 ospf6 passive&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf&lt;br /&gt;
  ospf router-id 172.16.0.6&lt;br /&gt;
  area 0.0.0.0 authentication message-digest&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
 router ospf6&lt;br /&gt;
  ospf6 router-id 172.16.0.6&lt;br /&gt;
 exit&lt;br /&gt;
 !&lt;br /&gt;
&lt;br /&gt;
 # systemctl restart frr.service&lt;br /&gt;
Cheque se está tudo OK com o OSPF e verifique no PE se está recebendo os prefixos anunciados.&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL&lt;br /&gt;
 172.16.0.5     1 Full/-          10m49s            35.310s 172.16.0.5   ens18:172.16.0.6                  0     0     0&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor'&lt;br /&gt;
 &lt;br /&gt;
 Neighbor ID     Pri    DeadTime    State/IfState         Duration I/F[State]&lt;br /&gt;
 172.16.0.5       1    00:00:30     Full/PointToPoint 25d22:53:47 ens18[PointToPoint]&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ip ospf neighbor detail'&lt;br /&gt;
 &lt;br /&gt;
  Neighbor 172.16.0.5, interface address 172.16.0.5&lt;br /&gt;
     In the area 0.0.0.0 via interface ens18&lt;br /&gt;
     Neighbor priority is 1, State is Full/-, 5 state changes&lt;br /&gt;
     Most recent state change statistics:&lt;br /&gt;
       Progressive change 21w3d15h ago&lt;br /&gt;
     DR is 0.0.0.0, BDR is 0.0.0.0&lt;br /&gt;
     Options 18 *|-|-|EA|-|-|E|-&lt;br /&gt;
     Dead timer due in 34.685s&lt;br /&gt;
     Database Summary List 0&lt;br /&gt;
     Link State Request List 0&lt;br /&gt;
     Link State Retransmission List 0&lt;br /&gt;
     Thread Inactivity Timer on&lt;br /&gt;
     Thread Database Description Retransmision off&lt;br /&gt;
     Thread Link State Request Retransmission on&lt;br /&gt;
     Thread Link State Update Retransmission on&lt;br /&gt;
 &lt;br /&gt;
     Graceful restart Helper info:&lt;br /&gt;
       Graceful Restart HELPER Status : None&lt;br /&gt;
&lt;br /&gt;
 # vtysh -c 'show ipv6 ospf6 neighbor detail'&lt;br /&gt;
  Neighbor 172.16.0.5%ens18&lt;br /&gt;
     Area 0.0.0.0 via interface ens18 (ifindex 4)&lt;br /&gt;
     His IfIndex: 60 Link-local address: fe80::469b:c1ff:fed6:43ee&lt;br /&gt;
     State Full for a duration of 25d22:57:14&lt;br /&gt;
     His choice of DR/BDR 0.0.0.0/0.0.0.0, Priority 1&lt;br /&gt;
     DbDesc status: Master SeqNum: 0xb94b0000&lt;br /&gt;
     Summary-List: 0 LSAs&lt;br /&gt;
     Request-List: 0 LSAs&lt;br /&gt;
     Retrans-List: 0 LSAs&lt;br /&gt;
     0 Pending LSAs for DbDesc in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSReq in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off]&lt;br /&gt;
     0 Pending LSAs for LSAck in Time 00:00:00 [thread off]&lt;br /&gt;
     Authentication header not present&lt;br /&gt;
&lt;br /&gt;
== Configurando o Unbound ==&lt;br /&gt;
Abaixo a configuração que usaremos nos servidores atentando para o detalhe do '''num-threads''', esse deve ter o valor igual ao número de CPUs do servidor.&lt;br /&gt;
&lt;br /&gt;
Também os IPs utilizados em '''outgoing-interface''' que serão diferentes em cada servidor, esses serão os IPs usados para '''recursividade'''. Consulte o manual do Unbound para obter mais informações sobre cada parâmetro listado na configuração.&lt;br /&gt;
&lt;br /&gt;
O tuning no Unbound pode ser alterado conforme abaixo:&lt;br /&gt;
 num-threads = nº CPUs&lt;br /&gt;
 so-reuseport = yes&lt;br /&gt;
 *-slabs = potência de 2 próximo ao num-threads&lt;br /&gt;
 msg-cache-size = 1g (quantidade de memória pra usar de cache)&lt;br /&gt;
 rrset-cache-size = 2 * msg-cache-size&lt;br /&gt;
 outgoing-range = 8192&lt;br /&gt;
 num-queries-per-thread = 4096&lt;br /&gt;
 so-rcvbuf e so-sndbuf = 4m ou 8m para servidores com muita requisição&lt;br /&gt;
Agora vamos criar nosso arquivo de configuração base em '''/etc/unbound/unbound.conf.d/local.conf''':&lt;br /&gt;
 server:&lt;br /&gt;
         verbosity: 1&lt;br /&gt;
         statistics-interval: 0&lt;br /&gt;
         statistics-cumulative: no&lt;br /&gt;
         extended-statistics: yes&lt;br /&gt;
         num-threads: 4&lt;br /&gt;
         serve-expired: yes&lt;br /&gt;
         interface: 127.0.0.1&lt;br /&gt;
         interface: 10.10.10.10&lt;br /&gt;
         interface: 10.10.9.9&lt;br /&gt;
         interface: 172.16.0.6&lt;br /&gt;
         interface: fc00::10:10:10:10&lt;br /&gt;
         interface: fc00::10:10:9:9&lt;br /&gt;
         interface: ::1&lt;br /&gt;
         interface-automatic: no&lt;br /&gt;
         outgoing-interface: 198.18.1.10&lt;br /&gt;
         outgoing-interface: 2001:db8::faca:198:18:1:10&lt;br /&gt;
         outgoing-range: 8192&lt;br /&gt;
         outgoing-num-tcp: 1024&lt;br /&gt;
         incoming-num-tcp: 2048&lt;br /&gt;
         so-rcvbuf: 4m&lt;br /&gt;
         so-sndbuf: 4m&lt;br /&gt;
         so-reuseport: yes&lt;br /&gt;
         edns-buffer-size: 1232&lt;br /&gt;
         msg-cache-size: 1g&lt;br /&gt;
         msg-cache-slabs: 4&lt;br /&gt;
         num-queries-per-thread: 4096&lt;br /&gt;
         rrset-cache-size: 2g&lt;br /&gt;
         rrset-cache-slabs: 4&lt;br /&gt;
         infra-cache-slabs: 4&lt;br /&gt;
         do-ip4: yes&lt;br /&gt;
         do-ip6: yes&lt;br /&gt;
         do-udp: yes&lt;br /&gt;
         do-tcp: yes&lt;br /&gt;
         chroot: &amp;quot;&amp;quot;&lt;br /&gt;
         username: &amp;quot;unbound&amp;quot;&lt;br /&gt;
         directory: &amp;quot;/etc/unbound&amp;quot;&lt;br /&gt;
         logfile: &amp;quot;/var/log/unbound/unbound.log&amp;quot;&lt;br /&gt;
         use-syslog: no&lt;br /&gt;
         log-time-ascii: yes&lt;br /&gt;
         log-queries: no&lt;br /&gt;
         pidfile: &amp;quot;/var/run/unbound.pid&amp;quot;&lt;br /&gt;
         root-hints: &amp;quot;/usr/share/dns/root.hints&amp;quot;&lt;br /&gt;
         hide-identity: yes&lt;br /&gt;
         hide-version: yes&lt;br /&gt;
         unwanted-reply-threshold: 10000000&lt;br /&gt;
         prefetch: yes&lt;br /&gt;
         prefetch-key: yes&lt;br /&gt;
         rrset-roundrobin: yes&lt;br /&gt;
         minimal-responses: yes&lt;br /&gt;
         module-config: &amp;quot;respip validator iterator&amp;quot;&lt;br /&gt;
         val-clean-additional: yes&lt;br /&gt;
         val-log-level: 1&lt;br /&gt;
         key-cache-slabs: 4&lt;br /&gt;
         deny-any: yes&lt;br /&gt;
         cache-min-ttl: 60&lt;br /&gt;
         key-cache-size: 128m&lt;br /&gt;
         neg-cache-size: 64m&lt;br /&gt;
         cache-max-ttl: 86400&lt;br /&gt;
         infra-cache-numhosts: 100000&lt;br /&gt;
         access-control: 198.18.0.0/22 allow&lt;br /&gt;
         access-control: 2001:db8::/32 allow&lt;br /&gt;
  &lt;br /&gt;
 rpz:&lt;br /&gt;
   name: rpz.block.host.local.zone&lt;br /&gt;
   zonefile: /etc/unbound/rpz.block.hosts.zone&lt;br /&gt;
   rpz-action-override: nxdomain&lt;br /&gt;
  &lt;br /&gt;
 python:&lt;br /&gt;
  &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;.&amp;quot;&lt;br /&gt;
     master: &amp;quot;b.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;c.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;d.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;f.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;g.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;k.root-servers.net&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/root.zone&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 auth-zone:&lt;br /&gt;
     name: &amp;quot;arpa.&amp;quot;&lt;br /&gt;
     master: &amp;quot;lax.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     master: &amp;quot;iad.xfr.dns.icann.org&amp;quot;&lt;br /&gt;
     fallback-enabled: yes&lt;br /&gt;
     for-downstream: no&lt;br /&gt;
     for-upstream: yes&lt;br /&gt;
     zonefile: &amp;quot;/var/lib/unbound/arpa.zone&amp;quot;&lt;br /&gt;
No parâmetro '''interface''' colocamos os IPs que serão usados para consulta dos clientes como o '''10.10.10.10''', '''10.10.9.9, fc00::10:10:10:10 e fc00::10:10:9:9'''. Ali repare que coloquei também o IP privado '''172.16.0.6''', isso porque cada servidor terá o seu IP privado e este deve ser usado pelo seu sistema de monitoramento para checar cada servidor. No '''outgoing-interface''' teremos os IPs, tanto '''IPv4''' quanto '''IPv6''', para que seja feita a recursividade na Internet utilizando eles. Não tem '''IPv6''' ainda na sua rede? Dê uma olhada nesse artigo. Outro parâmetro importante é o '''access-control''' e é através dele que liberamos os prefixos IP para consultarem no nosso DNS Recursivo. No exemplo estou liberando todo o prefixo '''198.18.0.0/22''' e o prefixo '''2001:db8::/32'''. Além da ACL no Unbound, recomendo que crie um filtro de pacotes com iptables ou nftables protegendo seu sistema e liberando as portas '''53/UDP''', '''53/TCP,'''  '''443/TCP e 853/TCP''' apenas para seus clientes. Falarei sobre a '''443/TCP e 853/TCP''' mais para frente nessa mesma documentação.&lt;br /&gt;
&lt;br /&gt;
Agora criaremos o arquivo '''RPZ''' ('''Response Policy Zones'''). Esse arquivo contém os sites que serão bloqueados via '''&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; Recursivo'''. São aqueles sites que às vezes você recebe um Ofício da Justiça solicitando o bloqueio deles. Não entrarei no mérito da efetividade desses bloqueios, porque muitos de vocês sabem que tecnicamente, existem formas de se fazer um bypass através desses bloqueios. Contudo vamos deixar nosso ambiente preparado para esses bloqueios e por isso crie o arquivo '''/etc/unbound/rpz.block.hosts.zone''' com esse conteúdo de exemplo:&lt;br /&gt;
 $TTL 2h&lt;br /&gt;
 @ IN SOA localhost. root.localhost. (2 6h 1h 1w 2h)&lt;br /&gt;
   IN NS  localhost.&lt;br /&gt;
 ; RPZ manual block hosts&lt;br /&gt;
 *.josedascoves.com CNAME .&lt;br /&gt;
 josedascoves.com CNAME .&lt;br /&gt;
No exemplo acima estamos bloqueando qualquer consulta de DNS para '''josedascoves.com''' ou qualquer coisa '''.josedascoves.com'''.&lt;br /&gt;
&lt;br /&gt;
Para testar podemos fazer assim do próprio servidor:&lt;br /&gt;
 # host josedascoves.com ::1&lt;br /&gt;
 Using domain server:&lt;br /&gt;
 Name: ::1&lt;br /&gt;
 Address: ::1#53&lt;br /&gt;
 Aliases:&lt;br /&gt;
 &lt;br /&gt;
 Host josedascoves.com not found: 3(NXDOMAIN)&lt;br /&gt;
Se a resposta for '''NXDOMAIN''' então está funcionando o bloqueio. Para incluir novos bloqueios basta adicionar os domínios, um abaixo do outro, conforme o exemplo que coloquei no arquivo RPZ.&lt;br /&gt;
&lt;br /&gt;
== Acertando o resolv.conf ==&lt;br /&gt;
Vamos modificar nosso /etc/resolv.conf para utilizar DNS externo. Sim você deve estar se perguntando em qual situação isso seria utilizado. Primeiro entenda que o Unbound não irá utilizar o DNS externo para fazer as consultas na Internet e sim, qualquer teste que você faça do servidor precisará apontar para o Unbound usando os IPs '''127.0.0.1''' ou '''::1'''. Faremos isso pela seguinte situação: imagine que o daemon unbound morreu mas você ainda continua com conectividade na Internet. Você conseguiria acessar qualquer local na Internet através do IP mas não através do hostname porque não conseguiria resolver nomes, seu unbound estaria fora do ar. Imagine ainda que você gostaria que seu servidor te avisasse do problema via Telegram ou e-mail. Por isso estamos utilizando um DNS externo no '''/etc/resolv.conf''', apenas para essas situações. Se você não quiser utilizar desse recurso, pode usar o '''127.0.0.1''' e '''::1''' no lugar.&lt;br /&gt;
 nameserver 8.8.8.8&lt;br /&gt;
 nameserver 8.8.4.4&lt;br /&gt;
 nameserver 2001:4860:4860::8888&lt;br /&gt;
&lt;br /&gt;
== Script de teste de recursividade ==&lt;br /&gt;
Estamos montando uma '''Rede de DNS Recursivo Anycast''', então é muito importante que você monitore essa rede para saber se algum node morreu e iniciar o troubleshooting, resolver o problema e levantar o sistema novamente. Tudo isso é importante mas o cliente não deve ficar esperando até você resolver o problema, seu sistema precisa ser inteligente o suficiente para se remover da Rede quando tiver um problema e se inserir novamente, quando o problema estiver sido solucionado. Se você montar uma Rede de DNS e um dos nodes apresentar algum problema, todos os clientes atendidos por aquele node migrarão automaticamente e transparentemente para outro '''DNS Recursivo Anycast''' mais próximo. Isso se chama '''disponibilidade'''.&lt;br /&gt;
&lt;br /&gt;
O script '''/root/scripts/checa_dns.sh''' abaixo tem a função de fazer os testes de recursividade e checar se o daemon do unbound continua rodando. Se algo acontecer, ele para o anúncio do '''10.10.10.10''' e '''10.10.9.9''' e retorna eles quando tudo estiver resolvido.&lt;br /&gt;
 # mkdir /root/scripts&lt;br /&gt;
&lt;br /&gt;
 #!/usr/bin/env bash&lt;br /&gt;
 #Script para teste de DNS v2.1&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 #Informe um domínio por linha:&lt;br /&gt;
 dominios_testar=(&lt;br /&gt;
 www.google.com&lt;br /&gt;
 www.terra.com.br&lt;br /&gt;
 www.uol.com.br&lt;br /&gt;
 www.globo.com&lt;br /&gt;
 www.facebook.com&lt;br /&gt;
 www.youtube.com&lt;br /&gt;
 www.twitch.com&lt;br /&gt;
 www.discord.com&lt;br /&gt;
 www.debian.org&lt;br /&gt;
 www.redhat.com&lt;br /&gt;
 )&lt;br /&gt;
 corte_taxa_falha=100 #Porcentagem de falha para executar uma ação&lt;br /&gt;
 #-----------------------------------------------------------------------&lt;br /&gt;
 remove_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; != &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no description' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'no ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME morreu!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 adiciona_ospf() {&lt;br /&gt;
    habilitado=&amp;quot;`vtysh -c 'show run' | grep \&amp;quot;LOOPBACKS\&amp;quot;`&amp;quot;&lt;br /&gt;
    if [ &amp;quot;$habilitado&amp;quot; == &amp;quot;&amp;quot; ]; then&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'description LOOPBACKS' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ip ospf passive' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 area 0.0.0.0' -c 'end' -c 'wr'&lt;br /&gt;
       vtysh -c 'conf t' -c 'interface lo' -c 'ipv6 ospf6 passive' -c 'end' -c 'wr'&lt;br /&gt;
       echo &amp;quot;Servidor $HOSTNAME retornou do inferno!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
    fi&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
 if [ $? -ne 0 ]; then&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME morreu DNS mas tentando levantar!&amp;quot; | /usr/local/sbin/telegram-notify --error --text -&lt;br /&gt;
    systemctl restart unbound&lt;br /&gt;
    systemctl status unbound &amp;amp;&amp;gt; /dev/null;&lt;br /&gt;
    if [ $? -ne 0 ]; then&lt;br /&gt;
       remove_ospf&lt;br /&gt;
       exit&lt;br /&gt;
    fi&lt;br /&gt;
    echo &amp;quot;Servidor $HOSTNAME servico DNS voltou mas tinha morrido!&amp;quot; | /usr/local/sbin/telegram-notify --success --text -&lt;br /&gt;
 fi&lt;br /&gt;
  &lt;br /&gt;
 qt_falhas=0&lt;br /&gt;
 qt_total=&amp;quot;${#dominios_testar[@]}&amp;quot;&lt;br /&gt;
 echo &amp;quot;total_dominios: $qt_total&amp;quot;&lt;br /&gt;
 for site in &amp;quot;${dominios_testar[@]}&amp;quot;&lt;br /&gt;
 do&lt;br /&gt;
   resolver=&amp;quot;127.0.0.1&amp;quot;&lt;br /&gt;
   echo -e &amp;quot; - dominio $site - $resolver - \c&amp;quot;&lt;br /&gt;
   host $site $resolver &amp;amp;&amp;gt; /dev/null&lt;br /&gt;
   if [ $? -ne 0 ]; then&lt;br /&gt;
      ((qt_falhas++))&lt;br /&gt;
      echo -e &amp;quot;[Falhou]&amp;quot;&lt;br /&gt;
   else&lt;br /&gt;
      echo -e &amp;quot;[OK]&amp;quot;&lt;br /&gt;
   fi&lt;br /&gt;
 done&lt;br /&gt;
  &lt;br /&gt;
 taxa_falha=$((qt_falhas*100/qt_total))&lt;br /&gt;
 echo &amp;quot;Falhas $qt_falhas/$qt_total ($taxa_falha%)&amp;quot;&lt;br /&gt;
  &lt;br /&gt;
 if [ &amp;quot;$taxa_falha&amp;quot; -ge &amp;quot;$corte_taxa_falha&amp;quot; ]; then&lt;br /&gt;
    remove_ospf&lt;br /&gt;
    exit&lt;br /&gt;
 fi&lt;br /&gt;
 adiciona_ospf&lt;br /&gt;
Se rodarmos o script manualmente veremos isto:&lt;br /&gt;
 # /root/scripts/checa_dns.sh&lt;br /&gt;
 total_dominios: 10&lt;br /&gt;
  - dominio www.google.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.terra.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.uol.com.br - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.globo.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.facebook.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.youtube.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.twitch.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.discord.com - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.debian.org - 127.0.0.1 - [OK]&lt;br /&gt;
  - dominio www.redhat.com - 127.0.0.1 - [OK]&lt;br /&gt;
 Falhas 0/10 (0%)&lt;br /&gt;
Se acontecer 100% de falhas o script irá remover os anúncios do OSPF. Se o daemon do unbound morrer, ele tentará reiniciá-lo. Se tudo normalizar o script irá retornar os anúncios para o OSPF. Deixei comentado no script as partes que enviariam uma notificação para o Telegram. Existem diversas documentações sobre isso na Internet, eu mesmo tenho uma. Assim que eu publicar aqui, atualizo essa documentação e sinta-se à vontade de modificar como desejar.&lt;br /&gt;
 # chmod 700 /root/scripts/checa_dns.sh&lt;br /&gt;
Adicione a linha abaixo em seu '''/etc/crontab''':&lt;br /&gt;
 */1 *   * * *   root    /root/scripts/checa_dns.sh&lt;br /&gt;
&lt;br /&gt;
== Habilitando o DoH (&amp;lt;abbr&amp;gt;DNS&amp;lt;/abbr&amp;gt; over HTTPS) e DoT (DNS over TLS) - opcional ==&lt;br /&gt;
Para habilitar o '''DoH''' e o '''DoT''' no Unbound é bem simples. O recurso do '''DoH''' e '''DoT''' vem para trazer mais segurança e privacidade para o usuário. É um recurso muito pouco utilizado ainda mas que seu cliente pode vir a pedir algum dia.&lt;br /&gt;
&lt;br /&gt;
Você precisará gerar certificados SSL legítimos e para isso você poderá usar o '''Let's Encrypt''' só que de uma forma não tão convencional.&lt;br /&gt;
&lt;br /&gt;
Na sequência vamos instalar o Let's Encrypt para gerarmos nosso certificado SSL:&lt;br /&gt;
 # apt install letsencrypt&lt;br /&gt;
Escolha um '''hostname''' para ser usado no nosso '''DoH''' e aponte ele no seu DNS Autoritativo para seus IPs 10.10.10.10 e 10.10.9.9. Aqui vamos usar o seguinte como exemplo: '''doh.brasilpeeringforum.org'''. Para gerarmos nosso certificado iremos usar o tipo '''DNS-01''', ele não necessita que tenhamos um servidor web rodando no servidor e nem tão pouco levanta um serviço na porta 80 para checar o hostname. Ele utiliza o DNS como validador e vai te solicitar que crie um registro '''CNAME''' no seu '''DNS Autoritativo''' para provar que você tem o controle sobre aquele hostname. Antes disso vamos instalar um programa em Python para podermos automatizar nossa renovação de certificado no futuro. Esse programa se encontra '''[https://github.com/joohoi/acme-dns-certbot-joohoi/raw/master/acme-dns-auth.py aqui]''' mas vou deixá-lo abaixo já modificado o interpretador.&lt;br /&gt;
&lt;br /&gt;
Crie o arquivo '''/etc/letsencrypt/acme-dns-auth.py''' com o conteúdo abaixo:&lt;br /&gt;
 #!/usr/bin/env python3&lt;br /&gt;
 import json&lt;br /&gt;
 import os&lt;br /&gt;
 import requests&lt;br /&gt;
 import sys&lt;br /&gt;
 &lt;br /&gt;
 ### EDIT THESE: Configuration values ###&lt;br /&gt;
 &lt;br /&gt;
 # URL to acme-dns instance&lt;br /&gt;
 ACMEDNS_URL = &amp;quot;&amp;lt;nowiki&amp;gt;https://auth.acme-dns.io&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
 # Path for acme-dns credential storage&lt;br /&gt;
 STORAGE_PATH = &amp;quot;/etc/letsencrypt/acmedns.json&amp;quot;&lt;br /&gt;
 # Whitelist for address ranges to allow the updates from&lt;br /&gt;
 # Example: ALLOW_FROM = [&amp;quot;192.168.10.0/24&amp;quot;, &amp;quot;::1/128&amp;quot;]&lt;br /&gt;
 ALLOW_FROM = []&lt;br /&gt;
 # Force re-registration. Overwrites the already existing acme-dns accounts.&lt;br /&gt;
 FORCE_REGISTER = False&lt;br /&gt;
 &lt;br /&gt;
 ###   DO NOT EDIT BELOW THIS POINT   ###&lt;br /&gt;
 ###         HERE BE DRAGONS          ###&lt;br /&gt;
 &lt;br /&gt;
 DOMAIN = os.environ[&amp;quot;CERTBOT_DOMAIN&amp;quot;]&lt;br /&gt;
 if DOMAIN.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
     DOMAIN = DOMAIN[2:]&lt;br /&gt;
 VALIDATION_DOMAIN = &amp;quot;_acme-challenge.&amp;quot;+DOMAIN&lt;br /&gt;
 VALIDATION_TOKEN = os.environ[&amp;quot;CERTBOT_VALIDATION&amp;quot;]&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 class AcmeDnsClient(object):&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
     Handles the communication with ACME-DNS API&lt;br /&gt;
     &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
     def __init__(self, acmedns_url):&lt;br /&gt;
         self.acmedns_url = acmedns_url&lt;br /&gt;
 &lt;br /&gt;
     def register_account(self, allowfrom):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Registers a new ACME-DNS account&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
         if allowfrom:&lt;br /&gt;
             # Include whitelisted networks to the registration call&lt;br /&gt;
             reg_data = {&amp;quot;allowfrom&amp;quot;: allowfrom}&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;,&lt;br /&gt;
                                 data=json.dumps(reg_data))&lt;br /&gt;
         else:&lt;br /&gt;
             res = requests.post(self.acmedns_url+&amp;quot;/register&amp;quot;)&lt;br /&gt;
         if res.status_code == 201:&lt;br /&gt;
             # The request was successful&lt;br /&gt;
             return res.json()&lt;br /&gt;
         else:&lt;br /&gt;
             # Encountered an error&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to register a new acme-dns &amp;quot;&lt;br /&gt;
                    &amp;quot;account. HTTP status {}, Response body: {}&amp;quot;)&lt;br /&gt;
             print(msg.format(res.status_code, res.text))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def update_txt_record(self, account, txt):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Updates the TXT challenge record to ACME-DNS subdomain.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         update = {&amp;quot;subdomain&amp;quot;: account['subdomain'], &amp;quot;txt&amp;quot;: txt}&lt;br /&gt;
         headers = {&amp;quot;X-Api-User&amp;quot;: account['username'],&lt;br /&gt;
                    &amp;quot;X-Api-Key&amp;quot;: account['password'],&lt;br /&gt;
                    &amp;quot;Content-Type&amp;quot;: &amp;quot;application/json&amp;quot;}&lt;br /&gt;
         res = requests.post(self.acmedns_url+&amp;quot;/update&amp;quot;,&lt;br /&gt;
                             headers=headers,&lt;br /&gt;
                             data=json.dumps(update))&lt;br /&gt;
         if res.status_code == 200:&lt;br /&gt;
             # Successful update&lt;br /&gt;
             return&lt;br /&gt;
         else:&lt;br /&gt;
             msg = (&amp;quot;Encountered an error while trying to update TXT record in &amp;quot;&lt;br /&gt;
                    &amp;quot;acme-dns. \n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request headers:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Request body:\n{}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response HTTP status: {}\n&amp;quot;&lt;br /&gt;
                    &amp;quot;------- Response body: {}&amp;quot;)&lt;br /&gt;
             s_headers = json.dumps(headers, indent=2, sort_keys=True)&lt;br /&gt;
             s_update = json.dumps(update, indent=2, sort_keys=True)&lt;br /&gt;
             s_body = json.dumps(res.json(), indent=2, sort_keys=True)&lt;br /&gt;
             print(msg.format(s_headers, s_update, res.status_code, s_body))&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
 class Storage(object):&lt;br /&gt;
     def __init__(self, storagepath):&lt;br /&gt;
         self.storagepath = storagepath&lt;br /&gt;
         self._data = self.load()&lt;br /&gt;
 &lt;br /&gt;
     def load(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Reads the storage content from the disk to a dict structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         data = dict()&lt;br /&gt;
         filedata = &amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             with open(self.storagepath, 'r') as fh:&lt;br /&gt;
                 filedata = fh.read()&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             if os.path.isfile(self.storagepath):&lt;br /&gt;
                 # Only error out if file exists, but cannot be read&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage file exists but cannot be read&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         try:&lt;br /&gt;
             data = json.loads(filedata)&lt;br /&gt;
         except ValueError:&lt;br /&gt;
             if len(filedata) &amp;gt; 0:&lt;br /&gt;
                 # Storage file is corrupted&lt;br /&gt;
                 print(&amp;quot;ERROR: Storage JSON is corrupted&amp;quot;)&lt;br /&gt;
                 sys.exit(1)&lt;br /&gt;
         return data&lt;br /&gt;
 &lt;br /&gt;
     def save(self):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Saves the storage content to disk&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         serialized = json.dumps(self._data)&lt;br /&gt;
         try:&lt;br /&gt;
             with os.fdopen(os.open(self.storagepath,&lt;br /&gt;
                                    os.O_WRONLY | os.O_CREAT, 0o600), 'w') as fh:&lt;br /&gt;
                 fh.truncate()&lt;br /&gt;
                 fh.write(serialized)&lt;br /&gt;
         except IOError as e:&lt;br /&gt;
             print(&amp;quot;ERROR: Could not write storage file.&amp;quot;)&lt;br /&gt;
             sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     def put(self, key, value):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Puts the configuration value to storage and sanitize it&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         # If wildcard domain, remove the wildcard part as this will use the&lt;br /&gt;
         # same validation record name as the base domain&lt;br /&gt;
         if key.startswith(&amp;quot;*.&amp;quot;):&lt;br /&gt;
             key = key[2:]&lt;br /&gt;
         self._data[key] = value&lt;br /&gt;
 &lt;br /&gt;
     def fetch(self, key):&lt;br /&gt;
         &amp;quot;&amp;quot;&amp;quot;Gets configuration value from storage&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
         try:&lt;br /&gt;
             return self._data[key]&lt;br /&gt;
         except KeyError:&lt;br /&gt;
             return None&lt;br /&gt;
 &lt;br /&gt;
 if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
     # Init&lt;br /&gt;
     client = AcmeDnsClient(ACMEDNS_URL)&lt;br /&gt;
     storage = Storage(STORAGE_PATH)&lt;br /&gt;
 &lt;br /&gt;
     # Check if an account already exists in storage&lt;br /&gt;
     account = storage.fetch(DOMAIN)&lt;br /&gt;
     if FORCE_REGISTER or not account:&lt;br /&gt;
         # Create and save the new account&lt;br /&gt;
         account = client.register_account(ALLOW_FROM)&lt;br /&gt;
         storage.put(DOMAIN, account)&lt;br /&gt;
         storage.save()&lt;br /&gt;
 &lt;br /&gt;
         # Display the notification for the user to update the main zone&lt;br /&gt;
         msg = &amp;quot;Please add the following CNAME record to your main DNS zone:\n{}&amp;quot;&lt;br /&gt;
         cname = &amp;quot;{} CNAME {}.&amp;quot;.format(VALIDATION_DOMAIN, account[&amp;quot;fulldomain&amp;quot;])&lt;br /&gt;
         print(msg.format(cname))&lt;br /&gt;
 &lt;br /&gt;
     # Update the TXT record in acme-dns instance&lt;br /&gt;
     client.update_txt_record(account, VALIDATION_TOKEN)&lt;br /&gt;
&lt;br /&gt;
 # chmod +x /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
Usaremos a seguinte instrução para criar nosso certificado:&lt;br /&gt;
 # certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d doh.brasilpeeringforum.org&lt;br /&gt;
 Saving debug log to /var/log/letsencrypt/letsencrypt.log&lt;br /&gt;
 Plugins selected: Authenticator manual, Installer None&lt;br /&gt;
 Cert is due for renewal, auto-renewing...&lt;br /&gt;
 Renewing an existing certificate for doh.brasilpeeringforum.org&lt;br /&gt;
 Performing the following challenges:&lt;br /&gt;
 dns-01 challenge for doh.brasilpeeringforum.org&lt;br /&gt;
 Running manual-auth-hook command: /etc/letsencrypt/acme-dns-auth.py&lt;br /&gt;
 Output from manual-auth-hook command acme-dns-auth.py:&lt;br /&gt;
 Please add the following CNAME record to your main DNS zone:&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
 &lt;br /&gt;
 Waiting for verification...&lt;br /&gt;
 &lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Challenges loaded. Press continue to submit to CA. Pass &amp;quot;-v&amp;quot; for more info about&lt;br /&gt;
 challenges.&lt;br /&gt;
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -&lt;br /&gt;
 Press Enter to Continue&lt;br /&gt;
Nesse momento você cria o registro '''CNAME''' no seu DNS Autoritativo conforme ele solicitou: '''_acme-challenge.doh.brasilpeeringforum.org IN CNAME b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.''' e somente depois de criado e checado no DNS, você pressiona o '''Enter''' para continuar. Você pode checar dessa forma:&lt;br /&gt;
 # host -t cname _acme-challenge.doh.brasilpeeringforum.org&lt;br /&gt;
 _acme-challenge.doh.brasilpeeringforum.org is an alias for b555d682-7b50-45d9-a92f-3c3d187dd4e7.auth.acme-dns.io.&lt;br /&gt;
Para que nosso certificado seja automaticamente renovado colocaremos no '''/etc/crontab''' a seguinte linha abaixo:&lt;br /&gt;
 00 00   1 * *   root    /usr/bin/certbot -q renew&lt;br /&gt;
Acima temos a instrução para renovação automática do certificado. Repare que você vai precisar também copiar esse certificado para seus outros servidores, escolha um servidor para manter o certificado sempre atualizado e crie um script que faça a mesma cópia remotamente para os outros servidores. O '''scp''' e o '''rsync''' são seus aliados nisso.&lt;br /&gt;
&lt;br /&gt;
=== Configurando o Unbound ===&lt;br /&gt;
Em nosso '''/etc/unbound/unbound.conf.d/local.conf''', adicionaremos no bloco &amp;quot;'''server:'''&amp;quot; o seguinte:&lt;br /&gt;
 interface: 10.10.10.10@443 &lt;br /&gt;
 interface: 10.10.9.9@443&lt;br /&gt;
 interface: fc00::10:10:10:10@443&lt;br /&gt;
 interface: fc00::10:10:9:9@443&lt;br /&gt;
 interface: 10.10.10.10@853 &lt;br /&gt;
 interface: 10.10.9.9@853&lt;br /&gt;
 interface: fc00::10:10:10:10@853&lt;br /&gt;
 interface: fc00::10:10:9:9@853&lt;br /&gt;
 tls-service-key: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/privkey.pem&amp;quot; &lt;br /&gt;
 tls-service-pem: &amp;quot;/etc/letsencrypt/live/doh.brasilpeeringforum.org/fullchain.pem&amp;quot;&lt;br /&gt;
Para usar o recurso do '''DoH''' você precisará habilitar o recurso no seu navegador e informar a URL. Vou colocar o exemplo do '''Google Chrome''': Digite '''chrome://settings/security?search=dns''' no seu Chrome e ative '''Usar DNS seguro''', selecione '''Personalizado''' e adicione nossa URL:&lt;br /&gt;
[[Arquivo:Doh bpf2.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== Finalizando ==&lt;br /&gt;
Aqui finalizamos nosso projeto para uma Rede de DNS(s) Recursivos Anycast com Hyperlocal. Esse projeto é escalável, seguro, resiliente e você entregará muito mais qualidade de Internet para o seu cliente. Pare de entregar o '''8.8.8.8''' para os seus clientes, você está contribuindo para uma Internet mais lenta, sem a qualidade que o seu cliente merece. Investi meu tempo, que é muito pouco, para deixar esse documento para a comunidade, para você melhorar o seu ISP, para dar um UP! nele, então vamos começar 2023 com o pé direito. O que acha?&lt;br /&gt;
&lt;br /&gt;
Como prova de conceito, uma imagem abaixo onde temos uma Rede em produção de DNS(s) Recursivos Anycast e apontando exatamente o momento em que houve alguma situação que fez com que as queries de DNS, convergissem de um node para outro, de forma transparente e automática para o cliente. Podemos notar também que ao ser resolvido o problema, o tráfego retornou para o seu node correto:&lt;br /&gt;
[[Arquivo:Convergencia.png|nenhum|commoldura]]&lt;br /&gt;
&lt;br /&gt;
== KINDNS (Stands for Knowledge-Sharing and Instantiating Norms for DNS and Naming Security) ==&lt;br /&gt;
Achou que havia terminado? Agora que você tem a capacidade de montar uma '''Rede de DNS Recursivo''' com todas essas features acima, com todas as ferramentas que foram comentadas, o que acha de certificar o que fez?&lt;br /&gt;
&lt;br /&gt;
Assim como o [https://www.manrs.org/ MANRS] veio para certificar nosso sistema de roteamento na Internet, agora temos o [https://kindns.org/ KINDNS] para certificar que nossos sistemas de DNS estão bem feitos e dentro dos padrões de segurança. Existem '''7 ações''' que podem ser certificadas para nossos DNS Recursivos e estão aqui em https://kindns.org/shared-private-resolvers/. Com essa nossa documentação, se bem aplicada, você pode se candidatar ao KINDNS e ter seu ASN listado aqui https://kindns.org/participants/&lt;br /&gt;
&lt;br /&gt;
Obter e manter o '''MANRS''' e '''KINDNS''' demonstra seu compromisso com as Boas Práticas, contribui para termos uma '''Internet''' mais segura e te abre portas para novos negócios que possam exigir essas conformidades.&lt;br /&gt;
&lt;br /&gt;
Autor: [[Usuário:Gondim|Marcelo Gondim]]&lt;br /&gt;
[[Categoria:Infraestrutura]]&lt;br /&gt;
__FORCARTDC__&lt;/div&gt;</summary>
		<author><name>Gondim</name></author>
	</entry>
</feed>