iptables REDIRECT 仅适用于第一个数据包

iptables REDIRECT 仅适用于第一个数据包

如果数据包包含例如字符串test,我需要将所有目标端口为 15000 的 UDP 数据包重定向到端口 15001。我有以下两个简单规则:

iptables -t nat -A PREROUTING -i eth0 -p udp --dport 15000 -m string --string 'test' --algo bm -j LOG --log-prefix='[netfilter] '
iptables -t nat -A PREROUTING -i eth0 -p udp --dport 15000 -m string --string 'test' --algo bm -j REDIRECT --to-ports 15001

奇怪的行为:

  • 如果第一个数据包包含test字符串,则重定向 全部连接的数据包;
  • 如果连接的第一个数据包不包含test,则永远不会进行重定向,即使后续数据包包含test

但是所有符合规则的数据包都被正确记录。

我还尝试将轨道信息添加到规则中:

-m state --state NEW,ESTABLISHED

但行为是一样的。有什么想法吗?

这是完整的iptables规则集:

过滤表:

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination  

nat 表:

Chain PREROUTING (policy ACCEPT)
 target     prot opt source               destination         
 LOG        udp  --  anywhere             anywhere             udp dpt:15000 STRING match  "test" ALGO name bm TO 65535 LOG level warning prefix "[netfilter] "
 REDIRECT   udp  --  anywhere             anywhere             udp dpt:15000 STRING match  "test" ALGO name bm TO 65535 redir ports 15001

 Chain INPUT (policy ACCEPT)
 target     prot opt source               destination         

 Chain OUTPUT (policy ACCEPT)
 target     prot opt source               destination         

 Chain POSTROUTING (policy ACCEPT)

混淆表:

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination  

原始表:

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

答案1

nat 表规则始终仅适用于连接中的第一个数据包。同一连接的后续数据包永远不会遍历 nat 规则列表,并且仅由 conntrack 代码支持

由于 UDP 本质上是无连接的,因此这里的“连接”仅由地址、端口和超时定义。因此,如果第二个具有相同源端口和地址以及相同目标端口和地址的 UDP 数据包在超时内到达,Linux 会认为它属于已建立的“连接”,并且根本不会评估 nat 规则表,而是重复使用对前一个数据包发出的判决。

看这里:http://www.netfilter.org/documentation/HOWTO/netfilter-hacking-HOWTO-3.html

答案2

这是因为 iptables 在PREROUTING链上应用了连接跟踪。每当建立新连接时,iptables 都会查阅 conntrack 缓存。如果找到匹配项,则不会从 nat 表中应用任何规则。

如果您想禁用更改此行为,请查看NOTRACK原始表中的目标。

请注意,这甚至适用于 UDP(无连接协议)。第一个数据包被视为打开连接NEW,另一个数据包被视为回复ESTABLISHED

我找到了一篇相关文章服务器故障

答案3

iptables 与连接跟踪区域

conntrack 区域功能允许将两个相同的 conntrack 5-uples(或其中的一部分)视为不同的属性。这通常可能与基于复杂策略的路由一起使用,处理相同的 IP,但流经不同的路径(路由),以防止 conntrack 合并来自不同路径的不相关流。

这里可以用它来解决这个问题:考虑UDP数据包没有test和数据包必须test是两个不同来源区域的一部分(通过使用CT --zone-orig):正常区域和重定向区域。每个源区域将允许状态中的 conntrack 条目NEW不发生冲突并被视为独立。假设钩子中有两个 nat 表PREROUTING:规则评估不是nat针对流的第一个数据包进行一次,而是针对第一个正常数据包进行一次,针对第一个test数据包进行一次。

虽然这不是真正需要的,但为了避免更多的重复规则,我会设置一个标记并在以后重复使用它以简化。

iptables -t raw -A PREROUTING -i eth0 -p udp --dport 15000 -m string --string 'test' --algo bm -j MARK --set-mark 1
iptables -t raw -A PREROUTING -m mark --mark 1 -j CT --zone-orig 1   
iptables -t nat -A PREROUTING -m mark --mark 1 -j LOG --log-prefix='[netfilter] '
iptables -t nat -A PREROUTING -p udp -m mark --mark 1 -j REDIRECT --to-ports 15001

测试(服务器 IP 为10.0.3.66)。按时间顺序,在查询之后输入的答案(来自术语 1 的答案 1 和来自术语 2 的答案 2):

serverterm1$ socat udp4-listen:15000,reuseaddr,fork -
query1normal
query3normal
answer1

serverterm2$ socat udp4-listen:15001,reuseaddr,fork -
query2test
query4test
answer2

client$ socat udp4:10.0.3.66:15000 -
query1normal
query2test
query3normal
query4test
answer1
answer2

serverterm3# conntrack -E -p udp --orig-port-dst 15000
    [NEW] udp      17 30 src=10.0.3.1 dst=10.0.3.66 sport=33150 dport=15000 [UNREPLIED] src=10.0.3.66 dst=10.0.3.1 sport=15000 dport=33150
    [NEW] udp      17 30 src=10.0.3.1 dst=10.0.3.66 sport=33150 dport=15000 zone-orig=1 [UNREPLIED] src=10.0.3.66 dst=10.0.3.1 sport=15001 dport=33150
 [UPDATE] udp      17 30 src=10.0.3.1 dst=10.0.3.66 sport=33150 dport=15000 src=10.0.3.66 dst=10.0.3.1 sport=15000 dport=33150
 [UPDATE] udp      17 30 src=10.0.3.1 dst=10.0.3.66 sport=33150 dport=15000 zone-orig=1 src=10.0.3.66 dst=10.0.3.1 sport=15001 dport=33150

警告:string针对流中的每个数据包评估匹配。如果可能,请考虑使用u32以减少开销。

相关内容