Você pode tentar usar moblock (google it - não é possível adicionar links ainda, novo usuário). Desative todas as listas de bloqueio baixadas e use apenas uma lista de bloqueios local que você gerar. Pode ser necessário adicionar suporte ao NFQUEUE (fila de netlink) ao seu kernel, mas ele pode estar lá por padrão.
A configuração geral é: para todos os pacotes SYN nas portas que você deseja filtrar, use a ação NFQUEUE do netfilter para empurrá-los para o moblock, no espaço do usuário. O Moblock faz uma correspondência eficiente e envia de volta uma resposta ACCEPT ou DROP ao netlink.
O formato de arquivo de configuração do moblock é bastante simples: em cada linha, forneça um nome e um intervalo de IP, no formato 123.123.123.42-123.123.124.56. Quando o moblock carrega os intervalos, ele cria uma estrutura de dados eficiente para corresponder a esses intervalos. Quando um pacote é descartado por causa de uma correspondência, o nome do intervalo e o IP da fonte real são registrados (ou não, se você desabilitar o registro de correspondências).
Eu usei o moblock em sua configuração padrão (listas de bloqueio baixadas) com cerca de 230000 IP ranges , e não vi nenhum desempenho perceptível (filtrar apenas o pacote SYN é importante para manter o tráfego do kernel / userspace para baixo embora).
Uma ressalva: se o moblock não estiver em execução, acredito que a ação padrão do NFQUEUE é DROP, resultando em uma negação de serviço do seu aplicativo. Dito isto, eu tive o moblock funcionando continuamente sem nenhum problema por mais de 6 meses. Ainda assim, talvez você queira configurar um probe de monitoramento que avise se um IP em bom estado não puder mais se conectar a: 80 em seu servidor. Você definitivamente não quer usar o moblock para filtrar o ssh, a menos que tenha listado explicitamente alguns IPs confiáveis no netfilter para recuperar.