iptables:将入站 UDP 重定向到其他端口,并将响应传出“公共”端口

iptables:将入站 UDP 重定向到其他端口,并将响应传出“公共”端口

我有一个在高级端口(16161)上监听的 SNMP 代理,我想从标准 SNMP 代理端口 161 重定向流量。简单的 iptables 规则:

iptables -t nat -A PREROUTING -p udp --dport 161 -j REDIRECT --to-ports 16161

然而响应似乎来自端口 16161 并被 Linux 客户端丢弃。

我想将响应的源端口更改为 161(根据 SNMP 规范这也是正确的。)我添加了:

-t nat -A POSTROUTING -p udp --sport 16161 -j SNAT --to-source :161

这似乎导致响应永远不会离开代理。如果我更改to-source为任何其他端口,即 162,它就可以正常工作。或者,如果我使用--dport 162并让客户端将请求发送到端口 162,响应可以使用端口 161。只有当 PREROUTINGdport与 POSTROUTING 匹配时to-source,响应才会从代理发送失败。

例如,使用 PREROUTING--dport 161和 POSTROUTING --to-source 162

snmpget -v2c -c public $DEVICE_IP iso.3.6.1.2.1.1.5.0

来自代理的 tcpdump,响应数据包上的源端口更改为 162(预期:)

$ tcpdump -n udp and port 161 or port 162 or port 16161
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
19:47:30.755126 IP 192.168.66.3.55843 > 192.168.9.87.161:  GetRequest(28)  .1.3.6.1.2.1.1.5.0
19:47:30.787415 IP 192.168.9.87.162 > 192.168.66.3.55843:  GetResponse(41)  .1.3.6.1.2.1.1.5.0="foo"

我甚至可以针对同一端口的 PREROUTING 和 POSTROUTING 规则,但请求不能通过响应将使用的同一端口进行:

$ iptables -t nat -L -v
Chain PREROUTING (policy ACCEPT 3 packets, 313 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    2   142 REDIRECT   udp  --  any    any     anywhere             anywhere             udp dpt:snmp redir ports 16161
    0     0 REDIRECT   udp  --  any    any     anywhere             anywhere             udp dpt:snmp-trap redir ports 16161

Chain INPUT (policy ACCEPT 3 packets, 313 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    2   168 SNAT       udp  --  any    any     anywhere             anywhere             udp spt:16161 to::162

单个 tcpdump 会话:

tcpdump -n udp and port 161 or port 162 or port 16161
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes

>>>>>>> made request to port 161, response over 162, OK <<<<<<<<<

19:55:10.709670 IP 192.168.66.3.51621 > 192.168.9.87.161:  GetRequest(28)  .1.3.6.1.2.1.1.5.0
19:55:10.751607 IP 192.168.9.87.162 > 192.168.66.3.51621:  GetResponse(41)  .1.3.6.1.2.1.1.5.0="foo"

>>>>>>> made request to port 162, response not sent <<<<<<<<<

19:55:20.372213 IP 192.168.66.3.55108 > 192.168.9.87.162:  GetRequest(28)  .1.3.6.1.2.1.1.5.0
19:55:21.378445 IP 192.168.66.3.55108 > 192.168.9.87.162:  GetRequest(28)  .1.3.6.1.2.1.1.5.0
19:55:22.380925 IP 192.168.66.3.55108 > 192.168.9.87.162:  GetRequest(28)  .1.3.6.1.2.1.1.5.0
19:55:23.390915 IP 192.168.66.3.55108 > 192.168.9.87.162:  GetRequest(28)  .1.3.6.1.2.1.1.5.0
19:55:24.393482 IP 192.168.66.3.55108 > 192.168.9.87.162:  GetRequest(28)  .1.3.6.1.2.1.1.5.0
19:55:25.397306 IP 192.168.66.3.55108 > 192.168.9.87.162:  GetRequest(28)  .1.3.6.1.2.1.1.5.0

如何让我的代理使用 iptables 在同一端口上接受 UDP 数据包并发送回复?

答案1

感谢 Tero 对我的问题的评论,使用-j DNAT代替REDIRECT是缺少的调味料。最终解决方案:

在 nat 规则中:

-A PREROUTING -p udp --dport 161 -j DNAT --to-destination :16161
-A POSTROUTING -p udp --sport 16161 -j SNAT --to-source :161

过滤规则:

-A INPUT -p udp --dport 16161 -m conntrack --ctstate DNAT -j ACCEPT

诀窍--ctstate DNAT来自这个答案因此只有端口 161 接受连接,而不接受 16161。

答案2

这是一适用于 MacOS 和 Linux 的替代 UDP 重定向器;除了通常的源/目标之外,它还支持指定源/目标接口,以及丢弃火星人(来自未知来源的 UDP 数据包)。

您可以这样运行它:

./udp-redirect \
   --listen-port 161 \
   --connect-address 127.0.0.1 --connect-port 16161

SNMP 客户端会将数据包发送到端口 161,然后端口 161 会将数据包重定向到端口 16161;返回的数据包会从端口 16161 经过重定向器发送出去。

免责声明:我是作者,我现在正在这篇文章中使用它来重定向 Wireguard 流量。

相关内容