Wireshark应用实战

王晓龙
王晓龙   编辑于 2020-02-17 09:58
阅读量: 1669

        在《计算机网络》这本书中,网络层协议介绍的最多,像IP、ARP、ICMP、RIP、OSPF、BGP等等都是网络层协议。但要说复杂程度,运输层的TCP协议敢认第二,就没有协议敢认第一了。在TCP/IP体系结构中,TCP协议和IP协议绝对是核心,但是IP协议还需要与其他网络层协议配套使用才能发挥作用,但TCP协议却仅凭一己之力就能扛起大半个运输层,其重要程度可想而知,其复杂程度也是可想而知。今天就来跟大家分享一期专题,让我们通过Wireshark抓包来对TCP协议进行一次最亲密的接触。

1.缘起

        我们都知道,TCP协议是面向字节流的,并且TCP报文段首部中并没有报文段长度或数据部分长度这样的字段,这就说明TCP报文段的长度并不重要,只要能在接收方那里还原出一模一样的字节流就可以了。在我们第七版课本的211页的最后一行,提到“根据对方给出的窗口值和当前网络拥塞的程度来决定一个报文段应包含多少个字节”,这不太扯了么?这明明是用来确定发送窗口的大小的,怎么成了决定一个报文段应包含多少个字节了呢?

        当然,学到后面我们就会知道,有一个东西叫做MSS,一个报文段到底有多大,是由MSS决定的。而且,为了提高网络利用率,MSS是越大越好,但为了不至于使数据在IP层传输时分片(至于为什么要分片以及如何分片,记不起来的同学赶紧打开课本复习一下,没记错的话应该是在课本的129页;而对于分片会有哪些影响,这里也不深入讨论),MSS也不能大得离谱。

        接下来的课本中提到了MSS和接收窗口值没有关系,作者前后矛盾的描述以及大开的脑洞实在是令人佩服:

        那么MSS到底与什么有关?又是如何确定的呢?课本220页原文如下:由于IP 数据报所经历的路径是动态变化的,因此在这条路径上确定的不需要分片的MSS,如果改走另一条路径就可能需要进行分片。因此最佳的MSS是很难确定的。在连接建立的过程中,双方都把自己能够支持的MSS写入这一字段,以后就按照这个数值传送数据,两个传送方向可以有不同的MSS值。而在页面的底部,有对最后一句话的注释:①注: RFC 879指出,流行的一种说法是:在TCP连接建立阶段“双方协商MSS值",但这是错误的,因为这里并不存在任何的协商,而只是一方把MSS值设定好以后通知另一方而已。

        这种让你渴望又感到烦恼,曾让你遍体鳞伤的描述,真的是让人迷茫。从作者的描述来看,第一句和第二句是想说,MSS跟路径有关;而最后一句及其注释却说,MSS是在连接建立的过程中,一方设定好以后通知另一方,并且可以在发送和接收这两个方向上有不同的MSS值。这种描述让人摸不着头脑,如何拨开谜雾找到被层层掩盖的真相?我们抓包来试一下吧。如果不可以,那就试两下。

2.抓包

        接下来就该我们大名鼎鼎的Wireshark登场了。启动Wireshark,捕获过滤器不做任何设置,直接双击使用的网卡,一场比特狩猎就开始了。

        如何才能捕获到我们想要的数据呢?由于这次是为了探究MSS,必然要进行大块数据的传输,所以就一边通过浏览器下载一边抓包。

        上图红框中的数据包是本次捕获到的建立TCP连接的三次握手。如何判断一定是这三个包呢?如果不记得了,就赶紧拿出课本来复习。这里有一个小提示,我们可以点击第二个包,这个时候第一个包在序号的前面会有一个小对勾,就表明第二个包是对第一个包的确认。同样,点击第三个包,第二个包的序号前面也会有小对勾,表明第三个包是对第二个包的确认。

        其实我们从摘要信息里也能看出来,第一个包给出的MSS是1460(1500-20字节的TCP首部-20字节的IP首部),这个是TCP连接的客户(也就是我的电脑的应用进程)发出的;第二个包给出的MSS是1440(为什么是这个数字?我们后边会给大家讲到),这个是TCP连接的服务器发回的确认报文段。

        这里插播一下其他内容,可能有些细心的同学已经发现了,窗口值Win = 66048。我们知道,在TCP报文段首部有一个窗口字段,长度为16位,其能表示的最大值是65535,那这个66048是怎么来的?

        认真看书的同学一定知道,TCP报文段首部还有一个选项字段,其中就有一个选项叫窗口扩大。那这个选项在哪里呢?我们把第一个红框中的详情展开:

        我们看到其中有一个选项叫Window scale,就是窗口扩大,后面的multiply by 256,就是窗口值扩大256倍,要表示66048已经是绰绰有余。如果我们细心观察的话,会发现TCP连接的服务器也设置了窗口扩大,其扩大倍数是1024。好了我们点到为止,继续说MSS。

        对于1440的数值我百思不得其解,于是打开了家里的路由器配置,当我看到数据包MTU设置为1480时才恍然大悟:

        因为我这里的路由器MTU设置为1480,那么服务器想传输数据给我又不想在IP层分片,就只能设置MSS为1480-20字节TCP首部-20字节IP首部=1440字节。那么问题又来了,服务器是怎么知道我家的路由器是怎么设置的从而非常聪明地把它自己的MSS进行了适当的更改?

3.解惑

        为了弄明白这个问题,我们抓包肯定是不行的,只能百度。好在百度也很给力。

        在TCP连接之初,交互双方通过协商MSS值可以巧妙解决端系统分片的问题,但是在复杂的实际网络环境下,影响到IP报文分片的并不仅仅是发送方和接收方,还有路由器、防火墙等中间设备。

        中间路径上的MTU问题,端系统并不知道,因此需要一个告知的机制,这个机制就是路径MTU发现(PMTUD: Path MTU Discovery )。

        在IP数据报中,一旦将DF位设置为1,将不允许中间设备对该报文进行分片,那么在遇到IP报文长度超过中间设备转发接口的MTU值时,该IP报文将会被中间设备丢弃。在丢弃之后,中间设备会向发送方发送ICMP差错报文(类型 3,代码 4)。

                                       (此图来源于网络)

        在ICMP差错报文中有一个字段是告知下一跳的MTU值。PMTUD正是利用ICMP差错报文的这一特性来实现的。发送方接收到该差错报文后,会根据该报文给出的下一跳的MTU值计算适合传输的最大报文段长度,从而在后续的发送报文过程中,避免在中间路径被分片的情况产生。

        另外,很多中间设备的接口支持adjust tcp mss功能,这个功能主要是通过由中间设备修改经过其转发的TCP SYN报文中的MSS值,让中间设备参与进TCP 三次握手时SYN报文的MSS协商来避免分片。此功能一旦开启,将对该接口的收发双向有效。

        至此,关于MSS是如何得到的,就有了一个清晰的认识:这个值确实与路径有关,这个值也确实需要双方协商,取其中的最小值。而且,如果MTU最小值在客户方路由器WAN口的话,由于发送和接收都必然会从此接口经过,则两个方向上的MSS值必然一致。

        可以抓包验证:

        再来一个上传数据的:

        可以看到,收发双向的MSS值都是1440。而如果我把路由器WAN口的MTU设置成1492,那么MSS就变成1452了:

 

        这里多说一句,为什么家中的路由器会把MTU设置为1480呢?设置为1500可以吗?

        我们知道,家中的路由器大多都是通过ADSL拨号上网(不管是光猫还是ADSL猫),而拨号这个工作,很多情况下都是无线路由器在做,猫只负责提供转换(光猫是光电转换,ADSL猫是数模转换)。拨号时需要使用PPP协议中的身份验证等功能,可是猫和无线路由之间是通过以太网连接的,所以要使用PPPoE(PPP over Ethernet ,把PPP协议封装在以太网协议中)协议,于是会有额外的8字节的开销( PPP数据帧作为以太网数据帧的数据部分。PPP帧首部和尾部,一共8字节)。有了这8字节的开销,我们所能设置的MTU的最大值就只能是1492了:

        至于为什么默认是1480,可能有其他方面的考虑,比如VPN和隧道等也会增加额外的开销。如果我们改变入网方式,比如改成动态IP,MTU就变成1500了:

4.one more thing

        我们在抓包的过程中,发现在摘要信息中有一个提示:TCP segment of a reassembled PDU。之所以出现这个提示,是因为应用层的数据块太大,而我们的TCP报文段长度最大只有MSS,所以就只能把应用层的数据块分开来发送了。

        那么问题来了,作为接收方,你觉得Wireshark是根据什么来判断,当前的TCP segment是TCP segment of a reassembled PDU?感兴趣的同学可以把你们的答案提交给我。

收藏 转发 评论