21 September 2011

UDP port forwarding with socat

This morning I was trying to do what should be a trivial operation with any modern operating system: forward traffic destined for a UDP port on my machine to a different port on the same machine. Specifically, I wanted to redirect SNMP traffic coming in to UDP port 161 over to UDP port 10161 so a user program could receive the packets.

My first feeble attempts to achieve this with netcat (or nc) met with failure, when the sending netcat process terminated after processing the first UDP datagram:

# This processes one packet then dies :-(
$ sudo nc -u -l 161 | nc -k -u localhost 10161

Perhaps there’s some way to get the second process not to die when it receives the data, but I couldn’t see how to do it.

The second approach I tried was using my Mac’s firewall tool, ipfw. This is the BSD industrial-strength firewall tool and should definitely be up to the task.

You need to enable the firewall via System Preferences, Security, then add the rule via ipfw. Here’s the rule I added:

# This logs that it is redirecting traffic but doesn't seem to do it
$ sudo ipfw add fwd localhost,10161 log udp from any to any dst-port 161 in

Again, this seems like it should work, the system logs indicated it was working, but no data arrived on port 10161 when I configured the listening process. Here are the configured rules listed by ipfw:

$ sudo ipfw list
00100 fwd,10161 log udp from any to any dst-port 161 in
65535 allow ip from any to any


After all these false starts, my actual solution was to install and use socat, a multi-purpose networking relay tool. Here’s the relevant command:

$ sudo socat UDP4-RECVFROM:161,fork UDP4-SENDTO:localhost:10161

Running this in the background redirects all the traffic from UDP port 161 to port 10161 on the localhost loopback interface. I also ended up redirecting stderr to /dev/null/ to avoid useless errors when the listening process on port 10161 wasn’t running.

If you know a way to get the same thing working with either of the tools above, please let me know. I’d be glad to have it posted here for posterity.

Update 15 November: UDP4-RECVFROM and UDP4-SENDTO are better options for use with an unreliable receiving server.