Existe alguma maneira rápida e eficiente de obter uma contagem de endereços IP de host em milhares de intervalos CIDR / netmask no Bash?

4

Estou usando o IPSet para gerenciar dezenas de milhares de intervalos IPv4 CIDR / netmask que, em seguida, são vinculados às regras do IPTables. Essa configuração está funcionando muito bem, mas eu gostaria de obter uma boa contagem geral de alto nível dos endereços IP do host em que o IPSet atua para fins de relatório do cliente.

A formatação de entrada do IPSet é consistentemente assim:

123.456.0.0/16 timeout 86400

Então eu posso encontrar as linhas que timeout para obter valores para atuar nos intervalos CIDR / netmask contidos na entrada.

Por exemplo, se eu salvar a saída IPSet (via ipset -L -n > ipset-20181228.txt ) para um arquivo de texto chamado ipset-20181228.txt e, em seguida, execute uma combinação de grep e wc -l como isso:

grep  "timeout" ipset-20181228.txt  | wc -l

Recebo uma contagem de mais de 39.000 itens, o que equivale a 39.000+ escalas de CIDR / netmask. Mas isso é (é claro) contar apenas os intervalos de CIDR / netmask e não as contagens completas de endereços de host IP nesse intervalo.

Tentei usar prips (que expande valores CIDR / netmask para endereços IP reais no Bash) com o grep para selecionar apenas itens com intervalos CIDR / netmask como este:

grep -oE '(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\/([0-9]{1,2})' ipset-20181228.txt | awk 'NF { system( "prips " $0)  }' | wc -l

E depois de um gritante 20 a 30 minutos (!!!) no meu 2018 MacBook Air (com os fãs chutando), a contagem que eu consegui foi de 736.000.000+ que é o que eu estou indo para… Mas 20 a 30 minutos é muito longo . Eu quero que isso seja o mais scriptável e não intrusivo possível, e não posso confiar em um comando como esse para ser executado em um servidor de produção sem consumir recursos. Quero dizer, observe como ele se comporta na configuração de desenvolvimento do MacBook Air local.

Existe alguma maneira de calcular apenas a contagem do intervalo CIDR / netmask com base simplesmente no valor CIDR / netmask? Espero que haja apenas uma ferramenta de linha de comando - ou uma opção nas ferramentas existentes que estou usando - que não conheço que possa ajudar.

JakeGould
fonte
Qual conversão você quer? Opção A. 1.2.3.0/24 para 1.2.3.0-1.2.3.255 Opção B. 1.2.3.0-1.2.3.255 para 1.2.3.0/24. Nmap, traceroute tem alguns recursos.
Biswapriyo
1
@Biswapriyo Nenhum dos dois. Você já leu a pergunta? Eu estou simplesmente pedindo para obter uma contagem de endereços IP com base na notação CIDR / netmask. Não converter de uma forma de notação de intervalo para outra.
JakeGould
2
Se entendi corretamente, você quer saber quantos hosts estão em um determinado par de ip / máscara. O número do host é 2^(32-mask)-2. A máscara representa os bits da rede, então a outra parte representa os bits dos hosts. -2 é para o endereço de rede e ips de transmissão. Se você tem ipcalc instalado, execute-o para ver essas informações. (Desculpe-me se eu entendi mal sua pergunta).
Paulo
1
@Paulo: Não subtraia 2; Não assuma que cada intervalo corresponda diretamente a uma sub-rede. Rotas e listas de filtros não têm correspondência com o layout físico - uma entrada pode corresponder apenas a parte de uma sub-rede ou cobrir várias sub-redes de uma só vez ou até se aplicar a redes que não têm nenhum conceito de "sub-rede" (por exemplo, links de ponto). E realmente, se um endereço representa um host ou não, nem é relevante na filtragem. Cada prefixo tem exatamente 2^(32-mask) endereços e é isso.
grawity
@grawity Eu vejo o seu ponto, acho que eu estava preso ao conceito de um intervalo de sub-rede. Esse intervalo da questão pode ser um intervalo de ips, assim como você disse. Obrigado por esclarecer. Eu assino 2^(32-mask).
Paulo

Respostas:

2

Se seu grep Comando gera linhas como 123.456.0.0/16, então você precisa canalizá-los para

awk -F / '{ count[$2]++ } END { for (mask in count) total+=count[mask]*2^(32-mask); print total }'

O comando apenas extrai máscaras (ou seja, o que é depois / ) e conta as ocorrências de cada máscara. No final, o número de hosts é calculado para cada máscara encontrada ( 2^(32-mask) ), multiplicado pelo número de ocorrências e somado.

Notas:

  • Nenhuma verificação de sanidade é executada. Por exemplo. entrada como 1.2.3.4/40 será aceito, a saída não inteira será calculada. Melhore sua preliminar grep filtre se necessário.
  • Cada intervalo contribui de forma independente para o número total. Se os seus intervalos se sobrepuserem, você obterá um resultado inflado (acho que sua tentativa com prips não foi melhor nisso).
Kamil Maciorowski
fonte
Isto e excelente. Executá-lo da seguinte maneira funciona muito rapidamente e o comando final com o qual eu usei isso é: grep -oE '(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\/([0-9]{1,2})' ipset-*.txt | awk -F / '{ count[$2]++ } END { for (mask in count) total+=count[mask]*2^(32-mask); print total }'
JakeGould
0

Eu pensei que algo assim funcionaria desde que o pôster original está executando grep para obter o CIDR de linhas com timeout:

awk -F'[ /]' '/timeout/ {hosts+=2^(32-$2)};ENDFILE{print "Hosts number in "FILENAME": "hosts;total+=hosts;hosts=0};END {print "Total: "total}' ipset*.txt

EDITAR- awk programa acima corre ok apenas com GNU awk. ENDFILE é uma extensão do GNU.

eu acho BSD awk ignora ENDFILE e executa essa seção se fosse parte da seção principal do programa.

Isso é compatível com o GNU e o BSD awk.

awk -F'[ /]' '{if (filename != FILENAME) hosts=0};/timeout/ {hosts+=2^(32-$2)};{filename=FILENAME;file_total[filename]=hosts};END{for (i in file_total) {print "Hosts number in "i": "file_total[i];total+=file_total[i]};{print "Total: "total};}' ipset*.txt
Paulo
fonte
Seu script revisado funciona no macOS, mas como expliquei anteriormente, é horrivelmente mais do que contar no macOS agora, assim como no Linux: estou recebendo um número de hosts de 8.500.000.000.000 + usando seu script em vez dos 736.000.000 esperados que estou usando em um teste de amostra ao vivo arquivo com a resposta aceita, bem como prips. Desculpe, obrigado pelo esforço, mas isso não está funcionando para dizer o mínimo.
JakeGould
1
@jakegould Ok, não é um problema de todos. Provavelmente não entendi a saída para filtrar corretamente. Além disso, eu não consegui um jeito fácil de instalar prips e veja como funciona e sua saída. De qualquer forma vale a pena o exercício para obter o awk relatório sem qualquer extensão GNU.
Paulo