I have an SNMP agent listening on a high-level port (16161) and I want to redirect traffic from the standard SNMP agent port 161. Easy iptables rule:
iptables -t nat -A PREROUTING -p udp --dport 161 -j REDIRECT --to-ports 16161
However responses appear to come from port 16161 and are dropped by linux clients.
I want to change the response's source port to 161 (this is also correct per the SNMP spec.) I added:
-t nat -A POSTROUTING -p udp --sport 16161 -j SNAT --to-source :161
and this appears to cause responses to never leave the agent. If I change to-source
to any other port, i.e. 162, it works. Or if I use --dport 162
and have the client send the request to port 162, the response can use port 161. Only when the PREROUTING dport
matches the POSTROUTING to-source
does the response fail to send from the agent.
Example, using PREROUTING --dport 161
and POSTROUTING --to-source 162
:
snmpget -v2c -c public $DEVICE_IP iso.3.6.1.2.1.1.5.0
tcpdump from the agent, source port is changed to 162 on the response packet (expected:)
$ 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"
I can even have a PREROUTING and POSTROUTING rule for the same port, but the request can't come over the same port that the response will use:
$ 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
single tcpdump session:
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
How do I get my agent to accept UDP packets on and send replies on the same port using iptables?