A simple way to create IP over UDP tunnels using
This is the protocol stack we're going to implement:
[ IP ] [ UDP ] [ IP ]
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:
when the kernel sends an IP packet to this device, it is sent to the userspace program which can do anything with it (like sending it in a tunnel);
conversely, the userpace program can send packets to the kernel through this network device.
We'd like to have a simple program which manages such a TUN device by encapsulating them over a UDP socket.
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
UDPtype creates a
connect()-ed UDP socket which means only the packets coming from this specific remote UDP endpoint will be accepted;
IFF_NO_PIflag which disables some encapsulation;
tun-type=tunasks a IP-based devices (as opposed for
tun-type=tapfor an Ethernet-based device which would implement an Ethernet over UDP tunnel);
iff-upsets the interface up;
su=$USERchanges the user of the process (instead of using
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.
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).