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

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

我需要为以下场景创建 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
  • 我无法在目标主机上更改任何内容B1,,B2...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

主机B1B2、 ...Bn似乎没有收到数据。有人知道哪里出了问题吗?调试实际上相当棘手(我发现没有真正的方法可以做到这一点)。

谢谢

答案1

取样器

有一个工具可以满足所有条件,取样器

UDP 采样器

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

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

samplicate -p 1234 7.2.3.1/1234 22.93.12.3/1234 12.42.1.3/1234

这或许是更合理的做法。


nftables

对于不合理的方法,这可以在内核中完成,或者使用iptables有困难(例如,在我的答案中只有两个重复UL SE 问答)或nftables可以做无状态 NAT避免与以下相关的一些复杂性连接跟踪区域

nftables用途iptables球座相等的:重复

DUP 声明

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

重复 设备
重复 地址 设备 设备

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

重复其行为与球座:必须立即将重复项“撤离”到接口上的网关(网关意味着 IPv4 地址,如果与接口类型相关,则仅用于使用 ARP 解析目标 MAC 地址,但不在 IP 数据包本身中)以避免被路由堆栈的其余部分异常处理。最终目的地不能是网关地址(除非恰巧在同一个局域网内)。

这里进行了特殊的路由设置,以便将已经无国籍将经过 SNAT 处理(到 A 自己的地址)/ DNAT 处理(到最终目的地)的数据包发送到主机本身,以便主机进一步将这些数据包路由到目的地,就好像这些数据包实际上是由主机自己发出的一样。这需要接受接收自己的本地 IP 地址,并禁用所有反向路径过滤器在接收韦特接口(因此需要在全部设置)。它仍然可以在eth0如果需要的话。

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

HOST_A=8.2.3.4

ip link add name vethinj up type veth peer name vethgw
ip link set vethgw up
sysctl -w net.ipv4.conf.vethgw.forwarding=1
sysctl -w net.ipv4.conf.vethgw.accept_local=1
sysctl -w net.ipv4.conf.vethgw.rp_filter=0
sysctl -w net.ipv4.conf.all.rp_filter=0
ip route add $HOST_A/32 dev vethinj

没有额外的 IP 地址可供分配。Linux 使用弱主机模型,IP 地址eth0可在韋斯因此可以作为网关通过韦希尼一旦路线被添加。

nftables文件中的规则multiply.nft,下面要加载的nft -f multiply.nft是:

  • 匹配数据包以进行乘法
  • 做一个无国籍者SNAT(ip saddr set)到 A 自己的地址。这不涉及连接跟踪的 NAT。
  • 对于每个目的地Bx,对目的地HOST_Bx进行无状态DNAT(ip daddr set),并将数据包复制到注入侧韦特对,使用A自己的地址作为网关。
  • 删除剩余的已更改的原件,因为它不再有用。

multiply.nft

define HOST_A=8.2.3.4
define HOST_B1=7.2.3.1
define HOST_B2=22.93.12.3
define HOST_Bn=12.42.1.3

table ip multiply
delete table ip multiply

table ip multiply {
        chain c {
                type filter hook prerouting priority -300; policy accept;
                iif != vethgw ip daddr $HOST_A udp dport 1234 ip saddr set $HOST_A goto cmultiply
        }

        chain cmultiply {
                jump cdnatdup
                drop
        }

        chain cdnatdup {
                ip daddr set $HOST_B1 dup to $HOST_A device vethinj
                ip daddr set $HOST_B2 dup to $HOST_A device vethinj

                ip daddr set $HOST_Bn dup to $HOST_A device vethinj
        }
}

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

nft add rule ip multiply cdnatdup ip daddr set 192.0.2.2 dup to 8.2.3.4 device vethinj

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

S1 →┄┄┄┄┄╮                        ╭┄┄┄┄┄┄┄┄→ B1
S2 →┄┄┄╮ ┊                        ┊ ╭┄┄┄┄┄┄→ B2
...    ┊ ┊                        ┊ ┊       ...
Sn →┄╮ ┊ ┊                        ┊ ┊ ╭┄┄┄┄→ Bn
     ┊ ┊ ╰┄┄  ┄      ┌──────┐↗┄┄┄┄╯ ┊ ┊
     ┊ ╰┄┄┄┄┄┄┄┄┄┄┄┄→│ eth0 │→┄┄┄┄┄┄╯ ┊
     ╰┄┄┄┄┄┄ ┄       └──────┘↘┄┄┄┄┄┄┄┄╯
                    ↙      ↖↖↖
             snat  ↯        ↑↑↑  internal
  nftables:  dnat  ⇊    A   ↑↑↑  routing
            & dup ↓↓↓       ↑↑↑
               ┌───────┐  ┌───────┐
               │vethinj│  │vethgw │
               └───────┘  └───────┘
                    ╰─── ⇶ ───╯ 
                   virtual wire

注意:由于此 NAT 不是由连接跟踪B1 B2...Bn 不可能回答原始来源,但是 OP 放弃了这一权利。

相关内容