Usar tabelas de IP ou rota nula para colocar na lista negra cerca de 1 milhão de endereços IP?

22

Eu me deparei com uma situação em que um cliente precisa colocar na lista negra um conjunto de pouco menos de 1 milhão de endereços IP individuais (sem sub-redes), e o desempenho da rede é uma preocupação. Embora eu conjecture que as regras do IPTables teriam menos impacto no desempenho do que as rotas, isso é apenas conjectura.

Alguém tem alguma evidência sólida ou outra justificativa para favorecer o IPTables ou o roteamento nulo como solução para colocar listas longas de endereços IP na lista negra? Nesse caso, tudo é automatizado, portanto, a facilidade de uso não é realmente uma preocupação.

EDIT 26-Nov-11

Após alguns testes e desenvolvimento, parece que nenhuma dessas opções é viável. Parece que as pesquisas de rota e as tabelas de ip fazem pesquisas lineares no conjunto de regras e demoram muito tempo para processar essas muitas regras. No hardware moderno, colocar 1 milhão de itens em uma lista negra do iptables reduz o servidor para cerca de 2 dúzias de pacotes por segundo. Portanto, IPTables e rotas nulas estão fora.

ipset, como recomendado por Jimmy Hedman, seria ótimo, exceto que ele não permite que você rastreie mais de 65536 endereços em um conjunto, por isso não posso nem tentar usá-lo, a menos que alguém tenha alguma idéia.

Aparentemente, a única solução para bloquear tantos IPs é fazer uma pesquisa indexada na camada de aplicação. Não é assim?


Mais Informações:

O caso de uso nesta instância está impedindo que uma lista de endereços IP "ofensores conhecidos" acesse o conteúdo estático em um servidor da web. FWIW, fazer o bloqueio através do Apache Deny fromé igualmente lento (se não mais), como também faz uma varredura linear.


FYI: A solução final de trabalho foi usar o mod_rewrite do apache em conjunto com um mapa de banco de dados de berkeley para fazer pesquisas na lista negra. A natureza indexada dos bancos de dados de berkeley permitiu que a lista fosse dimensionada com o desempenho de O (log N).

tylerl
fonte
5
O ipset ( ipset.netfilter.org ) não é menos projetado para lidar com esse tipo de problema?
precisa
@ JimmyHedman: Você deve fazer disso uma resposta. E, em seguida, adicione uma sugestão para fazer o benchmark, fazendo tudo de três maneiras :) #
MikeyB 26/11
Estou curioso para saber mais sobre o problema que você está tentando resolver. Talvez o bloqueio de endereços IP da 1M não seja o caminho para corrigir o problema?
SpacemanSpiff (
Ajudaria muito saber por que você deseja bloquear tantos endereços e se deseja filtrar o tráfego INPUT ou FORWARD.
Juliano
Aqui você pode ver como o ipset torna as regras do iptables cerca de 11x mais rápidas que as regras regulares do iptables. daemonkeeper.net/781/mass-blocking-ip-addresses-with-ipset Espero esta ajuda.
Alien Torres

Respostas:

15

tente usar o iptables e criar uma árvore de vários níveis para diminuir o número de pesquisas.

iptables -N rules_0_0_0_0_2
iptables -N rules_64_0_0_0_2
iptables -N rules_128_0_0_0_2
iptables -N rules_192_0_0_0_2
iptables -N rules_0_0_0_0_4
iptables -N rules_16_0_0_0_4

iptables -A INPUT -p tcp --dport 80 -s 0.0.0.0/2 -j rules_0_0_0_0_2
iptables -A INPUT -p tcp --dport 80 -s 64.0.0.0/2 -j rules_64_0_0_0_2
iptables -A INPUT -p tcp --dport 80 -s 128.0.0.0/4 -j rules_128_0_0_0_2
iptables -A INPUT -p tcp --dport 80 -s 192.0.0.0/4 -j rules_192_0_0_0_2

iptables -A rules_0_0_0_0_2 -s 0.0.0.0/4 -j rules_0_0_0_0_4
iptables -A rules_0_0_0_0_2 -s 16.0.0.0/4 -j rules_16_0_0_0_4

e assim por diante - adicionando níveis de aninhamento; Obviamente, você precisará de uma maneira automática de criar as regras e deverá ter cadeias apenas para as redes em que há um ou mais infratores - dessa forma, você pode reduzir o número de pesquisas que precisam ser feitas de maneira bastante significativa e acho que pode realmente funciona.

pQd
fonte
Isso soa como se pudesse funcionar, reduzindo efetivamente a complexidade de tempo da pesquisa de regras do firewall de O (n) para O (log n), criando efetivamente uma árvore de pesquisa nas tabelas de ip.
Por Zweigbergk,
Se você decidir seguir essa rota, provavelmente seria útil usar algum algoritmo para criar uma árvore de pesquisa binária equilibrada a partir da lista de endereços IP e, em seguida, simplesmente despejar a estrutura dessa árvore de pesquisa como um conjunto de regras de tabelas de IP.
Por Zweigbergk,
@Per von Zweigbergk - na verdade ... ou apenas poda a árvore cedo, onde não há necessidade de fazer pesquisas mais profundas. embora o carregamento dessa quantidade absurda de regras leve muito tempo.
PQD
Essa é uma abordagem muito boa. Obviamente, é necessário um pouco de processamento para manter, mas é a ideia certa, eu acho.
tylerl
3
@pQd após falhas anteriores com iptables et al., implementei uma solução no apache usando um RewriteMap com o banco de dados Berkeley. Mas meu mecanismo mais rápido, usando o iptables em um loop, carregava cerca de 100 regras por segundo, enquanto o iptables-restore fazia o conjunto inteiro em cerca de 4 segundos. Este é um computador de mesa topo de linha. O mecanismo RewriteMap tem um impacto indetectável baixo no desempenho.
tylerl
11

É exatamente ipsetpara isso.

No site http://ipset.netfilter.org/ :

Se você quiser

  • armazene vários endereços IP ou números de porta e combine com a coleção por iptables de uma só vez;
  • atualizar dinamicamente as regras do iptables em endereços IP ou portas sem penalidade de desempenho;
  • Expresse conjuntos de regras complexos baseados em portas e endereços IP com uma única regra de tabelas de ip e se beneficie da velocidade dos conjuntos de IP

então o ipset pode ser a ferramenta adequada para você.

Ele foi escrito por Jozsef Kadlecsik, membro da equipe principal do netfilter (que também escreveu o alvo REJECT). Portanto, essa é a melhor escolha que posso pensar.

Está incluso nos kernels recentes.

cstamas
fonte
Até onde eu vi, o ipset chega aos 65k endereços IP. Existe algum tipo de conjunto capaz de lidar com entradas de 1 milhão?
tylerl
7
Se você usar o tipo de conjunto hash: ip, poderá ter um número muito grande de endereços. Eu tentei 1000000 e o desempenho foi muito bom. Se você configurar uma regra -m state --state ESTABLISHED antes de verificar seu conjunto, poderá garantir que apenas verifique o conjunto em novas conexões, o que aumentaria o desempenho ao lidar com um grande número de pacotes.
Matthew Ife
Vale ressaltar, porém, que o uso de memória de um ipset com endereços de 1 milhão começa a aumentar. De acordo com este post na lista de discussão netfilter, a fórmula atual de 2015 para o tamanho do hash do ipset é H * 40byte + (N/4 + N%4) * 4 * element sizede aproximadamente 64 MB para endereços de 1 milhão em um hash de slot de 1,5 m. O uso da solução apache / berkdb armazena os dados no disco e carrega apenas as páginas dos endereços ativos.
M Conrad
5

Eu não testei isso sozinho, mas quando ouvi a descrição do seu problema, pensei " pf" imediatamente (como no OpenBSD).

pftem o conceito de tabelas de endereços que podem ser exatamente o que você está procurando.

De acordo com uma pesquisa muito superficial que eu fiz, parece que isso tem o potencial de ter uma escala melhor do que ipset. De acordo com o capítulo das Perguntas frequentes sobre PF em Opções de tempo de execução , pronto para uso sem ajuste, o pf suporta um total de 1.000 tabelas, com um total de 200.000 entradas em todas as tabelas por padrão. (100.000 se o sistema tiver <100 MB de memória física). Isso me leva a acreditar que vale a pena considerar tentar testar isso para ver se funciona em algum tipo de nível útil.

Claro, estou assumindo que você esteja executando seus servidores no Linux, então você teria que ter uma caixa de firewall separada executando algum sistema operacional com pf (como OpenBSD ou FreeBSD). Você também pode melhorar o rendimento eliminando qualquer tipo de filtragem de pacotes com estado.

Per von Zweigbergk
fonte
Converter a arquitetura do servidor do cliente em BSD não é realmente uma opção. Pensando fora da caixa, pelo menos.
tylerl
2
Você não precisaria converter toda a arquitetura do servidor em BSD; seria suficiente criar um firewall para colocar na frente do servidor real. (Fácil de fazer em uma máquina virtual.)
Per von Zweigbergk
2

Você investigou usando um FIB_TRIE em vez de FIB_HASH.

FIB_TRIE deve escalar muito melhor para sua contagem de prefixos. (As rotas nulas do / 32s ainda são prefixos, apenas muito específicas)

Você pode precisar compilar seu próprio kernel para usá-lo, mas isso ajuda.

Notas FIB_TRIE

Joel K
fonte
2

Para a posteridade: de acordo com os ipsetdocumentos, o tamanho padrão de um conjunto é 65536, isso pode ser alterado por opções.

maxelem Este parâmetro é válido para o comando create de todos os conjuntos de tipos de hash. Ele define o número máximo de elementos que podem ser armazenados no conjunto, o padrão 65536. Exemplo:ipset create test hash:ip maxelem 2048.

Coloquei isso aqui, pois ainda não posso comentar.

plitter
fonte
1

Algumas notas úteis para quem se deparar com esse problema no futuro:

Primeiro de tudo, não analise nenhum tráfego desnecessário. Se você estiver bloqueando o tráfego TCP, por exemplo, filtre apenas os pacotes SYN, dessa forma, você só acessa o filtro uma vez por conexão. Você pode usar -m statese quiser, mas o rastreamento de conexão tem sua própria sobrecarga que você pode evitar se o desempenho for um problema.

Segundo, colocar um milhão de regras no iptables leva muito tempo: vários minutos. Se você precisar rastrear muitas entidades, é melhor mantê-lo fora do netfliter. O tamanho do conjunto de regras faz a diferença.

Terceiro, o objetivo é evitar verificações lineares; mas, infelizmente, o iptables e o iproute2 são inerentemente lineares. Você pode dividir suas regras no estilo de árvore binária em um grande número de cadeias, o que limita o número de regras que você precisa consultar, mas mesmo assim o iptables não é adequado para esse tamanho de problema. Ele vai trabalhar , mas é um desperdício de recursos valiosos.

Quarto, e mais importante, levar sua carga de trabalho ao espaço do usuário não é uma má idéia. Isso permite que você escreva seu próprio código restrito ou use uma solução pronta para uso que esteja ajustada ao seu conjunto de problemas. Minha própria solução para esse problema, como mencionado, foi usar pesquisas BDB acionadas pelo sistema mod_rewrite do apache. Isso teve o benefício adicional de acionar apenas uma pesquisa por sessão e somente após o envio de uma solicitação válida. Nesse caso, o desempenho foi extremamente rápido e o custo da lista de bloqueio foi quase insignificante.

Você pode fazer uma manipulação semelhante do espaço do usuário com o iptables usando o -j QUEUEdestino em conjunto com libnetfilter_queue. Essa ferramenta é poderosa, simples e mal documentada. Eu recomendaria ler o máximo possível a partir de tantas fontes quanto possível, pois há muito material interessante espalhado pela Web que não faz parte de nenhuma documentação oficial.

tylerl
fonte