Olá a todos!
Isto começou com uma birra. Estava a tentar perceber porque é que uma blocklist que eu sabia, sabia, ter o domínio de telemetria de uma Smart TV lá dentro continuava a deixar passar tráfego para esse mesmo domínio. Abri o painel do AdGuard, filtrei por cliente, e o número de queries vindas da TV era… baixíssimo. Demasiado baixo para um aparelho daqueles, que normalmente despeja telemetria como se lhe pagassem à query. E aí caiu-me a ficha: a TV não estava a ser bloqueada porque a TV nunca esteve a falar comigo. Andava a resolver DNS por fora, alegremente, há semanas, sem nunca me ter pedido licença.
Se há coisa que me irrita é montar uma infraestrutura de filtragem DNS decente, com carinho, e depois descobrir que metade dos aparelhos lá de casa estão a mandar queries directamente para o 8.8.8.8 como se o meu resolver fosse decorativo. É como instalar uma porta blindada à frente e deixar a janela da cozinha aberta de par em par. Pior: é não saber sequer que a janela existe.
Hoje vou falar-vos disto. Do bypass de DNS, dos vários sabores que ele tem, de porque é que isto vos afecta mesmo que não tenham “nada a esconder”, e a parte importante como é que se fecha a coisa de forma a que aguente. Aviso já: não é uma regra mágica. São camadas. E há uma camada que quase toda a gente esquece, e que vou guardar para o fim para fazer suspense (é o IPv6, mas finjam que não leram).
O falso sentimento de segurança
Vamos lá ser honestos uns com os outros por um segundo. Quase toda a gente que corre um homelab montou um resolver local algures pelo caminho. Um Pi-hole num Raspberry Pi que já anda a aquecer há quatro anos, um AdGuard Home num container, um Unbound espetado directamente no OPNsense. Configurámos o DHCP a distribuir o IP do resolver, atirámos meia dúzia de blocklists para lá, vimos o contador de “queries blocked” a subir, e fomos dormir com aquela sensação morna de que tínhamos o DNS da rede debaixo de olho.
E é mentira. Bem-intencionada, mas mentira.
O modelo mental que temos é este, limpinho:
Dispositivo → Query DNS (porta 53) → resolver local → resposta filtrada ✓
O que está realmente a acontecer na vossa rede, neste preciso momento, enquanto lêem isto, parece-se mais com esta confusão:
Chromecast → Query DNS (UDP 53) → 8.8.8.8 directamente → sem filtro ✗
Firefox → HTTPS (TCP 443) → cloudflare-dns.com → sem filtro ✗
App Android → TLS (TCP 853) → dns.google → sem filtro ✗
Smart TV → Query DNS (UDP 53) → DNS hardcoded do vendor → sem filtro ✗
Telemóvel → QUIC (UDP 443) → resolver do fabricante → sem filtro ✗
O vosso resolver: "Ninguém me liga. Estou aqui. Tenho blocklists e tudo."
Quatro, cinco vectores ao mesmo tempo, cada um com a sua lógica própria, todos a contorná-lo. E a parte que custa mesmo a digerir: na esmagadora maioria dos casos isto não é um bug, nem um ataque, nem nada de exótico. É comportamento de fábrica. Foi desenhado para vos passar ao lado. As vossas blocklists, para metade da rede, podem perfeitamente não existir.
A família completa dos métodos de bypass
Antes de falarmos em fechar isto, convém perceberem a dimensão real do bicho. Não é um buraco. É um penico furado por vários sítios, e cada furo tem o seu próprio feitio.
DNS hardcoded no firmware. O mais primário e, para mim, o mais irritante de todos, porque é o mais descarado. Chromecast, Google Home, Android TV, e uma quantidade obscena de tralha IoT trazem servidores DNS escritos a fogo no firmware, tipicamente o 8.8.8.8 e o 8.8.4.4. O vosso DHCP pode anunciar o resolver que quiser, com TTL bonito e tudo; estes aparelhos lêem, sorriem, e mandam a query para a Google na mesma. A Google até documenta este comportamento como feature nos dispositivos Nest/Chromecast, com a desculpa de “robustez” se o DNS local da rede estiver mal configurado, o aparelho continua a funcionar. Conveniente para o utilizador que não faz ideia do que é DNS. Uma pedra no sapato para quem quer mandar na própria rede. E não pensem que é só a Google: já apanhei câmaras IP a fazer hardcode para resolvers na China, e robôs aspiradores com DNS de fabricantes que eu nem sabia que existiam.
DNS-over-HTTPS (DoH). Este é o que me tira mesmo do sério, porque foi desenhado para ser invisível e realmente cumpre. O DoH mete as queries DNS dentro de tráfego HTTPS normal, na porta 443, indistinguível de alguém a fazer scroll no Instagram. Do ponto de vista da firewall, é uma ligação TLS para um IP qualquer; não há porta 53, não há nada para detectar à vista desarmada. O Firefox suporta-o nativamente e, em várias regiões, liga-o sozinho. O Chrome faz o chamado “secure DNS auto-upgrade”: se o resolver que o sistema está a usar tiver uma versão DoH conhecida, o Chrome silenciosamente passa a falar DoH com ele, sem vos avisar. A intenção é boa, privacidade contra o ISP. O efeito colateral, na vossa rede, é que perdem visibilidade e controlo de uma penada.
DNS-over-TLS (DoT). Primo do DoH, mas mais honesto: usa uma porta dedicada, a 853, e nem tenta disfarçar-se de tráfego web. Encripta as queries sobre uma ligação TLS própria. Por usar uma porta exclusiva, é trivial de bloquear. Basta fechar a 853. O Android, da versão 9 em diante, traz isto na funcionalidade “Private DNS” (aquela definição que mete dns.google ou dns.adguard.com e fica encriptado ponta a ponta com o resolver público, completamente fora da vossa alçada).
DNS-over-QUIC (DoQ). O membro mais novo da família. Corre sobre QUIC, normalmente em UDP 853, com a 443 como recurso. É mais rápido que o DoT porque o QUIC despacha o handshake do TLS de forma mais eficiente e sobrevive a mudanças de rede sem reabrir a ligação. Ainda relativamente verde em termos de adopção, mas o Android 11+ já o fala, e os resolvers grandes (AdGuard, Cloudflare) já o servem.
E os que estão a chegar. Só para não dizerem que não avisei: há mecanismos novos a entrar em cena, como o DDR (Discovery of Designated Resolvers), em que o cliente pergunta ao resolver de sempre “ó pá, tens aí uma versão encriptada de ti próprio?” e faz upgrade automático para DoH/DoT. E há o ECH (Encrypted Client Hello), que encripta o SNI ou seja, daqui a algum tempo nem o nome do site dentro do TLS vai dar para ver, o que mata várias técnicas de bloqueio baseadas em SNI. A guerra do DNS não acabou; está só a mudar de campo.
Mas isto importa mesmo no meu homelab?
Estou a ouvir-vos daqui: “Ok Nuno, dramatismo à parte, eu não tenho segredos de Estado em casa. Quem é que quer saber das minhas queries DNS?”
Parem dois segundos e pensem comigo no que é que realmente corre no vosso homelab. Provavelmente um Nextcloud com as vossas fotos e documentos. Talvez um Vaultwarden – ou seja, as vossas passwords todas. Um Immich com a biblioteca de fotografias da família inteira. Bases de dados. Câmaras. Isto não é “nada a esconder”; isto é exactamente o tipo de coisa que justifica um homelab em primeiro lugar.
Agora juntem a isso o seguinte. Aqueles aparelhos IoT a resolver DNS por fora estão a despejar telemetria que vocês não vêem nem controlam para onde vai, com que frequência, o quê. Isso já era mau. Mas o cenário que me preocupa de verdade é outro: se um desses aparelhos for comprometido, por exemplo uma câmara chinesa com firmware de 2019 que nunca mais viu uma actualização é um candidato de luxo e o malware pode estabelecer comunicação com a infraestrutura de comando-e-controlo (C2) via DNS, e fazê-lo por DoH na 443, e o vosso resolver local nunca, nunca, chega a ver uma única dessas queries. Vocês têm um intruso a conversar com casa pela vossa própria ligação à Internet, e o vosso painel de DNS continua verdinho a dizer que está tudo bem.
As blocklists existem por uma razão. Se metade da rede as ignora, é como ter uma firewall que protege metade dos portos e deixa a outra metade aberta. Não está “meio segura”. Está aberta, com decoração.
A abordagem: defense-in-depth, camada a camada
Não há uma regra que resolva isto. Quem vos disser que há, está a vender-vos qualquer coisa. O que há é uma sobreposição de camadas que, em conjunto, torna o bypass chato o suficiente para que a esmagadora maioria dos aparelhos desista e caia de volta no vosso resolver sem ninguém ter de tocar em nada.
Precisam de duas coisas: uma firewall capaz (OPNsense, pfSense, ou equivalente que faça NAT e regras de saída a sério) e um resolver local (AdGuard Home, Pi-hole, ou Unbound directo). Vou pelos cinco passos, mas reparem que a ordem importa: o primeiro é o que dá mais retorno por menos esforço.
Passo 1: Capturar e redireccionar todo o DNS na porta 53
A pedra basilar. Em vez de bloquear a porta 53 para fora (o que parte aparelhos e gera comportamento esquisito), nós redireccionamos: uma regra de NAT Port Forward que apanha qualquer tráfego DNS na porta 53 destinado a qualquer sítio que não seja o vosso resolver, e o reencaminha para o resolver local. O aparelho julga que falou com o 8.8.8.8 e recebeu resposta. Recebeu, sim, só que da resposta foi o vosso AdGuard, filtradinha. Ele nem dá por nada, e é por isso que esta abordagem é tão elegante: não há UX partida, não há aparelho a chorar que “não tem Internet”.
NAT Port Forward (OPNsense/pfSense):
Interface: LAN
Protocolo: TCP/UDP
Origem: LAN net
Destino: ! (NOT) "This Firewall" ou o IP do resolver
Porta de destino: 53 (DNS)
Redirect target: IP do AdGuard/Pi-hole
Redirect port: 53
Dois detalhes que separam quem testou de quem copiou de um tutorial:
- Excluam o próprio resolver do redirect (o
! NOT). Se não excluírem, criam um loop: o resolver tenta resolver, é redireccionado para si próprio, e a coisa morde a própria cauda. - Acrescentem, logo a seguir, uma regra de block na saída para a porta 53. Sim, a seguir ao redirect. Parece redundante mas não é: o redirect trata do tráfego que transita pela firewall, mas em redes com routing assimétrico, VLANs mal isoladas, ou clientes a usar TCP em vez de UDP, vale a pena ter o bloqueio explícito como rede de segurança. Cinto e suspensórios.
Depois disto, façam um teste rápido a partir de um portátil: dig @8.8.8.8 doubleclick.net. Se a resposta vier filtrada (um 0.0.0.0 ou NXDOMAIN em vez do IP real), o redirect está a funcionar: falaram “com a Google” e respondeu-vos o vosso Pi-hole.
Passo 2: Fechar o DoT (porta 853)
Este é de uma simplicidade desarmante. O DoT vive na 853. Fechem-na na saída, TCP e UDP (o UDP apanha também o DoQ na porta standard, dois coelhos numa cajadada).
Firewall Rule (saída, na interface LAN):
Acção: Block
Protocolo: TCP/UDP
Porta de destino: 853
Descrição: Bloquear DNS-over-TLS e DoQ (porta standard)
Uma regra. DoT enterrado. O efeito prático é que, se alguém tiver o “Private DNS” do Android configurado, ele vai falhar a ligação encriptada e se estiver no modo “automático” e não “forçado” cai de volta para DNS normal, que vocês já capturaram no Passo 1. Se estiver no modo forçado para um hostname específico, o aparelho fica sem DNS e o utilizador é obrigado a desligar a definição. Que, convenhamos, é o resultado que queremos.
Passo 3: Matar o QUIC na 443 (UDP)
O QUIC, que é o transporte do HTTP/3, anda em UDP na 443. O DoQ pode usar essa mesma porta como alternativa quando a 853 está fechada (e está, ver Passo 2). Logo, bloqueiem UDP 443 na saída.
Firewall Rule (saída, na interface LAN):
Acção: Block
Protocolo: UDP
Porta de destino: 443
Descrição: Bloquear QUIC/HTTP3 e DoQ alternativo
O trade-off honesto: ao fazer isto, matam o HTTP/3 para todo o tráfego web da rede. A boa notícia é que isto é completamente transparente. Os browsers fazem fallback para HTTP/2 sobre TCP automaticamente, sem o utilizador notar coisa nenhuma. Podem perder uns milissegundos de latência aqui e ali em ligações muito boas, mas na prática ninguém vê a diferença. Para mim vale claramente a pena; fechar o QUIC tapa um vector de DoH/DoQ que de outra forma seria muito chato de apanhar. (Se um dia precisarem mesmo de HTTP/3 para um serviço específico, abrem uma excepção pontual por IP de destino.)
Passo 4: Bloquear os domínios de servidores DoH conhecidos, via DNS
Há um calcanhar de Aquiles em quase todos os clientes DoH: para falarem com um servidor DoH, primeiro precisam de descobrir onde ele está. E a forma como o descobrem é… resolvendo o hostname por DNS normal. O Firefox vai perguntar pelo cloudflare-dns.com, o Chrome pelo dns.google. E essa pergunta passa pelo vosso resolver local.
Ou seja: se o vosso resolver devolver “não existe” para esses hostnames, o cliente nunca encontra o servidor DoH e cai de volta no DNS normal. Para isto, a melhor ferramenta que conheço é a blocklist da HaGeZi dedicada a encrypted DNS bypass e são mais de 3500 domínios de servidores DoH/DoT públicos, mantida e actualizada com regularidade.
AdGuard Home → Filtros → Listas de bloqueio DNS → Adicionar:
URL: https://raw.githubusercontent.com/hagezi/dns-blocklists/main/adblock/doh.txt
Nome: HaGeZi Encrypted DNS / DoH Bypass
A partir daqui, cloudflare-dns.com, dns.google, dns.quad9.net, doh.opendns.com e milhares de outros deixam de resolver.
Há uma limitação que tenho de vos dizer, senão fico a dever-vos honestidade: isto só funciona se o cliente resolver o hostname pelo vosso DNS primeiro. Há clientes – e o Firefox é o exemplo clássico – que trazem bootstrap IPs hardcoded: se o DNS falhar a resolver o hostname do resolver DoH, o Firefox tem um IP de recurso já gravado para se ligar à Cloudflare na mesma. Para esses casos, o bloqueio por domínio não chega. É precisamente para isso que serve o passo seguinte.
Passo 5: Bloquear os IPs dos servidores DoH na firewall
Aqui apertamos o último parafuso. Alguns apps e aparelhos IoT saltam o DNS por completo e ligam-se ao servidor DoH directamente por IP – seja porque o têm hardcoded, seja por bootstrap como o Firefox acima. A resposta é uma lista de IPs conhecidos de servidores DoH carregada na firewall, e um bloqueio de tudo o que tente lá chegar.
No OPNsense/pfSense isto faz-se com um alias do tipo URL Table (IPs), que se actualiza sozinho:
Firewall Alias:
Nome: DoH_Servers
Tipo: URL Table (IPs)
URL: https://raw.githubusercontent.com/hagezi/dns-blocklists/main/ips/doh.txt
Frequência: Diária
E depois uma regra de bloqueio na saída que use esse alias como destino. A lista traz mais de 1600 IPv4 de servidores DoH públicos, Cloudflare, Google, Quad9, OpenDNS, NextDNS, AdGuard Public DNS, e umas centenas mais.
Aqui chega a pergunta que toda a gente faz, e com razão:
“Espera lá. Acabaste de bloquear o 8.8.8.8 e o 1.1.1.1. Como é que o DNS continua a funcionar?”
Resposta: porque o meu resolver não depende de ninguém lá fora. Se usarem o Unbound em modo recursivo (e não em forwarding), o Unbound resolve tudo sozinho, descendo a cadeia DNS a partir dos root servers, sem nunca precisar de perguntar nada ao 8.8.8.8 nem ao 1.1.1.1:
Unbound: "Root server, quem manda no .com?"
Root: "Fala com o a.gtld-servers.net."
Unbound: "Servidor de .com, quem manda no google.com?"
TLD: "Fala com o ns1.google.com."
Unbound: "ns1.google, qual é o IP do google.com?"
Google: "142.251.142.206."
Nenhum resolver de terceiros no caminho. Os root servers e os servidores autoritativos não estão na blocklist (e não fazia sentido estarem), portanto nada parte. É por isto que recomendo Unbound recursivo em vez de forwarding: em forwarding, a Cloudflare (ou quem quer que seja o vosso upstream) fica a ver todos os domínios que a vossa rede visita que é exactamente a fuga de privacidade que estamos aqui a tentar fechar. Em recursão, a privacidade é vossa e mais ninguém vê o quadro completo. Sai um pouco mais lento nas primeiras queries (a cache ainda está fria), mas em poucos minutos de utilização normal nem se nota.
A camada que quase toda a gente esquece: IPv6
Pronto, é agora. Se tens IPv6 activo na rede, e se tens fibra de operador português, há uma boa probabilidade de teres, mesmo sem saber, então todas as cinco regras de cima podem estar impecáveis em IPv4 e a rede continua a vazar DNS por IPv6. Isto é, na minha experiência, o erro número um de quem segue um tutorial à risca e depois jura que “configurou tudo” mas o dnsleaktest continua a mostrar a Google.
A lógica é simples e cruel: um aparelho com 8.8.8.8 hardcoded provavelmente também tem 2001:4860:4860::8888 hardcoded. Se a vossa regra de redirect e os vossos bloqueios são só para IPv4, o aparelho simplesmente usa o caminho IPv6 e passa por baixo de tudo. Além disso, o vosso próprio router pode estar a anunciar resolvers IPv6 públicos aos clientes via RA/RDNSS (Router Advertisements), o que sabota o DHCP a montante.
O que têm de fazer, em paralelo a tudo o resto:
- Duplicar o Passo 1 para IPv6. Uma regra de NAT/redirect (ou, mais simples, um bloqueio) para porta 53 em IPv6, excluindo o resolver.
- Garantir que os RAs anunciam o vosso resolver como DNS IPv6 (RDNSS), e não um público. No OPNsense isto controla-se nas definições de Router Advertisements por interface.
- Replicar os bloqueios de 853 e UDP 443 para IPv6 as regras de firewall têm de existir para ambas as famílias de endereços; não assumam que uma cobre a outra.
- A blocklist de IPs da HaGeZi também tem variante IPv6 (
ips/doh-ipv6.txt) usem-na no alias.
Se não querem lidar com nada disto e o IPv6 não vos faz falta para já, a opção pragmática é desligar o IPv6 na LAN até terem tempo de o fazer em condições. Não é a solução bonita, mas uma rede sem IPv6 é melhor do que uma rede com um buraco de IPv6 por onde foge tudo o que vocês acham que bloquearam.
O que é que isto não apanha
Nenhuma solução é à prova de bala, e prefiro dizer-vos as limitações do que vendê-vos uma falsa sensação de segurança que é precisamente o problema que abriu este post.
Os apps da Meta. Facebook, Instagram e WhatsApp correm o seu próprio DoH a partir de domínios como *.c10r.facebook.com, e o detalhe maldoso é que esses mesmos IPs servem o tráfego normal do Facebook. Não dá para separar. Se os bloqueiam, partem o Facebook inteiro, não só o DNS. Isto não é acidente pois a Meta misturou de propósito a resolução DNS encriptada na infraestrutura principal, exactamente para que bloqueá-la doa. É por isto que a própria HaGeZi exclui estes domínios da lista. Se quiserem mesmo apanhá-los, é caso a caso e com dor.
Servidores DoH privados. Qualquer pessoa minimamente motivada levanta um resolver DoH num VPS de cinco euros, na porta 443, com um certificado válido, e nenhuma blocklist do mundo o conhece. Tudo o que descrevi funciona contra o comportamento por defeito de browsers, apps e aparelhos não contra um adversário que está activamente a tentar fugir. Se o “adversário” é o teu filho adolescente com um VPS, isto é outra conversa (e provavelmente uma conversa, não uma regra de firewall).
Túneis VPN. No instante em que um aparelho levanta uma VPN, todas as vossas regras de DNS ficam invisíveis o tráfego vai encapsulado dentro do túnel e o DNS resolve-se algures no outro extremo. Num homelab, onde controlam os próprios aparelhos, isto é gerível (e até desejável quando vocês é que montam a VPN). Mas é uma limitação real que convém ter presente.
Blocklists desactualizadas. Os providers trocam de IP. Uma lista estática hoje brilhante está furada daqui a três meses. Por isso é que insisti em aliases do tipo URL Table com actualização diária automática tanto o OPNsense como o pfSense fazem isto nativamente, é só configurar a frequência e esquecer.
A imagem maior: privacidade e controlo
Porque é que vale a pena gastar uma tarde nisto? A resposta vai muito para além de bloquear uns anúncios.
Corremos um homelab por uma razão de fundo: controlo. Sobre os nossos dados, os nossos serviços, a nossa privacidade. Mas se os aparelhos lá de casa estão a mandar queries DNS para fora sem o nosso conhecimento, esse controlo é uma ficção. Cada query que escapa é um bocadinho de informação sobre nós que sites visitamos, que aparelhos temos, a que horas estamos em casa entregue a um terceiro, de bandeja, sem contrapartida.
E na perspectiva de segurança pura, o DNS é a primeira linha de defesa contra malware, phishing e comunicação com C2. Se essa linha tem buracos, estão a operar numa rede parcialmente protegida. E há uma frase que se repete muito em segurança, gasta de tão repetida mas verdadeira: uma rede parcialmente protegida é uma rede desprotegida. O atacante não precisa de furar a parede toda; precisa de encontrar a janela que ficou aberta.
A minha recomendação prática
Se levam minimamente a sério a privacidade e a segurança da vossa rede, isto devia subir na lista de prioridades. Não é complexo, não precisa de hardware nenhum especial, e a soma das camadas apanha a esmagadora maioria do bypass que acontece por defeito.
Pela ordem de retorno por esforço:
- Comecem pelo Passo 1 (redirect da porta 53). É o mais impactante e o mais fácil. Só isto já recupera a maioria dos aparelhos teimosos.
- Façam logo a versão IPv6 do Passo 1, ou desliguem o IPv6 na LAN. Não saltem esta é a que mais gente esquece e a que mais frustração causa depois.
- Bloqueiem a 853 e o UDP 443 (Passos 2 e 3). Duas regras, dois vectores fechados.
- Acrescentem as blocklists e o alias de IPs (Passos 4 e 5). É onde apanham o DoH “civilizado” dos browsers.
- Verifiquem. Não confiem, testem.
Para verificar, três ferramentas que uso sempre:
dnsleaktest.comnum browser de cada tipo de aparelho.- A partir de um cliente:
dig @8.8.8.8 example.come ver se a resposta vem do vosso resolver. - E o que não mente, directamente na firewall, a apanhar tudo o que tente escapar na 53 para fora:
# na shell do OPNsense/pfSense, ajustar a interface (igb0 = WAN, por ex.)
tcpdump -i igb0 -n 'port 53 or port 853 or (udp port 443)'
Se aquilo está em silêncio enquanto a rede trabalha, ganhaste. Se vês queries a sair, tens ali o aparelho exacto (pelo IP de origem) que ainda anda a fazer das suas e aí é caçá-lo individualmente.
Lembrem-se de uma coisa: o objectivo não é a perfeição inatingível. É tornar o bypass chato o suficiente para que os aparelhos caiam de volta no vosso resolver sozinhos, sem ninguém ter de pensar nisso no dia a dia. A segurança faz-se de camadas, e o DNS é uma das mais fundamentais de todas. Não a deixem entregue ao que os fabricantes dos vossos gadgets decidiram por vocês porque, garanto-vos, eles decidiram a pensar neles, não em vós.
Até ao próximo post: mantenham os resolvers de pé e as blocklists frescas, fofas e atualizadas. Se não controlam o DNS, não controlam a rede.
Um abraço,
Nuno
P.S. Se andam de OPNsense ou pfSense e querem isto com screenshots passo a passo, adaptado a cada firewall (incluindo a parte chata do IPv6), digam nos comentários e faço um post dedicado. E se têm aí algum aparelho particularmente cabeludo no que toca a ignorar o DNS da rede daqueles que parece que foram programados de propósito para vos chatear partilhem qual é. É sempre útil ir mapeando que fabricantes decidiram que a vossa rede é uma sugestão e não uma regra.
