ubunut pppoe拨号部分网站无法访问的原因及解决办法

ubuntu 9.10(karmic koala)AMD64系统下,设置好ADSL PPPoE拨号后,出现一种情况,部分网站可以正常访问,而有些网站则没有响应,无法正常访问。比如google.cn是正常的,而sina.com.cn则无法访问。

  出现这个问题的原因是PPPoE默认设置的MTU1492字节有问题。MTU是链路层的一个特性,叫做最大传输单元(Maximum Transfer Unit)。如果网络层(IP层)要发送的数据比链路层的MTU还要大,那么IP层必须对数据进行分片(fragmentation)。PPPoE的MTU是一种逻辑MTU,因为PPPoE并没有一个实体的链路层存在。通常情况下以太网(ethernet)的MTU为1500字节,所以PPPoE设置其MTU为1492字节,加上PPPoE 8个字节的头部,刚好达到以太网的MTU,从而可以提高网络的利用率。但实际上很多ADSL接入方式的MTU并不是1500字节,比如我的ADSL链路使用traceroute实测的路径MTU(PMTU)是1492字节。那么这种情况下,PPPoE设置其MTU为1492就存在问题了,加上8个字节的PPPoE头部后,就超过了以太网的MTU大小。

那为什么部分网站可以访问,而部分网站不能访问呢?回答这个问题前先介绍一个概念最大报文段长度MSS(Maximum Segment Size),MSS表示传输控制层(TCP)传往另一端的最大数据块长度。大多数系统为了提高链路层的利用率,减少TCP分段,通常将MSS设置为MTU减去40字节,因为这40字节刚好是20字节到TCP头和20字节的IP头之和。浏览网站到时候,首先要和网站建立TCP连接,在握手阶段,两端的TCP层会向对方通告自己能够接受的MSS。

  可以用tcpdump来监测整个TCP交互的过程。当请求sina.com.cn的时候,本地系统的MSS期望值是1452字节,加上20个字节的TCP头,20个字节的IP头,8个字节的PPPoE头,正好是1500字节。而sina.com.cn的MSS是1460,这也是以太网(RFC 894)可以接受的最大的MSS。这样网站接受了客户系统通告的MSS大小1452,然后发送MSS大小的数据块(包括可能的选项)给客户端,加上总共40字节的TCP和IP头部后,到达PPPoE服务器到数据大小是1492字节,再加上8个字节的PPPoE头后达到了1500字节,超过了以太网的MTU1492,如果PPPoE服务器无法处理这种情况,数据包就会被丢弃,也就无法看到网站的回应。而浏览google.cn的时候,服务器选择了较小的MSS(我监测到的是1430)来发送数据包,从而服务器的响应会顺利返回到浏览器。一般来说我们浏览网站的时候,系统发送给网站的请求数据量是很小的,基本都可以顺利通过链路到达服务器。

  既然物理链路的路径MTU(PMTU)为1492,那么设置PPPoE的MTU为1484(1492-8)或更小就可以解决问题了。当然最好实测一下你自己的路径MTU。
  设置方法有两个。
  一个是使用ifconfig命令,sudo ifconfig ppp0 mtu 1484,但是这样设置系统重新启动后会回复到原来的设置,所以一劳永逸的办法是修改/etc/ppp/peers/dsl-provider文件,在里面增加一行mtu 1484就可以了。