The title pretty much sums it up. I would like to send UDP traffic through a SSH tunnel. Specifically, I need to be able to send UDP packets through the tunnel and have the server be able to send them back to me on the other side. I know how to do it for TCP connections. Is this it possible with UDP?
11 Answers
This small guide tells you how to send UDP traffic via SSH using tools that come standard (ssh,nc,mkfifo) with most UNIX-like operating systems.
Performing UDP tunneling through an SSH connection
Step by step
Open a TCP forward port with your SSH connection
On your local machine (local), connect to the distant machine (server) by SSH, with the additional -L option so that SSH will do TCP port-forwarding:
local# ssh -L 6667:localhost:6667 server.foo.com
This will allow TCP connections on the port number 6667 of your local machine to be forwarded to the port number 6667 on server.foo.com through the secure channel.
Setup the TCP to UDP forward on the server
On the server, we open a listener on the TCP port 6667 which will forward data to UDP port 53 of a specified IP. If you want to do DNS forwarding like me, you can take the first nameserver's IP you will find in /etc/resolv.conf.
But first, we need to create a fifo. The fifo is necessary to have two-way communications between the two channels. A simple shell pipe would only communicate left process' standard output to right process' standard input.
server# mkfifo /tmp/fifo
server# nc -l -p 6667 < /tmp/fifo | nc -u 192.168.1.1 53 > /tmp/fifo
This will allow TCP traffic on server's port 6667 to be forwarded to UDP traffic on 192.168.1.1's port 53, and responses to come back.
Setup the UDP to TCP forward on your machine
Now, we need to do the opposite of what was done above on the local machine. You need priviledged access to bind the UDP port 53.
local# mkfifo /tmp/fifo
local# sudo nc -l -u -p 53 < /tmp/fifo | nc localhost 6667 > /tmp/fifo
This will allow UDP traffic on local machine's port 53 to be forwarded to TCP traffic on local machine's port 6667. Enjoy your local DNS server :)
As you've probably guessed, when a DNS query will be performed on the local machine, e.g. on local UDP port 53, it will be forwarded to local TCP port 6667, then to server's TCP port 6667, then to server's DNS server, UDP port 53 of 192.168.1.1. To enjoy DNS services on your local machine, put the following line as first nameserver in your /etc/resolv.conf:
nameserver 127.0.0.1
- 117
This example (I think John's answer points the the same thing at a different place), describes how to access another machine's UDP/DNS services over an TCP/SSH connection.
We will forward local UDP/53 traffic to TCP, then TCP traffic with the port-forwarding mechanism of SSH to the other machine, then TCP to UDP/53 on the other end.
Typically, you can do it with openvpn.
But here, we'll do it with simpler tools, only openssh and netcat.
At the end of that page, is another comment with a reference to 'socat',
The same UDP/DNS access is made with,
Server side:
socat tcp4-listen:5353,reuseaddr,fork UDP:nameserver:53
Client side:socat udp4-listen:53,reuseaddr,fork tcp:localhost:5353
Refer socat examples for more.
- 111
- 57,042
SSH (at least OpenSSH) has support for simple VPNs. Using the -w or Tunnel option in the ssh client, you can create a tun device at both ends, which can be used to forward any kind of IP traffic. (See also Tunnel in the manual page of ssh_config(5).) Note that this requires OpenSSH (and probably root privileges) at both ends.
- 501,077
Or you could simply use ssf (which was designed to handle this use case), with a simple command:
Client side:
#>./ssfc -U 53:192.168.1.1:53 server.foo.com
This command redirects local port 53 (dns) to 192.168.1.1 port 53, through a secure tunnel between localhost and server.foo.com.
You will need a ssf server (instead of - or next to - your ssh server):
#>./ssfs
By the way, both client and server side of ssf work on Windows / Linux / Mac. This is a userland application, so you don't need tun/tap or VPN.
To redirect port 53, you will need administrative privileges - regardless of the tool you're using.
For more info, details, use case, or download: https://securesocketfunneling.github.io/ssf/
- 439
I couldn't get nc to work for SNMP, because SNMP clients keep choosing a new source UDP port, and several can be active at once.
Instead, I've written a post describing how to do it with socat in this blog post, using SNMP as an example. Essentially, using two terminals, starting with an overview:
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.
- 19,080
- 397
on ssh server:
sudo ip tuntap add dev tun7 mode tun user SSHUSER
sudo ip addr add 192.168.7.1/30 dev tun7
sudo iptables -t nat -A PREROUTING -p udp -i eth0 --dport PUBLIC_PORT -j DNAT --to-destination 192.168.7.2:LOCAL_PORT
sudo iptables -t filter -A FORWARD -i eth0 -p udp -d 192.168.7.2 --dport LOCAL_PORT -j ACCEPT
sudo iptables -t filter -A FORWARD -i tun7 -o eth0 -j ACCEPT
sudo iptables -t nat -A POSTROUTING -o tun7 -j MASQUERADE
# set "PermitTunnel point-to-point" for user SSHUSER in /etc/ssh/sshd_config
sudo sshd -t && sudo systemctl restart sshd
replace eth0 with the interface connected to the internet
on ssh client running udp server:
sudo ip tuntap add dev tun8 mode tun user LOCALUSER
sudo ip addr add 192.168.7.2/30 dev tun8
ssh -v -w 8:7 SSHUSER@REMOTEHOST
you might also need sudo ip link set tun7 up on the remote host
and sudo ip link set tun8 up on the local host.
inspired by comment UDP traffic through SSH tunnel
- 41
For forwarding only one port (whether local -> remote or remote -> local), you can use https://github.com/mullvad/udp-over-tcp as a more safe alternative to socat. This translates UDP packets into a single TCP stream with packet length, so packet boundaries are preserved. Its usage is quite simple. For example, you can expose your UDP server apps through an SSH server by:
user@local_pc $ tcp2udp.exe --tcp-listen localhost:5000 --udp-forward localhost:3000
user@local_pc $ ssh -NR 4000:localhost:5000 user@ssh_server
user@ssh_server $ udp2tcp.exe --udp-listen 0.0.0.0:6000 --tcp-forward localhost:4000
For forwarding UDP connections for all destinations, you may want SOCKS5 server with UDP associate supported, which requires UDP connections between clients and servers. To make UDP-enabled SOCKS5 proxies available from behind TCP connections, I created this software: https://github.com/ge9/socks-with-udp-over-ssh . This detects UDP port assignment message for UDP associate and encodes UDP packets with length and destination port into a TCP stream.
Using gost (edited)
I found out gost (ver2 https://v2.gost.run/ or ver3 https://latest.gost.run/) can also be used for this purpose.
First, run gost in your SSH server.
user@ssh_server$ gost -L :7777
Since this 7777 is tcp port, you can use SSH port forwarding to expose this to the local machine:
user@local_pc$ ssh -NL 7777:localhost:7777
Then, you can "convert back" this 7777 to SOCKS5 proxy, using gost:
user@local_pc$ gost -L :7000 -F localhost:7777
Now, the :7000 on your local machine is a SOCKS5 server with UDP support through the SSH server.
If you want to forward only a single UDP port (like mullvad/udp-over-tcp does), use this instead as the last command:
user@local_pc$ gost -L udp://:7000/localhost:1234 -F localhost:7777
Now, your local machine's :7000 provides access to your UDP server app running on localhost:1234 of the SSH server.
- 126
To run socat commands automatically, you can use this script I made: https://gist.github.com/iTrooz/e410e753f0e8f89dfb413c1dfe939900
Definitively not perfect, but somewhat works
- 11
- 1
An experienced red teamer got this to work and proven by wireshark, but had to change the UDP packets into TCP packets and then forward them into the ssh tunnel and then convert them from TCP packets back into UDP packets to the listener UDP port of the application.
- 19
