Вопрос или проблема
У меня есть сервер H с двумя сетевыми адаптерами с IP-адресами 192.168.105.10
и 192.168.104.10
. Приложение, работающее на H, получает данные от сервера C по UDP порту 1703
. IP-адрес сервера C — 192.168.105.14
Я хочу дублировать входящие UDP пакеты и отправлять их на сервер D, где другое приложение слушает на 192.168.104.11
также на порту 1703
.
H работает на debian 11 (ядро 5.10).
Пока у меня есть следующая настройка таблицы NFT на H:
#!/sbin/nft -f
table ip route_C_packets
delete table ip route_C_packets
table ip route_C_packets {
chain C_in {
type filter hook prerouting priority 0; policy accept;
ip saddr "192.168.105.14" udp port 1703 ip daddr set "192.168.104.11" dup to "192.168.104.11" ip daddr set "192.168.105.10"
}
}
Это работает, однако выглядит немного некрасиво. Согласно моему пониманию:
ip saddr "192.168.105.14" udp port 1703
: фильтрует только UDP пакеты из C на интересующем меня порту
ip daddr set "192.168.104.11
: переопределяет адрес назначения (так что приложение, работающее на D, действительно может их получить)
dup_to "192.168.104.11"
: дублирует пакет и отправляет его на D, но самостоятельно не модифицирует daddr
ip daddr set "192.168.105.10"
: восстанавливает исходный адрес назначения для не дублированного пакета, чтобы приложение, работающее на H, могло действительно его получить.
Этот трюк с изменением daddr
и затем восстановлением его обратно кажется мне неправильным. Есть ли какой-то синтаксис, чтобы установить daddr
на дублированном пакете, а не на исходном?
ИЗМЕНЕНИЕ: Все здесь имеет маску подсети 255.255.255.0
. 168.105
и 168.104
по сути две изолированные сети.
Ответ или решение
Для решения поставленной задачи, в которой необходимо дублировать UDP пакеты с одного сервера на другой, сохраняя при этом их доставку на основной сервер, необходим корректный подход с использованием nftables. В осуществленной вами конфигурации существует логическая ошибка, связанная с изменением адреса назначения и его последующим восстановлением. Это действительно не самый элегантный способ решения проблемы, однако существует более прямолинейный метод использования nftables для корректного дублирования пакетов, с модификацией адреса назначения только для дублированного экземпляра пакета.
Теория
В данном случае мы имеем сервер H с двумя сетевыми интерфейсами, на который поступают UDP пакеты от сервера C. Задача состоит в том, чтобы не только обеспечить доставку этих пакетов на сервер H, но и продублировать их на сервер D. nftables позволяет управлять сетевыми пакетами, предоставляя возможности для фильтрации, маршрутизации и модификации пакетов на уровне ядра.
Важно понимать, что используемая функция dup
служит для дублирования пакетов. Однако в документации к nftables функция dup
воспринимается как операция, которая только повторяет пакет, добавляя его в очередь отправки ещё раз с теми же данными, без непосредственной возможности изменения адреса назначения в этой копии. Изменение адресного назначения, как правило, подразумевает использование механизма NAT, в частности, цели SNAT или DNAT.
Пример
Ваш существующий скрипт:
#!/sbin/nft -f
table ip route_C_packets
delete table ip route_C_packets
table ip route_C_packets {
chain C_in {
type filter hook prerouting priority 0; policy accept;
ip saddr "192.168.105.14" udp port 1703 ip daddr set "192.168.104.11" dup to "192.168.104.11" ip daddr set "192.168.105.10"
}
}
может быть оптимизирован. Альтернативный подход будет заключаться в использовании цепочек и правил, обеспечивающих нужную логику.
Применение
Для достижения желаемого результата без "хаков" с изменением и восстановлением адреса назначения исходных пакетов, мы можем воспользоваться командой chain
. Мы можем создать две разные цепочки: одну для изменения исходящих пакетов, и вторую, которая просто будет дублировать пакеты на нужный IP адрес:
#!/sbin/nft -f
table ip route_C_packets
delete table ip route_C_packets
table ip route_C_packets {
chain C_in {
type filter hook prerouting priority 0; policy accept;
ip saddr "192.168.105.14" udp dport 1703 dup to "192.168.104.11"
}
chain C_dup {
type nat hook postrouting priority 100; policy accept;
ip saddr "192.168.105.14" udp dport 1703 ip daddr "192.168.104.11" snat to "192.168.105.10"
}
}
В этом примере:
-
Выделение цепочек: Мы создаем две цепочки —
C_in
для дублирования пакетов иC_dup
для изменения адреса назначения в дубликате. -
Дублирование с
dup to
: ВC_in
мы просто используем командуdup to "192.168.104.11"
, которая отвечает за дублирование пакетов на сервер D. Это нужно для создания копии пакета без изменений в IP адресах. -
NAT для дублированного пакета: В этапе postrouting с помощью
C_dup
, после дублирования, можно попытаться использовать NAT для изменения адреса назначения в дублированном пакете, однако это может зависеть от версии nftables — изменять его только при отправке дубликатов. Как правило, для такой задачи может понадобиться дополнительная настройка и проверка с использованием подменных IP или маршрутов.
Обработка и реализация NAT на дублированных пакетах в одной строке, как это представлено в примере, может быть не полностью совместима с текущими версиями nftables. Если указанное решение не помогает, может потребоваться разбивка задачи на несколько этапов с дополнительным использованием промежуточных решений либо внешних скриптов, чтобы гарантировать остановку процессов и сетевую маршрутизацию корректным образом.
Подобные изменения требуют аккуратного тестирования в тестовой среде, чтобы убедиться, что оригинальные и дублированные данные отправляются и принимаются корректно. Это связано с масштабируемостью и гибкостью сетевых конфигураций, использующих nftables, в сравнении с устаревшими iptables.