ping fails with MTU >= 298

Solution 1:

The fact you have set MTU on the hosts you control means nothing as the packets between them — in theory — might fly through any media with any MTU.

To deal with this issue (besides the IP fragmentation mechanism), the so-called "Path MTU discovery" mechanism exists.

Note that it relies on the ICMP protocol to work properly. Beside other things, it means that if you have tight firewall settings, you must have something like

iptables -t nat -A $CHAIN -m state --state RELATED -j ACCEPT

in your rules for your INPUT chain (and in the FORWARD chain if your firewall also does SNAT for its clients).

The "related" state means that when an ICMP packet of the type 3, code 4 (destination unreachable / fragmentation required) is received, the conntrack subsystem decides which connection it is related to and then passes it further down the netfilter stack. The state of such packet is "RELATED" as known to iptables¹ so if you have passing of such packets denied — as often happens when people disable everything wholesale and then punch the minimal holes — P-MTU discovery won't work properly.

Note also that even if you "unbreak" proper support for P-MTU on your sides, it might still be broken somewhere in between.

In order to deal with it, there exists at least two knobs:

  • Clamping MSS to MTU in the IP stack.
  • Limiting these things on the OpenVPN level by its tun-mtu, tun-mtu-extra and mssfix knobs.

Note that these settings does affect performance, so use as the last resort.


¹ Because while not a part of an IP exchange, it's clearly related to it.

Solution 2:

I had a very similar issue at home, with SSH connections hanging at (as I recall) the exact same place in the connection setup. For me, tweaking the local MTU setting helped reduce the problem somewhat, but to make the problem go away, I had to turn on TCP MTU probing. After doing so I didn't have any similar problems. Only allowing RELATED packets through iptables, as discussed in kostix's answer, didn't help.

For Linux, try

sudo sysctl net.ipv4.tcp_mtu_probing=1

The possible values are:

  • 0 = disabled
  • 1 = disabled by default, enabled when an ICMP black hole detected
  • 2 = always enabled, use initial MSS of tcp_base_mss

Other OSes will be similar and different.

Note that this needs to be done on the client system, not the firewall (so not on the pfSense box) -- unless of course you are initiating your SSH connections from the firewall.

Solution 3:

I had the exact same issue: pinging with size 297 worked, 298 did not.

Our client was configured to not use compression:

comp-lzo no

Changing it to use compression fixed the issue:

comp-lzo yes

I don't understand why this works, but it does.