I once used Linux to set up an ad-hoc network and connected with it using an Android phone with static IP. I used iptables to do NAT. The Android phone can get access to the internal network. But when I opened up the web browser on it and tried to log on to Google, nothing appeared. Later I found out the problem. This is caused by the MSS setting. The Android phone uses a default value 1460 while the actual MTU of interface eth0 on my Linux, which has actual Internet connection, is 576. Therefore, when I start up a TCP connection on my phone, the MSS value contained in the SYN message would be 1460. Usually, the server gives a similar value. So they are all higher than the capacity of eth0. Evil comes here.

The problem can be described as:

  1. DNS looks-up gives correct result
  2. Can ping domain names
  3. Can access small files on the Internet, but fails on larger ones
  4. Usually, when open up a web page, the browser just connects and wait for a very long time, doing nothing, then disconnect

The solution to this problem is very easy (if you know where to find it, BTW, if you’re viewing this article, you already find it). Just add the following rule in your iptables

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

If you’re not viewing this article, please refer to man iptables, in which a more detailed syndrome is described :)

Since the browser on my Linux uses eth0 directly, it will know the exact MTU value of it. So problems won’t happen. But the browser on my phone won’t see that since it connects to the wireless interface. So trouble comes.

In the end, I want to point out that increase the MTU of eth0 manually by

# ifconfig eth0 mtu 1500

is another solution, though I don’t recommend solving the problem in this way.

Next task would be to find out where the default MSS for Android is set. I’ll update this blog once I succeed. If you know it, please leave a comment below, thanks :)