Есть ли способ быстро и эффективно получить количество 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