rbacuri.dpdns.org — status: online

Quando o firewall mente: caçando um UFW decorativo

Um dos hábitos mais importantes que venho desenvolvendo nessa transição de carreira é: nunca confiar que uma ferramenta está fazendo o que diz que está fazendo. Esse caso mostrou exatamente por que isso importa.

O sintoma

Ao tentar liberar uma porta nova num servidor doméstico, o comando ufw allow rodava sem erro, ufw status mostrava tudo “active” e a regra certinha na lista — mas a porta continuava inacessível. Isso já era estranho o suficiente pra investigar mais fundo.

Primeira causa: um serviço concorrente sobrescrevendo tudo

A primeira pista veio comparando ufw status com a realidade do kernel:

sudo iptables -L INPUT -n

O resultado não tinha nenhuma menção às chains que o UFW deveria estar usando (ufw-before-input, ufw-user-input, etc). Em vez disso, havia regras completamente diferentes — incluindo uma que liberava uma porta antiga de um serviço já removido há tempos.

A causa: um pacote de infraestrutura (netfilter-persistent) estava habilitado no boot, restaurando um snapshot estático e desatualizado de regras salvas em disco — de antes de qualquer hardening ter sido aplicado. Esse snapshot sobrescrevia tudo que o UFW configurava, a cada reinicialização, silenciosamente.

Correção: desabilitar esse serviço concorrente, deixando o UFW como único gerenciador de firewall.

Segunda causa: o “gancho” que nunca existiu

Depois de desabilitar o serviço concorrente, o problema pareceu resolvido — até um segundo incidente revelar que não estava. Uma investigação mais funda mostrou algo sutil:

sudo iptables-save | grep "^-A INPUT"

Só existia uma única regra manual ali (inserida numa correção de emergência anterior) — nenhuma linha conectando a chain principal INPUT às chains internas do UFW. As chains do UFW existiam no kernel, prontas, configuradas — mas nunca eram chamadas. Era como ter um sistema de alarme instalado, ligado, com sensores funcionando, mas sem nenhum fio conectando ele ao painel central.

Comparar iptables-save com nft list ruleset (o backend moderno por trás do iptables no Ubuntu recente) revelou a peça que faltava: chains específicas de uma das duas famílias de protocolo (IPv4) simplesmente não existiam — só as equivalentes de IPv6. Reinstalar o pacote do zero não resolveu, porque o problema não estava na configuração em disco — estava preso num estado corrompido, direto no kernel.

A correção real: derrubar completamente o conjunto de regras do kernel e deixar o UFW reconstruir tudo do absoluto zero.

sudo nft flush ruleset
sudo systemctl restart ufw

Depois disso, finalmente: seis linhas de conexão apareceram na chain INPUT, e o firewall passou a filtrar de verdade — não só a reportar que estava filtrando.

Bônus: o navegador também pode mentir

Depois de resolver o firewall, configurei acesso remoto privado via VPN pra um ambiente de laboratório. A resolução de nome funcionava perfeitamente por linha de comando (Resolve-DnsName), mas o navegador continuava dando erro de DNS.

Motivo: o Chrome tem seu próprio resolver de DNS embutido (DNS-over-HTTPS), que ignora completamente a configuração de rede do sistema operacional quando está no modo “escolher um provedor específico”. Ele mandava a consulta direto pra um servidor DNS público, que nunca teria como saber resolver um hostname privado da minha rede.

A lição

Duas ferramentas diferentes (ufw status, e o resolver de DNS do navegador) reportavam sucesso enquanto faziam algo diferente do esperado. Em nenhum dos dois casos havia mensagem de erro — só um resultado final que não batia com a expectativa.

A lição prática: sempre que uma ferramenta de rede/segurança reporta “ativo” ou “funcionando”, vale a pena confirmar numa camada mais baixa — o kernel, no caso do firewall; o comportamento real de resolução, no caso do DNS — antes de assumir que o problema está em outro lugar.