MTU – MSS – Kernel Compile and Networking Gem

Unbelievably, this is still a problem across the internet!

If your connection through to the internet is less than 1500 (bytes) MTU, or if the destination you wish to connect to is less than 1500 MTU, and there is a “brain dead” ‘block all ICMP‘ at that far end or anywhere else along the route breaking the Path MTU Discovery, then you will suffer lost or failed connections…

Unfortunately, such is the paranoia for some systems about blocking everything with a firewall… :-(

If your host/server is behind a modem-router, your machine’s MTU can be 1500 to the modem-router whereas the restricting internet connection MTU may well be somewhat smaller…

Hence, from the Linux kernel compile config:

CONFIG_NETFILTER_XT_TARGET_TCPMSS:

This option adds a `TCPMSS’ target, which allows you to alter the MSS value of TCP SYN packets, to control the maximum size for that connection (usually limiting it to your outgoing interface’s MTU minus 40).

This is used to overcome criminally braindead ISPs or servers which block ICMP Fragmentation Needed packets. The symptoms of this problem are that everything works fine from your Linux firewall/router, but machines behind it can never exchange large packets:

  1. Web browsers connect, then hang with no data received.
  2. Small mail works fine, but large emails hang.
  3. ssh works fine, but scp hangs after initial handshaking.

Workaround:

Activate this option and add a rule to your firewall configuration like:

iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

To compile it as a module, choose M here. If unsure, say N.

Unfortunately, although that is a good workaround that usually works, it is not a “fix all” panacea… For ICMP blocked links over tunnels, or multiply encapsulated data packets, or for just simply bad equipment, you may need to instead explicitly set the MSS with:

iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss nnnn

where “nnnn” is for example 1452 for PPPoE, or 1412 for PPP (typical for ADSL modems), or it can be made to be smaller if you are still having problems for an even more constrained link over a tunnel or whatever. (To avoid packet fragmentation, the MSS should be at least 40 bytes smaller than the MTU to allow for the TCP/IP headers overhead. The MSS can be safely set smaller than actually needed, the only penalty is the overhead of needing respectively more data packets for large chunks of data.)

Although the TCP MSS clamping solves the MTU issue for TCP, other protocols such as ICMP itself and UDP may still be adversely affected by an overzealous firewall blocking ICMP.

In summary, when there is no ICMP, then the workaround is to force:

  • MTU=1500 and MSS=1460 for ethernet and PPPoA;
  • MTU=1492 and MSS=1452 for PPPoE;
  • MTU=1452 and MSS=1412 for PPP (using such as dial-up or ADSL)
  • MTU=x and MSS=x-40 for tunnels for whatever smallest MTU along any part of the link.

Note that some PPP daemons may already be configured to force those settings for their connection as appropriate.

Depending on your ISP/connection, for an MTU consistent with plain ethernet PPPoE may be able to be set for an MTU of 1500 bytes rather than 1492 by using a 1508 byte ethernet frame payload, sometimes called ‘baby jumbo frames‘. (The increased overhead of extra MPLS and ethernet headers means that the support of 1600 byte frames is a mandatory requirement in Carrier Ethernet Networks.)

There is a good explanation on: “How to Setup a Linux Firewall with PPPoE/NAT/iptables“. Wikipedia shows how data is encapsulated in the 1518 bytes maximum of an Ethernet frame.

Good luck!

Leave a Reply