Nada no fail2ban descarta um pacote sozinho: ele chama uma ação, e é essa ação que nomeia um protocolo e uma porta. Quando a jail relata um ban enquanto o daemon continua aceitando logins, o ban costuma ser real e mais estreito do que o log sugere. Um cliente que se reconecta pelo outro transporte nunca encontra a regra que foi instalada. Compare o que a ação instalou com aquilo em que o daemon escuta antes de mudar qualquer coisa, porque a prova está na cadeia de firewall que a ação escreveu, não na lista da jail.

Leia a cadeia, não o resumo da jail

O fail2ban insere a própria cadeia à frente da cadeia do serviço, então uma listagem de contadores mostra exatamente o que existe. Uma cadeia com o nome da jail, contendo uma única regra cuja coluna de protocolo diz udp, é uma explicação completa para os logins TCP que continuam chegando. Apenas pacotes UDP da origem bloqueada são rejeitados. O serviço tem um ouvinte TCP, e nada nessa cadeia o toca.

Atenção também ao efeito da jail vizinha. Um host pode parecer perfeitamente configurado só porque outra jail fornece a metade que falta, e a mesma compilação não faz nada onde essa jail não está instalada.

A ação nomeia um único protocolo, e é aí que quebra

Cada banaction é um modelo de comando de firewall, e o protocolo fica em um dos seus espaços reservados. A estreiteza é intencional, já que uma jail web e uma jail DNS não têm nada a ver com bloquear portas idênticas. Torna-se uma armadilha quando o serviço escuta em mais de um transporte, o que os daemons VPN fazem rotineiramente. O filtro pode observar logins falhos dos dois transportes enquanto a ação cobre um.

Implantações de SoftEther e OpenVPN costumam escutar em UDP e TCP ao mesmo tempo, e como a linha do log parece igual nos dois casos, o filtro observa ambos. A assimetria nunca aparece no relatório da própria jail. O fail2ban contou as falhas corretamente e então instalou uma regra que vale para metade do tráfego por onde essas falhas chegaram.

Faça o ban cobrir os dois transportes

Corrija na definição da jail; regras escritas à mão serão misturadas na próxima recarga. Escreva duas ações, uma para cada protocolo:

action = %(banaction)s[name=%(__name__)s-tcp, actionname=%(__name__)s-tcp, protocol="tcp", port="%(port)s", chain="%(chain)s"]
         %(banaction)s[name=%(__name__)s-udp, actionname=%(__name__)s-udp, protocol="udp", port="%(port)s", chain="%(chain)s"]

Não tente encurtar com protocol = all. A banaction padrão é uma ação multiport, e ela se expande para -p <protocol> -m multiport --dports <port>; sem protocolo L4 não há nada para a correspondência de porta testar, então o iptables rejeita a regra enquanto a jail ainda relata um ban bem-sucedido. Uma ação de todas as portas como iptables-allports ou nftables-allports aceita uma única entrada, mas bloqueia todas as portas daquela origem, o que é outra decisão e precisa da própria justificativa. Deixe protocol em tcp ou udp e aceite as duas entradas.

Prove que a regra existe em vez de confiar na configuração, porque uma configuração descreve uma intenção até que uma cadeia a sustente:

iptables -S f2b-vpn-tcp
iptables -S f2b-vpn-udp

Cada cadeia deve listar uma regra, com -p tcp na primeira e -p udp na segunda, ambas nomeando o endereço bloqueado. Depois confirme que o mesmo endereço é recusado nos dois transportes. Um ban que você não viu na cadeia é uma esperança, e o próximo relato do mesmo sintoma custará a mesma hora outra vez.

O que um ban ainda deixa passar, e o próximo caso

O que a ação faz é rejeitar uma única origem, e apenas nas portas listadas nela. Não faz nada contra um atacante que troca de endereço, e não consegue separar uma máquina hostil de uma saída NAT de nível de operadora compartilhada por centenas de usuários, onde um único ban deixa de fora pessoas que não fizeram nada. Certifique-se de que o filtro lê o endereço que o cliente realmente tem, não um cabeçalho encaminhado nem um endereço de proxy. Mantenha a janela curta o bastante para que um erro expire sozinho.

Nada disso defende pular a correção do protocolo; defende manter duas ideias ao mesmo tempo. O ban é mais estreito do que o resumo da jail sugere, e mesmo um ban completo é mais estreito do que a ameaça. Coloque a cadeia de firewall ao lado da lista de ouvintes do daemon e compare protocolo por protocolo, porque são essas duas listas que decidem se um ban pode chegar ao serviço.

Guarde o comando de recarga e a listagem de cadeias no runbook ao lado da jail. A próxima pessoa vai precisar dos dois, e o resumo da jail não dirá nenhum deles.

Artigos relacionados