Вопрос или проблема
Я хотел бы отразить только очень ограниченный пакетный трафик, направленный на один IP и UDP-порт, на тот же IP, но другой порт. Я смотрел на https://superuser.com/questions/1593995/iptables-nftables-forward-udp-data-to-multiple-targets, но, похоже, что оператор дублирования nftables позволяет дублировать только на другой IP, а не на тот же IP с другим портом.
Например, трафик на 127.0.0.1 порт 123 должен дублироваться на 127.0.0.1 порт 456. Поскольку это единственное дублирование, у меня нет никаких проблем с тем, что оригинальный номер порта теряется. Теперь я задаюсь вопросом, возможно ли вообще такое дублирование, потому что 127.0.0.1 не является “сливом”/исходящим интерфейсом, а является конечным адресом дублируемого пакета. Может ли быть способ объединить это с DNAT?
Существует ли какой-то другой механизм, кроме привязки eBPF-пробы к сетевому устройству с входящим UDP-трафиком?
Это можно сделать с помощью nftables и семейства netdev с цепочкой ingress и оператором dup. Это требует использования метки, чтобы избежать бесконечного цикла. В зависимости от конкретного варианта использования, дублирование также, вероятно, можно сделать на egress (поскольку это на loopback интерфейсе, дублированный пакет egress появится как ingress), но это потребует ядра >= 5.17 для поддержки, в то время как ingress доступен уже долгое время.
Требуется ядро >= 4.10 (для поддержки статической модификации UDP с правильной контрольной суммой).
# nft -f - <<'EOF'
table netdev t_dup # для идемпотентности
delete table netdev t_dup # для идемпотентности
table netdev t_dup {
chain c_ingress {
type filter hook ingress device "lo" priority filter; policy accept;
iif lo udp dport 123 meta mark != 1 meta mark set 1 dup to lo udp dport set 456
}
}
EOF
-
Кандидат-пакет проверяется на наличие метки и обрабатывается только в том случае, если метка отсутствует, начиная с задания метки: это предотвратит возникновение цикла позже.
-
Он дублируется. Метка, являясь частью дублированного sk_buff, также дублируется
Дубликат фактически будет неизмененным пакетом: отправленным в то же место (
lo
) и также на порт 123 -
Оператор
dup
, в отличие от любой цели iptables, включая ее цельTEE
, не является оператором rule, завершающим оператором. Правило продолжается с безстатической модификацией пакета: UDP-порт изменяется на 456 -
Дублированный пакет также прибывает в ingress, но так как он имеет метку, правило игнорирует его: цикл предотвращается
Дублированный порт можно протестировать с помощью socat:
socat -u udp4-recv:456,bind=127.0.0.1 -
Заметки:
-
Если никто не слушает на дублированном порту, будет отправлен ICMP-порт недоступен, но поскольку этот порт (456) не совпадает с портом, на который отправляет приложение (123), он будет проигнорирован стеком сети.
-
Сетевой фильтр ingress происходит после AF_PACKET, tcpdump не захватит измененный порт и не дублированный пакет.
Мне нужно было сделать это для пакетов netflow/IPFix. Я пробовал ваше решение, но оно не сработало для меня как есть.
Тем не менее, вдохновленный вашим и другим ответом, я в конечном итоге получил рабочий вариант. Протестировано на Debian 11 с ядром 5.10:
table ip mangle
delete table ip mangle
table ip mangle {
chain prerouting {
type filter hook prerouting priority mangle; policy accept;
iifname "eth0" udp dport 6660 \
dup to 127.0.0.1 device lo udp dport set 6666 notrack \
dup to 127.0.0.1 device lo udp dport set 6667 notrack \
dup to 127.0.0.1 device lo udp dport set 6668 notrack
}
chain input {
type filter hook input priority mangle; policy accept;
iifname lo udp dport 6666 ip daddr set 127.0.0.1 notrack
iifname lo udp dport 6667 ip daddr set 127.0.0.1 notrack
iifname lo udp dport 6668 ip daddr set 127.0.0.1 notrack
}
}
Это дублирует все, что поступает на eth0 для UDP/6660, на порты UDP локального хоста 6666, 6667 и 6668 и устанавливает адрес назначения на 127.0.0.1. Последнее необходимо, потому что некоторые программы иначе с этим не справляются.
Я протестировал это с Fastnetmon, nfdump/nfsen и AS-Stats.
Для моего случая использования я хотел захватить и отразить трафик, генерируемый процессом на локальной машине. Таким образом, захват, используя фильтр на prerouting
, input
или ingress
, не имеет смысла – Netfilter видит пакеты, сгенерированные локальным процессом, только в output
, а затем в postrouting
(см. эту хорошую графику в вики nftables).
Мое решение моим требованиям – это комбинация ответов @A.B и @Alfredo, где первое правило захватывает в postrouting
, а второе правило переписывает IP-заголовки после того, как дублированный пакет попадает в вход lo
.
Оригинальное использование заключается в захвате отчетов HEP (инкапсулированные захваты пакетов) от локальной службы, которые обычно отправляются в внешнее мониторинговое учреждение, и зеркалировании их на локальный процесс sngrep
, который используется для отладки на машине – поэтому такие специфические названия и адреса портов. “17” просто потому, что мне нравится это число.
table ip t_sngrep
delete table ip t_sngrep
table ip t_sngrep {
chain c_dup {
type filter hook postrouting priority filter; policy accept;
udp dport 9060 meta mark != 17 meta mark set 17 dup to 127.0.0.17 device "lo"
}
chain c_rewrite {
type filter hook input priority filter; policy accept;
# meta mark 17 meta nftrace set 1 # необязательная трассировка, используя nft monitor
meta mark 17 udp dport set 8060 ip saddr set 127.0.0.1 ip daddr set 127.0.0.17
# meta mark 17 log prefix "sgrep_filter " # необязательное для логирования результата
}
}'
Правило переписывания необходимо, потому что в противном случае вы увидите пакеты на lo
от {some-real-ip}
к {some-other-real-ip}
, и sngrep
педантично (и правильно) не будет обрабатывать эти пакеты – поэтому мы переписываем исходные и конечные адреса на что-то, что можно ожидать увидеть на lo
, а также переписываем конечный HEP-порт – для верности и чтобы предотвратить путаницу.
sngrep
затем можно настроить для разбора отраженного HEP-трафика с помощью
sngrep -EL udp:127.0.0.17:8060
Ответ или решение
Дублирование UDP-пакетов с помощью nftables: Полное Решение
Введение
Современные решения в области сетевых технологий требуют высокой гибкости в обработке трафика. Одной из таких задач является необходимость дублирования UDP-пакетов, направленных на определённый IP-адрес и порт, на другой порт, оставаясь при этом на том же IP. В данной статье мы рассмотрим, как достичь этой цели с помощью nftables
и каких шагов следует придерживаться.
Задача
Наша цель — дублировать трафик, направленный на адрес 127.0.0.1
и порт 123
, на тот же адрес 127.0.0.1
, но на порт 456
. Это может понадобиться для мониторинга или сбора статистики, когда требуется, чтобы копии пакетов отправлялись на другой порт для обработки.
Подход
Для решения данной задачи мы будем использовать механизм ingress
и конструкцию dup
в nftables
, что позволяет делать дубликаты пакетов. Важно отметить, что необходимо установить маркер для предотвращения зацикливания.
Пример Конфигурации
Вот пример конфигурации, который позволяет реализовать нашу задачу:
# nft -f - <<EOF
table netdev t_dup {
chain c_ingress {
type filter hook ingress device "lo" priority filter; policy accept;
iif lo udp dport 123 meta mark != 1 meta mark set 1 dup to lo udp dport set 456
}
}
EOF
Объяснение Конфигурации
-
Создание таблицы: Мы создаём таблицу
netdev
с названиемt_dup
, что обеспечивает изоляцию конфигурации. -
Цепочка
ingress
: В цепочкеc_ingress
происходит проверка входящего трафика, который связан с интерфейсомlo
(loopback). -
Условие: Если пакет нацелен на порт
123
и не имеет установленного маркера (то есть не обрабатывался ранее), мы устанавливаем маркер и дублируем пакет на порт456
. -
Дублирование: Конструкция
dup
позволяет отправить дубликат пакета обратно на тот же интерфейсlo
, но с изменённым портом.
Тестирование и Применение
Вы можете протестировать данную конфигурацию с помощью утилиты socat
:
socat -u udp4-recv:456,bind=127.0.0.1 -
Этот пример позволит вам проследить за дублированными пакетами, направленными на порт 456
.
Замечания
- Проблемы с прослушиванием: Если на дублируемом порту (в нашем случае
456
) нет приложения, то может быть выпущено ICMP сообщение о недостижимом порте. Однако это не повлияет на основное приложение, отправляющее пакеты на порт123
. - Учет версий ядра: Убедитесь, что версия ядра вашего Linux >= 4.10 для корректной обработки дублируемых UDP пакетов.
Выводы
Использование nftables
для дублирования UDP-пакетов — это мощное средство, позволяющее тонко настраивать сетевую инфраструктуру. Применяя предложенное решение, вы сможете значительно улучшить свой мониторинг сетевого трафика. Убедитесь в правильности реализации и проведите тестирование, чтобы гарантировать функциональность в вашем конкретном окружении.