1

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?

  • 1
    Have you tried iptables -t nat -A PREROUTING -p udp --dport 161 -j DNAT --to-destination 127.0.0.1:16161 rule only? – Tero Kilkanen Jun 26 at 7:03
  • Thanks @Tero I will try that. I was wondering if maybe REDIRECT was causing conntrack to attempt some stateful handling on the steam that was causing issues with the response. – thom_nic Jun 26 at 10:57
0

Thanks to Tero's comment on my question, using -j DNAT instead of REDIRECT was the missing sauce. Final solution:

in nat rules:

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

filter rules:

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

The --ctstate DNAT trick came from this answer so only port 161 accepts connections and not also 16161.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.