Forwarding SNMP ports over SSH using socat

Here is an example of the problem we need to solve: We have SSH access to a network, but want to access an SNMP agent in that network from a local client. We use SNMP here in this example, but it could be any other protocol that uses UDP, such as DNS or TFTP.

We’ll forward the SNMP traffic in a TCP port like this, with “socat” doing the UDP-in-TCP tunneling:

One could use netcat, and that works as long as the SNMP client uses the same source port. But it changes source port eventually, trust me! 🙂

Instead, we use socat. It has a “fork” parameter, that does exactly what we want.

Install socat

socat needs to be installed on both the SSH client and server. On ubuntu/debian this is done with:

client$ sudo apt-get install socat
client$ ssh server
server$ sudo apt-get install socat

Stop the SSH client’s snmpd (if any)

Because we’ll want the SNMP manager to be able to query the SSH client as if it was the switch, SSH client’s snmpd (listening on UDP port 161), needs to be stopped. Again, on ubuntu/debian this is done with:

client$ sudo /etc/init.d/snmpd stop

Run socat on both SSH client and server

Now we’re ready to run this. You’ll need two terminals that start on the SSH client to sit around doing nothing (or use screen)

Terminal one:

client$ ssh -L 10000:localhost:10000 server
server$ socat -T10 TCP4-LISTEN:10000,fork UDP4:switch:161

This creates the SSH forwarding of TCP port 10000 and runs socat on the server. Notice how the switch’s IP address is mentioned in the socat command line as “switch”.

Terminal two:

client$ sudo socat UDP4-LISTEN:161,fork TCP4:localhost:10000

That sets up socat on the client. That should do it.

Test it!

client$ snmpget -v2c -cpublic localhost sysName.0
SNMPv2-MIB::sysName.0 = STRING: switch

Yup, it works!

14 thoughts on “Forwarding SNMP ports over SSH using socat”

  1. Cool !
    I use it to grab MRTG data from my ISP router through SNMP tunnel. I did it effortlessly y straight forward.
    Thanks a lot for your post.

  2. Newbie here, I am using OpenSSH_4.1p1, OpenSSL 0.9.8 05 Jul 2005 on Cygwin, and the -L parameter shows different parameters for the -L switch:

    [-L [bind_address:]port:host:hostport]

  3. Hey,

    Do you know of a way to achieve this without installing socat? I am trying to do exactly this to a setup I have at CERN but due to security restrictions I am unable to install anything on the gateway.

    Is there an executable version of socat, that I can run from a local AFS directory, that you know of? Would I have to run it as sudo anyway?


    1. Sure, you don’t *need* socat. You could write this from scratch in any language you like. Whether or not you can find a statically linked socat executable depends e.g. on you OS, distribution. Basically, I have no idea. I haven’t needed it yet.

  4. I stumbled upon this little gem while trying to work out a remote maintenance solution and it “works” but there’s one little thing that would need to be added/changed in order for it to work correctly. The equipment we are maintaining actually needs both UDP 161 AND UDP 162 in order to work correctly. I’ve tried a few variations to your solution but I can’t seem to get it to work right. Can you offer any suggestions or corrections to allow for both snmp ports to tunnel through ssh?

    1. 🙂 A little clarification here…

      Port 161 is for SNMP get, get-next, get-bulk, set and their responses. The SNMP Manager initiates the conversation by “sending a request”. The SNMP agent handles that request and sends a response. My example above only deals with port 161.

      Port 162 is for SNMP traps and informs, i.e. asynchronous notifications. Think “alerts” or “alarms” that the equipment sends to a manager, when the equipment discovers something is wrong. First you’ll need to configure the equipment to actually send something you “server”!!! (As is often the case, tshark is your friend). If you then still want to forward port 162, first you’ll need some running SNMP trap daemon (snmptrapd in Linux) that can receive and handle SNMP traps and informs (on the “client” side!) . On my debian & ubuntu boxes, it can’t be localhost, since we need to stop “snmp”, which is both snmpd and snmptrapd, in order for port 161 port forwarding to work.

      Once you have a trap receiver running (say on the host “trapreceiver”), the original SSH port forwarding command could look like this instead of the “ssh -L …” command above:

      ssh -L 10000:localhost:10000 -R 10001:localhost:10001 server

      Then, in addition to the other socat commands above:

      On the client machine, run:
      socat -T10 TCP4-LISTEN:10001,fork UDP4:trapreceiver:162

      And on the server machine run:
      sudo socat UDP4-LISTEN:162,fork TCP4:localhost:10001

      I haven’t tried this myself, but I’m pretty sure it will work. The tricky question is what to do with the traps once they’re received; what do you actually want to do with the traffic you get on trapreceiver’s port 162. By default snmptrapd doesn’t do anything useful. It’ll depend on the equipment and your use case.

  5. This is good stuff , thanks for putting it out there

    I am working on a Ubuntu Host.
    The Ubuntu Host can ssh to a Cent OS server inside our lab.
    Only the CentOS server can perform snmp commands on a device.
    I desire to run snmp gets from Ubuntu to the device and cannot.
    So your solution sounds exactly what I need.
    My assumption is Ubuntu is the SSH client, CENTOS is the SNMP Manager, and the device is the SNMP Agent.

    So I installed socat on Ubuntu and CENT OS, configured as shown, but still could not reach the device using SNMP from Ubuntu.

    I did this on Ubuntu
    client$ ssh -L 10000:localhost:10000 server
    which took me to the CENTOS then did this command

    and in a second terminal on the Ubuntu did this

    then tried to run a snmp command from ubuntu expecting the snmp get to hit the device , but got snmp timeout.

    Can you offer any corrections.

    Thanks in advance.

  6. Thanks for your post!

    I’m having trouble though.. server side is a Linux machine, client side is a mac. On the client after doing the SNMP query I get the response back and then socat seems to die trying to re-bind to 161?

    $ sudo socat -s UDP4-LISTEN:161,fork TCP4:localhost:10161
    2017/08/14 16:54:55 socat[27401] E bind(5, {LEN=16 AF=2}, 16): Address already in use

    any ideas?

  7. So, I had the issue that I was only able to send one command over the UDP socket 161, before it failed with: “Address already in use”. The solution for me, was to use:
    “socat -T15 udp4-recvfrom:161,reuseaddr,fork tcp:localhost:10000”

    The main difference being the use of UDP4-RECVFROM instead of UDP4-LISTEN. This allows me to send and receive multiple replies.

  8. thanks for this. I adapted the solution above to get DNS working over an SSH tunnel

    user@local:~$ ssh -L 10000:localhost:10000 ${SERVER}
    user@server:~$ socat -T10 TCP4-LISTEN:10000,fork UDP4:${DNSSERVER}:53

    user@local:~$ sudo socat UDP4-LISTEN:53,fork TCP4:localhost:10000

Leave a Reply
