Есть ли способ быстро и эффективно получить количество IP-адресов узлов в тысячах диапазонов CIDR/ масок в Bash?

Я использую IPSet для управления десятками тысяч диапазонов CIDR/ маски IPv4, которые затем связываются с правилами IPTables. Эта установка работает отлично, но я хотел бы получить хорошее общее количество обзоров IP-адресов хостов, на которых работает IPSet для отчетов клиентов.

Форматирование записи IPSet постоянно выглядит следующим образом:

123.456.0.0/16 timeout 86400

Так что я могу разобраться в строках, которые имеют timeout чтобы получить значения для действия в диапазонах CIDR/ маска сети, содержащихся в записи.

Например, если я сохраню вывод IPSet (через ipset -L -n > ipset-20181228.txt) в текстовый файл с именем ipset-20181228.txt а затем запустить комбинацию grep а также wc -l как это:

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

Я получил количество 39 000+ предметов, что соответствует 39 000+ CIDR/ диапазонам маски. Но это (конечно) только подсчет диапазонов CIDR/ маска сети, а не полный подсчет IP-адресов хоста в этом диапазоне.

Я пытался использовать prips (который расширяет значения CIDR/ сетевой маски до фактических IP-адресов в Bash) с помощью grep, чтобы исключить только элементы с диапазонами CIDR/ сетевой маски, например:

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

И после колоссальных 20–30 минут (!!!) на моем MacBook Air 2018 года (с включенными фанатами) счет, который я получил, составил 736 000 000+, на что я рассчитываю… Но 20–30 минут - это слишком долго, Я хочу, чтобы это было настолько скриптовым и ненавязчивым, насколько это возможно, и я не могу доверять такой команде для запуска на производственном сервере без израсходования ресурсов; Я имею в виду, посмотрите, как он ведет себя на моей локальной установке для разработки MacBook Air 2018 года.

Есть ли способ просто рассчитать счетчик CIDR/ диапазона маски на основе просто значения CIDR/ маски? Я надеюсь, что есть какой-то инструмент командной строки - или опция в существующих инструментах, которые я использую - которые я не знаю, которые могут помочь.

2 ответа

Решение

Если твой grep команды выводят строки как 123.456.0.0/16то вам нужно их

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

Команда извлекает только маски (то есть, что после /) и подсчитывает вхождения каждой маски. В конце рассчитывается количество хостов для каждой обнаруженной маски (2^(32-mask)), умноженное на количество вхождений и суммированное.

Заметки:

  • Проверка работоспособности не выполняется. Например, ввод, как 1.2.3.4/40 будет принято, нецелочисленный вывод будет рассчитан. Улучшите свой предварительный grep фильтруйте при необходимости.
  • Каждый диапазон независимо вносит свой вклад в общее количество. Если ваши диапазоны перекрываются, вы получите завышенный результат (я думаю, что ваша попытка с prips было не лучше в этом).

Я думал, что что-то вроде этого будет работать, так как оригинальный постер использует grep для получения CIDR из строк с 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

РЕДАКТИРОВАТЬ awk Программа выше работает нормально только с GNU awk, ENDFILE это расширение GNU.

Похоже BSD awk игнорируемых ENDFILE и запускает этот раздел, если он был частью основного раздела программы.

Это совместимо с GNU и 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
Другие вопросы по тегам