WireGuard and OpenVPN on the same port

2019-04-12 16:42

Accessing the internet through an always-on VPN full tunnel could be considered standard user behaviour these days. Things start to get annoying when the network (provider) limits VPN usage. For me, the most prominent case was an Eduroam wifi at a german university which grants only the absolute minimum of network access to its users, as required by the Eduroam specification. Here's the full list of mandatory (as in RFC MUST) unblocked ports (see page 32):

Service Protocol/Port Direction
Standard IPSec VPN IP protocol 50 (ESP)
IP protocol 51 (AH)
UDP port 500 (IKE)
incoming and outgoing
incoming and outgoing
outgoing
OpenVPN 2.0 UDP port 1194 incoming and outgoing
IPv6 Tunnel broker service IP protocol 41 incoming and outgoing
IPSec NAT-Traversal UDP/4500 incoming and outgoing
Cisco IPSec VPN over TCP TCP/10000 outgoing
PPTP VPN IP protocol 47 (GRE)
TCP port 1723
incoming and outgoing
outgoing
SSH TCP port 22 outgoing
HTTP TCP port 80
TCP port 443
TCP port 3128
TCP port 8080
outgoing
outgoing
outgoing
outgoing
Mail sending TCP port 465
TCP port 58
outgoing
outgoing
Mail reception TCP port 143
TCP port 993
TCP port 110
TCP port 995
outgoing
outgoing
outgoing
outgoing
FTP (passive) TCP port 21 outgoing

My mobile phone didn't have any problems with the universitys setup since it runs an OpenVPN full tunnel which just works. My laptop, however, connects to the outside world via a WireGuard full tunnel. WireGuard uses UDP and its default port 51820 isn't listed in the Eduroam specification. Changing the port to one of 500/udp, 1194/udp, 4500/udp would work and did work for 500/udp and 4500/udp. Port 1194/udp was already taken by OpenVPN.

When I contacted the university network administrators about it, they motivated their choice of only complying with the minimum list of available ports by encouraging their clients of using VPN tunnels and reconfigured their firewall to allow 52810/udp. They did not comment on my question on why they did not follow recommendations on page 32f:

"Adherence to the following specifications is RECOMMENDED: [...] network access to roaming visitors SHOULD not be port-restricted at all (i.e. in addition to the minimum list of open ports from above, allow all outgoing communication). Where this is not possible, the number of filtered protocols SHOULD be kept as low as possible."

This lead me to trying to be more stealthy and use 1194/udp on my laptop with WireGuard, hoping that the default OpenVPN port will be available on almost all networks I am going to connect to in the future. This means I need iptables on the server side to intercept incoming WireGuard packets and redirect them to the correct port (WireGuard de-facto-default 51820/udp). The page on the WireGuard protocol gives pretty clear instructions on how to classify UDP payload as WireGuard packet. The handshake initiation packet starts with 0x01000000, the response with 0x02000000 and the data packets with 0x04000000. For legacy IP, the UDP payload starts at byte 28 and for IPv6 the payload starts at byte 48. This technique is based on the assumption that no regular OpenVPN packet starts with one of these three values, otherwise it will be sent to the WireGuard interface in error.

I'm using iptables-persistent here to insert PREROUTING rules to the nat table.

$ cat /etc/iptables/rules.v4
[...]
*nat
[...]
-A PREROUTING -p udp --dport 1194 -m u32 --u32 "28=0x04000000" -m comment --comment "wireguard data packet" -j REDIRECT --to-ports 51820
-A PREROUTING -p udp --dport 1194 -m u32 --u32 "28=0x01000000" -m comment --comment "wireguard handshake initiation" -j REDIRECT --to-ports 51820
-A PREROUTING -p udp --dport 1194 -m u32 --u32 "28=0x02000000" -m comment --comment "wireguard handshake response" -j REDIRECT --to-ports 51820
[...]
$ cat /etc/iptables/rules.v6
[...]
*nat
[...]
-A PREROUTING -p udp --dport 1194 -m u32 --u32 "48=0x04000000" -m comment --comment "wireguard data packet" -j REDIRECT --to-ports 51820
-A PREROUTING -p udp --dport 1194 -m u32 --u32 "48=0x01000000" -m comment --comment "wireguard handshake initiation" -j REDIRECT --to-ports 51820
-A PREROUTING -p udp --dport 1194 -m u32 --u32 "48=0x02000000" -m comment --comment "wireguard handshake response" -j REDIRECT --to-ports 51820
[...]

Of course, this technique is not really providing stealthiness. If you are looking for disguising OpenVPN traffic as an HTTPS connection, take a look at nginx stealth VPN.