当前位置: > Linux服务器 > VPN >

linux下pptp搭建的vpn代理上网很慢 终于解决

时间:2014-05-14 17:39来源:linux.it.net.cn 作者:it
问题 linux平台用pptp搭建了vpn服务器,拨入后访问内网ftp,下载文件极慢;用其作网关上网,除了baidu外,大部分网站访问速度极慢,几乎无法访问。

解决 在pptp所在的linux服务的iptables的*filter表中加入

-I FORWARD -p tcp --syn -i ppp+ -j TCPMSS --set-mss 1356

或者在命令提示符运行

/sbin/iptables -I FORWARD -p tcp --syn -i ppp+ -j TCPMSS --set-mss 1356

原因分析

=====在断开vpn链接的情况下:

在windowsXP下用ping -f -l XXXXXX 192.168.0.1一步一步测试(XXXXXXX为MTU大小,可以从1500开始,逐渐减小,知道可以ping通)

我们可以得到可以ping通的MTU最大为1426;

=====在连接vpn的前提下

在windowsXP下用ping -f -l XXXXXX 192.168.0.1一步一步测试(XXXXXXX为MTU大小,可以从1500开始,逐渐减小,知道可以ping通)

我们可以得到可以ping通的MTU最大为1372;

超过这个数则不能通,

====拨通vpn,在服务器上用netstat –i查看接口,得到
Iface MTU Met RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
eth0 1500 0 102528561 0 0 0 194391413 0 0 0 BRU
eth1 1500 0 519820535 954 11553 924 208798037 0 0 0 BRU
lo 16436 0 151062 0 0 0 151062 0 0 0 LRU
ppp0 1396 0 19 0 0 0 8 0 0 0 OPRU

可知ppp的最大mtu为1396,当然,对应的mss应为(mtu-20字节的IP头部+20字节的TCP 头部=)1356

【小知识1】计算机网络中的MSS:
MSS: Maximum Segment Size 最大分段大小
MSS最大传输大小的缩写,是TCP协议里面的一个概念。
MSS就是TCP数据包每次能够传输的最大数据分段。为了达到最佳的传输效能,TCP协议在建立连接的时候通常要协商双方的MSS值,这个值TCP协议在实现的时候往往用MTU值代替(需要减去IP数据包包头的大小20Bytes和TCP数据段的包头20Bytes)所以往往MSS为1460。通讯双方会根据双方提供的MSS值得最小值确定为这次连接的最大MSS值。

【小知识2】mtu是网络传输最大报文包。
mss是网络传输数据最大值。
mss加包头数据就等于mtu.
简单说拿TCP包做例子。
报文传输1400字节的数据的话,那么mss就是1400,再加上20字节IP包头,20字节tcp包头,那么mtu就是1400+20+20.
当然传输的时候其他的协议还要加些包头在前面,总之mtu就是总的最后发出去的报文大小。mss就是你需要发出去的数据大小。

【小知识3】http://www.cnpaf.net/Class/TCPANDIP/200511/9898.html

假设PC建立了到SERVER的HTTP连接,PC希望从SERVER下载一个大的网页。SERVER接收到PC的请求后开始发送大网页文件,其IP的DF位置1,不允许分片,IP报文长度为1500字节。到达VPN网关2的外网口(以太)后,VPN网关2发现其长度超过了1500个字节,于是将其丢弃,并给SERVER发回一个目的地址不可达的ICMP信息,同时指出“MTU of next hop: 1500”。PC接收到该消息后,又按照1500字节对外发送,又被丢弃,于是就形成了循环,无法通讯。
根据上述的分析,很容易得到如下解决方式,在VPN网关2的出接口设置MTU为1500-4-20=1476,这样VPN网关2返回ICMP不可达消息时将给出”MTU of next hop: 1476”。SERVER将以1476作为自己的最大MTU对外发送,到达VPN网关1,封装GRE和外层IP头后就不会超过1500而顺利发到对端。

-I FORWARD -p tcp --syn -i ppp+ -j TCPMSS --set-mss 1356

因为mss是在TCP连接建立开始时,通过带有syn标志的IP数据包进行传输的,所以我们在iptables里面规定,在转发数据时,只要发现产生于ppt*的带有 syn标志数据包时,将其mss设定为1356字节,这样就与ppp0接口的路径MTU向匹配了,数据自然就可以畅通无阻啦。

(注,vpn拨入一个,则建立一个ppt*的虚拟设备,这个可以再linux上用ifcpnfig看到,第一个为ppp1,第二个为ppp2……)

参考:

1、http://fanqiang.chinaunix.net/app/other/2005-09-13/3655.shtml

2、http://technet.microsoft.com/zh-cn/library/cc768084(en-us).aspx

3、这是一个比较复杂的问题。首先,发现问题的过程是这样的:使用一台WinXP的电脑(简称主机A)连接公司的VPN成功后,访问内网的一个基于 B/S的CRM系统(简称主机B)时,发现首页可以显示(页面比较简单,包含的数据量较小),输入账号密码登陆后,发现只能显示页面顶部的一点点内容,而下面大部分内容无法显示。而换一台Win2000的电脑登陆,内容就可以完全显示出来。登陆到Linux VPN主机上,利用tcpdump对数据传输过程进行抓包分析,发现:每当B向A传输大于1396字节的数据时,VPN主机就会反馈B如下信息
注意:
10.87.0.200:VPN主机的内网网卡的IP地址
10.87.200.1:主机A的IP地址
10.87.200.6:主机B通过VPN获取的IP地址
21:54:21.953848 IP 10.87.0.200 > 10.100.0.100: icmp 556: 10.100.0.203 unreachable -
need to frag (mtu 1396)
可以看到VPN主机向提供web服务的主机B返回了一个ICMP不可达的差错报文。其含义是VPN主机收到了一个需要分片才能通过的数据包,而这个数据包在其IP头部又设置了不能分片(DF)的标志。所以该数据包不能通过VPN主机。
根据TCP/IP协议,在建立TCP连接时,传输双方都要指明自己的mss(最大报文长度)大小,然后选取双方之中最小的那个mss,以避免在随后的数据传送过程中出现数据包分片传输的情况。通过抓包分析,主机B的mss为1460字节,主机A的mss为1357字节。两者取小所以双方协商的结果确定 mss为1357字节,也就是说以后进行TCP数据传输时,数据包的最大传输单元MTU不能超过1397(mss+20字节的IP头部+20字节的TCP 头部),同时在IP头部设置了不能分片(DF)的标志。
然后在VPN主机上执行netstat –i,观察各个网络接口的路径MTU值为多少。观察结果如下:
Iface MTU
eth0 1500 //外网网卡接口
eth1 1500 //内网网卡接口
lo 16436 //本机回环接口
ppp0 1396 //WinXP VPN接入通道接口
可以看到ppp0接口的路径MTU为1396字节,也就是说如果一个数据包想要通过这个接口的话,一定不能大于1396字节,如果大于这个值,会出现两种结果:
1、如果这个数据包的IP头部没有设置不能分片(DF)的标志,那么VPN主机就把这个数据包分片,使其数据包大小小于1396字节,然后允许其通过。
2、反之,如果这个数据包的IP头部设置不能分片(DF)的标志,那么VPN主机就会返回一个ICMP不可达的差错报文。同时丢弃这个数据包。
问题就出在这里,主机A和主机B协商的mss为1357字节,也就是说其TCP数据包的MTU为1397,而ppp0允许的路径MTU却为1396,主机 A的MTU居然大于ppp0的路径MTU!当主机B向主机A发送了一个1397字节的数据包时,自然不能通过ppp0接口了。回到发现问题的那个情况,首页之所以能够显示成功,是因为首页包含的数据较小,传输时只需要一个没有超过1396字节的IP数据包就可以了,所以能够显示出来,而登陆成功后的页面包含的数据较大,需要分为多个IP数据包进行传输。这里可以假设一下,开头的一个IP数据包因为没有超过1396字节因而通过,而随后的IP数据包因为其大小为1397字节,超过了路径MTU,所以不予通过。反映到页面,就是登陆页面下面的大部分内容无法显示了。
我们再来看看用安装了Win2000主机C连接VPN又是什么状况呢?通过抓包发现,主机C提出的mss为1360(可以推算出其MTU为1400),而执行netstat –i,发现此时的ppp0的MTU为1496,路径MTU大于主机C的MTU,这个结果是正常的。
大家一定会问,为何主机B提出的MTU小于路径MTU,这个问题只能问问微软了,我查了一些英文资料,说这是WinXP本身系统的一个问题。
知道了问题的原理,那让我们来看看如何进行解决吧。解决方法很简单,就是借助iptalbes,设定主机B进行协商时提出的mss为1356。即在iptables里面加入一条规则:
iptables -A FORWARD -p tcp --syn -s 10.87.200.0/31 -j TCPMSS --set-mss 1356

因为mss是在TCP连接建立开始时,通过带有syn标志的IP数据包进行传输的,所以我们在iptables里面规定,在转发数据时,只要发现带有 syn标志并且源地址为主机B的IP数据包时,将其mss设定为1356字节,这样就与ppp0接口的路径MTU向匹配了,数据自然就可以畅通无阻啦。

因为mss是在TCP连接建立开始时,通过带有syn标志的IP数据包进行传输的,所以我们在iptables里面规定,在转发数据时,只要发现带有 syn标志并且源地址为主机B的IP数据包时,将其mss设定为1356字节,这样就与ppp0接口的路径MTU向匹配了,数据自然就可以畅通无阻啦。
(责任编辑:IT)
------分隔线----------------------------