Вопрос или проблема
Итак, у меня есть несколько файлов, которые содержат CIDR
записи (такие как 1.1.1.0/24
). Задача состоит в том, чтобы добавить записи из этих файлов в один NFTables
набор, используя bash-скрипт. При этом я ограничен утилитами OpenWRT
.
Проблема в том, что в этих файлах может быть много записей, и они могут исчерпать лимит 4096 символов на команду. А также эти файлы автоматически обновляются с помощью cron
, поэтому набор нужно периодически стирать и заполнять заново.
Мне кажется, что есть более простой способ сделать это, чем я уже сделал. Я также хочу уменьшить время выполнения этого процесса. Вот моя попытка сделать это.
nft add element $TARGET_SET { $(awk '{print $1 ", "}' "$CUSTOM_CIDRS_FILE") }
Вот еще один вопрос: если в моем файле очень большое количество записей, превысит ли лимит в 4096 символов на команду? И еще один последний вопрос: займет ли это много времени, чтобы сформировать набор, если я добавляю записи по одной в цикле?
Я в первую очередь жду ответов с хорошей практикой.
awk
может сформировать строку для выполнения, которая может быть удержана ниже
определенной длины; это несомненно будет более эффективно, чем
xargs
, который должен создавать echo ... | tr
конвейер.
#!/usr/bin/env awk
{
len = length()
if (len > limit) {
if (length(outbuf)) {
system("echo " ENVIRON["TARGET_SET"] outbuf)
}
outbuf = $0
limit = 6
} else {
outbuf = outbuf "," $0
}
limit -= len + 1
}
END {
if (length(outbuf)) {
system("echo " ENVIRON["TARGET_SET"] outbuf)
}
}
"echo "
в этом скрипте предназначены для тестирования, вместо этого следует запустить подходящую команду nft ...
. TARGET_SET
должен быть
экспортирован, чтобы awk
мог считать его из окружения.
Где вы читали о лимите в 4096 символов в командах nftables? Если у меня есть список из 4000 диапазонов CIDR (это почти 64,000 символов), я могу выполнить вашу команду без ошибок:
# wc -l ranges.txt
400.0 ranges.txt
# export TARGET_SET=example_set
# export CUSTOM_CIDRS_FILE=ranges.txt
# nft add set ip filter $TARGET_SET { type ipv4_addr\; flags interval\; }
# nft add element $TARGET_SET { $(awk '{print $1 ", "}' "$CUSTOM_CIDRS_FILE") }
Команды nft add
выполняются за примерно 0.003 секунды с 4000 элементами.
Кажется, что в какой-то момент мы можем столкнуться с ограничениями длины командной строки в Linux, в этом случае мы можем сгруппировать команды. Это добавит элементы партиями по 1000:
xargs -n1000 sh -c '
nft add element ip filter $TARGET_SET { $(
echo "$@" | tr " " ","
) }' -- < $CUSTOM_CIDRS_FILE
(Обратите внимание, что вышеуказанное предполагает, что TARGET_SET
является переменной окружения, а не переменной оболочки.)
Это выполняется за примерно 0.1 секунды для тех же 4000 элементов.
Вы можете использовать директиву nft -f
:
echo add element $TARGET_SET { $(awk '{print $1 ", "}' "$CUSTOM_CIDRS_FILE") } | nft -f -
nft
возьмет сгенерированную директиву add element
из stdin, тем самым преодолевая лимит длины командной строки.
В моем тестировании этого метода на Raspberry Pi 4B добавление списка, содержащего 39065 IPv4 адресов, занимает около 0.5 секунд.
Ответ или решение
Для добавления CIDR-адресов из файлов в набор NFTables с использованием OpenWRT и при наличии ограничений на длину команд в 4096 символов, существует несколько методов. Давайте рассмотрим, как эффективно решить эту задачу, сразу учитывая автоматическое обновление файлов с помощью cron и необходимость периодической очистки набора.
1. Оптимизация процесса добавления CIDR
Для начала определим, как можно организовать добавление адресов из файлов. Ваша задача состоит в том, чтобы избежать превышения ограничения по количеству символов в команде и снизить время выполнения скрипта.
Использование AWK для обработки
Можно использовать awk для обработки файла с CIDR-адресами и создания команды, которая будет разбираться на части в соответствии с ограничениями. Пример скрипта выглядит следующим образом:
#!/usr/bin/env awk
{
len = length($0)
if (len > limit) {
if (length(outbuf)) {
system("nft add element " ENVIRON["TARGET_SET"] " { " outbuf " }")
}
outbuf = $0
limit = 4096 - 60 # учитываем длину остальных частей команды
} else {
outbuf = outbuf "," $0
}
limit -= len + 1
}
END {
if (length(outbuf)) {
system("nft add element " ENVIRON["TARGET_SET"] " { " outbuf " }")
}
}
Этот скрипт позволит обрабатывать адреса из файла и добавлять их в набор, избегая превышения лимита на размер команды.
Пакетная обработка с xargs
Это еще один способ, который позволяет избежать ограничения на длину команды, выполняя добавление в пакетах:
export TARGET_SET="example_set"
export CUSTOM_CIDRS_FILE="cidrs.txt"
xargs -n1000 sh -c '
nft add element ip filter $TARGET_SET { $(
echo "$@" | tr " " ","
) }' -- < $CUSTOM_CIDRS_FILE
Такой подход позволит добавлять элементы по 1000 за раз, что значительно уменьшит нагрузку на командную строку.
2. Очистка набора перед обновлением
Поскольку файлы обновляются автоматически с помощью cron, важно включить процесс очистки набора. Это можно сделать следующим образом:
nft flush set ip filter $TARGET_SET
Запустите эту команду перед добавлением новых элементов, чтобы гарантировать, что предыдущие адреса не будут мешать актуальным данным.
3. Запуск скрипта каждый раз
Чтобы автоматизировать процесс, можно создать bash-скрипт и настроить его запуск с помощью cron. Скрипт будет включать этапы чтения файла CIDR, очистки набора и добавления новых элементов:
#!/bin/bash
TARGET_SET="example_set"
CUSTOM_CIDRS_FILE="cidrs.txt"
# Очистить набор
nft flush set ip filter $TARGET_SET
# Добавить новые CIDR
awk '...' < "$CUSTOM_CIDRS_FILE"
Заключение
Используя предложенные методы, вы сможете эффективно добавлять CIDR-адреса в набор NFTables без риска превышения лимитов командной строки и с минимизацией времени выполнения. Автоматизация процесса улучшит актуальность данных, а использование awk и xargs обеспечит высокую скорость обработки.
Такие подходы не только упрощают процесс управления сетевыми правилами, но и повышают надежность и скорость работы вашего сетевого окружения в OpenWRT.