iptables / nftables:将UDP数据转发到多个目标

Kev*_*ier 5 networking linux iptables forwarding nftables

我需要为以下场景创建 iptables 规则:

  • 不同的主机向主机发送UDP数据A。目标端口是1234.
  • 主机A(8.2.3.4)将收到的UDP数据重定向到主机B1(​​7.2.3.1)、B2(22.93.12.3)、... Bn(12.42.1.3);IP 地址仅供参考。
  • 它与负载平衡无关,因此每个主机B1, B2, ...Bn必须接收所有包。因此,主机A必须复制包。
  • 转发的包必须有正确的目标IP(B1, B2, ... Bn)和源IP(主机A
  • 我无法更改向主机发送数据的初始主机上的任何内容A
  • 我无法更改目标主机上的任何内容B1B2...Bn
  • 主持人B1, B2, ...Bn不必能够回复

我尝试用PREROUTING/解决这个问题mangle

HOST_A=8.2.3.4
HOST_B1=7.2.3.1
HOST_B2=22.93.12.3
...
HOST_BN=12.42.1.3

iptables -F -t mangle
iptables -t mangle -A PREROUTING -d $HOST_A -p udp --dport 1234 -j TEE --gateway $HOST_B1
iptables -t mangle -A PREROUTING -d $HOST_A -p udp --dport 1234 -j TEE --gateway $HOST_B2
...
iptables -t mangle -A PREROUTING -d $HOST_A -p udp --dport 1234 -j TEE --gateway $HOST_BN

iptables -L -t mangle
Run Code Online (Sandbox Code Playgroud)

主机B1, B2, ...Bn似乎没有收到数据。有谁知道出了什么问题吗?调试实际上相当棘手(我发现没有真正的方法来做到这一点)。

谢谢

A.B*_*A.B 4

采样器

\n

有一个工具可以满足所有条件,samplicator

\n
\n

UDP采样器

\n

这个小程序在给定端口上接收 UDP 数据报,然后将这些数据报重新发送到一组指定的接收器。此外,可以为每个接收器单独指定采样除数 N,然后接收器将仅接收所接收数据包的 N 个中的一个。

\n
\n

在主机 A 上运行的示例命令将与 OP 的目标 B1 B2 和 Bn 示例相匹配:

\n
samplicate -p 1234 7.2.3.1/1234 22.93.12.3/1234 12.42.1.3/1234\n
Run Code Online (Sandbox Code Playgroud)\n

这可能是更合理的做法。

\n
\n

nftables

\n

对于不合理的方法,这可以在内核中完成,要么使用困难的iptables (例如,在这个UL SE Q/A中我的答案中只有两个重复项),要么使用可以执行无状态 NAT 的nftables ,避免与conntrack相关的一些复杂性区域

\n

nftables使用iptablesTEE等效项:dup

\n
\n

DUP声明

\n

dup 语句用于复制数据包并将副本发送到不同的目的地。

\n

dup 到 设备
\n dup 到 地址 设备 device

\n
\n

注意:第一个语法不能在该ip系列中使用,而只能在该netdev系列中使用,这会增加多个问题,其中一个是必须猜测正确的 MAC 地址(在以太网接口的情况下),这也需要更改,所以变得不太实用。

\n

dup具有与TEE相同的行为:副本必须立即“疏散”到接口上的网关(网关意味着 IPv4 地址,如果与接口类型相关,则仅用于使用 ARP 解析目标 MAC 地址,但不在 IP 数据包本身中)可能是为了避免路由堆栈的其余部分对其进行异常处理。最终目的地不能是网关地址(除非恰好在同一个局域网中)。

\n

这里完成了一个特殊的路由设置,以便将已经无状态的SNATed(到 A 自己的地址)/DNATed(到最终目的地)数据包注入回主机本身,以便主机进一步将它们路由到目的地,就好像它一样实际上是自己发出来的。这需要接受接收自己的本地 IP 地址,并禁用接收veth接口上的所有反向路径过滤器(因此也需要在所有设置上执行此操作)。它仍然可以在eth0上显式重新启用

\n

除了其初始运行的网络配置(使用其单个接口eth0)之外,在主机 A 上进行设置)之外,在主机 A 上进行设置:

\n
HOST_A=8.2.3.4\n\nip link add name vethinj up type veth peer name vethgw\nip link set vethgw up\nsysctl -w net.ipv4.conf.vethgw.forwarding=1\nsysctl -w net.ipv4.conf.vethgw.accept_local=1\nsysctl -w net.ipv4.conf.vethgw.rp_filter=0\nsysctl -w net.ipv4.conf.all.rp_filter=0\nip route add $HOST_A/32 dev vethinj\n
Run Code Online (Sandbox Code Playgroud)\n

无需分配额外的 IP 地址。Linux使用弱主机模型, eth0上的IP地址在vethgw上可用,因此可以通过vethinj作为网关进行访问。,因此一旦添加路由,

\n

文件中的nftables规则将multiply.nft在下面加载nft -f multiply.nft

\n
    \n
  • 匹配数据包进行相乘
  • \n
  • 对 A 自己的地址执行无状态SNAT ( )。ip saddr set这不涉及conntrack的NAT。
  • \n
  • 对于每个目标 Bx,对目标 HOST_Bx 执行无状态 DNAT ( ip daddr set),并将数据包复制到 veth 对的注入侧使用 A 自己的地址作为网关。
  • \n
  • 丢弃剩余的更改过的原件,因为它不再有用。
  • \n
\n

multiply.nft:

\n
define HOST_A=8.2.3.4\ndefine HOST_B1=7.2.3.1\ndefine HOST_B2=22.93.12.3\ndefine HOST_Bn=12.42.1.3\n\ntable ip multiply\ndelete table ip multiply\n\ntable ip multiply {\n        chain c {\n                type filter hook prerouting priority -300; policy accept;\n                iif != vethgw ip daddr $HOST_A udp dport 1234 ip saddr set $HOST_A goto cmultiply\n        }\n\n        chain cmultiply {\n                jump cdnatdup\n                drop\n        }\n\n        chain cdnatdup {\n                ip daddr set $HOST_B1 dup to $HOST_A device vethinj\n                ip daddr set $HOST_B2 dup to $HOST_A device vethinj\n\n                ip daddr set $HOST_Bn dup to $HOST_A device vethinj\n        }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

要在此之后添加新的目标 192.0.2.2,可以手动执行以下操作:

\n
nft add rule ip multiply cdnatdup ip daddr set 192.0.2.2 dup to 8.2.3.4 device vethinj\n
Run Code Online (Sandbox Code Playgroud)\n

下面是来自 S2 并复制到 B1、B2 和 Bn 的单个数据包的文本示意图:

\n
S1 \xe2\x86\x92\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x95\xae                        \xe2\x95\xad\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x86\x92 B1\nS2 \xe2\x86\x92\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x95\xae \xe2\x94\x8a                        \xe2\x94\x8a \xe2\x95\xad\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x86\x92 B2\n...    \xe2\x94\x8a \xe2\x94\x8a                        \xe2\x94\x8a \xe2\x94\x8a       ...\nSn \xe2\x86\x92\xe2\x94\x84\xe2\x95\xae \xe2\x94\x8a \xe2\x94\x8a                        \xe2\x94\x8a \xe2\x94\x8a \xe2\x95\xad\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x86\x92 Bn\n     \xe2\x94\x8a \xe2\x94\x8a \xe2\x95\xb0\xe2\x94\x84\xe2\x94\x84  \xe2\x94\x84      \xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90\xe2\x86\x97\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x95\xaf \xe2\x94\x8a \xe2\x94\x8a\n     \xe2\x94\x8a \xe2\x95\xb0\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x86\x92\xe2\x94\x82 eth0 \xe2\x94\x82\xe2\x86\x92\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x95\xaf \xe2\x94\x8a\n     \xe2\x95\xb0\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84 \xe2\x94\x84       \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98\xe2\x86\x98\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x94\x84\xe2\x95\xaf\n                    \xe2\x86\x99      \xe2\x86\x96\xe2\x86\x96\xe2\x86\x96\n             snat  \xe2\x86\xaf        \xe2\x86\x91\xe2\x86\x91\xe2\x86\x91  internal\n  nftables:  dnat  \xe2\x87\x8a    A   \xe2\x86\x91\xe2\x86\x91\xe2\x86\x91  routing\n            & dup \xe2\x86\x93\xe2\x86\x93\xe2\x86\x93       \xe2\x86\x91\xe2\x86\x91\xe2\x86\x91\n               \xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90  \xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90\n               \xe2\x94\x82vethinj\xe2\x94\x82  \xe2\x94\x82vethgw \xe2\x94\x82\n               \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98  \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98\n                    \xe2\x95\xb0\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80 \xe2\x87\xb6 \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x95\xaf \n                   virtual wire\n
Run Code Online (Sandbox Code Playgroud)\n

注意:由于此 NAT 不是由conntrack处理的,因此不可能让 B1 B2...Bn 回复原始源,但这已被 OP 放弃。

\n