/dev/posts/

IP over UDP tunnel with socat

Published:

Updated:

A simple way to create IP over UDP tunnels using socat.

This is the protocol stack we are going to implement:

[ IP  ]
[ UDP ]
[ IP  ]

Warning: no protection!

This does not provide any protection (encryption, authentication)!

In order to create a tunnel, we must create a TUN device interface. A TUN device is a network device managed by a userspace program:

We would like to have a simple program which manages such a TUN device by encapsulating them over a UDP socket.

Using socat

It turns out socat can do this already!

On the first host:

sudo socat UDP:192.0.2.2:9000,bind=192.0.2.1:9000 \
  TUN:10.0.1.1/24,tun-name=tundudp,iff-no-pi,tun-type=tun,su=$USER,iff-up

On the second one:

sudo socat UDP:192.0.2.1:9000,bind=192.0.2.2:9000 \
  TUN:10.0.1.2/24,tun-name=tundudp,iff-no-pi,tun-type=tun,su=$USER,iff-up

Explanations:

Now we can ping over the tunnel:

host1:~$ ping 10.0.1.2
PING 10.0.1.2 (10.0.1.2) 56(84) bytes of data.
64 bytes from 10.0.1.2: icmp_seq=1 ttl=64 time=39.3 ms
64 bytes from 10.0.1.2: icmp_seq=2 ttl=64 time=40.1 ms

host1:~$ ip route get 10.0.1.2
10.0.1.2 dev tunudp  src 10.0.1.1 
    cache

You can add IPv6 addresses to the tunnel and it works as expected: both IPv4 and IPv6 packets are sent over the same UDP socket and the version field is used to distinguish them.

Using ip fou

The other solution is to use ip fou (for foo over UDP):

modprobe fou
ip fou add port 9000 ipproto 4
ip link add name tunudp type ipip \
       remote 192.168.2.2 local 192.168.2.1 ttl 225 \
       encap fou \
       encap-sport auto encap-dport 9000

We can expect better performance as its handled completely in the kernel side. The downside is that you have to create two different tunnels (one for encapsulating IPv4 and the other for IPv6).