OpenVPN working with TCP not with UDP

Solution 1:

These particular symptoms (with a VPN) are fairly common symptoms indicating an issue with your path MTU.

MTU basics

The path MTU (Maximum transmission unit) is the largest packet that can traverse between two devices on the internet (or any other network). Each link along the path has its own MTU, which may or may not match the others. The overall path MTU is the lowest MTU along the entire path.

If your computer attempts to send a packet larger than than the path MTU, the data packet is dropped at the hop which it exceeds, and the data will never arrive. In well-behaved networks, your computer should receive an error response and know to auto-adjust the MTU down and/or fragment subsequent packets. On badly-behaved networks, it might just be dropped silently.

Path MTU (auto)discovery is the mechanism used to automatically detect the MTU between you and the VPN server, however it is more robust with TCP than with UDP on badly-behaved networks, because TCP mandates explicit feedback that can tell you which packets don't arrive.


The reason it acts the way it does with VPN links is because the VPN encapsulation headers reduce the MTU of your tunnelled connection, and because UDP provides no feedback on dropped packets.

If your real PMTU is, for example, 1400 bytes, sending a 1400-byte packet through a VPN might take 1432 bytes. Over a TCP connection, if you try to send a 1432 byte packet, TCP can tell it doesn't arrive and fragments it and sends it again as a 1400 byte packet and a second 32 byte packet (that's a gross simplification nonetheless). With UDP it just gets dropped silently. However, in both cases, sending any packet smaller than 1400 bytes will succeed.

This is why SSH and telnet works whereas web browsing doesn't. Your VPN has reduced your MTU below your default, but your OS hasn't realized either because error messages are not being returned properly or PMTU autodiscovery isn't working. But because SSH and telnet and ping all use very small packets (typically <100 bytes), if your MTU has been reduced from 1400 to 1368 (1400 - 32), it doesn't matter, as they are still much smaller than the limit. SSH and telnet typically send between one byte and one line at a time, plus packet headers. Ping packets are typically up to 64-bytes plus packet headers, again much smaller than any sane MTU (1400+)

Web browsing initially connects because the DNS, TCP SYN/ACK packets and HTTP requests are both usually much smaller than 1400 bytes, but as soon as the website tries to send the actual web page, it'll use full-size packets which then get silently discarded along the way.


Solving the problem

There's the easy (cheaty) way, and the other way which involves figuring out what the problem actually is.

The cheaty way being to set the MTU much lower manually - for example to 1000, so everything will fit inside even the reduced MTU of the VPN. This in itself is a good test to see if the MTU is the problem.

The better way would be to figure out where the problem lies, and fix it. MTU autodiscovery problems can arise because of a crappy server or ISP, which you can do nothing about, or local firewall/configuration issues, which you can fix. It may be your OpenVPN routing and firewall rules aren't allowing ICMP error messages to get back to your machine.

An intermediate method would be to figure out the true maximum MTU and set that manually - you can start with something small like 1000 bytes and work upwards to find the highest value that works. Basically, connect your VPN using UDP, and then ping something through the VPN with the command ping -f <server address> -l <packet size> and increase packet size upwards until it stops working - either with a timeout or an error.