Wireshark网络分析的艺术

978-7-115-41021-4
作者: 林沛满
译者:
编辑: 傅道坤

图书目录:

详情

本书延续了上一版图书诙谐风趣的写作风格,同时借助于更为丰富齐全的案例来与读者分享Wireshark的强大技巧。并借助Wireshark通过抓包分析的方式来帮助大家学习、掌握TCP/IP、DNS、HTTP等技术的精髓;最后通过几个实用的案例,帮助大家进一步掌握Wireshark的一些高级功能。

图书摘要

版权信息

书名:Wireshark网络分析的艺术

ISBN:978-7-115-41021-4

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。





林沛满,2005年毕业于上海交通大学,现任EMC网络存储部门的主任工程师。多年来为多个产品团队提供 过技术咨询,范围包括网络、操作系统、文件系统和域等,这就是本书所涵盖的协议如此五花八门的原因。每年临近加薪的日子,他也会组织一些技术培训来提醒上司。本书的部分内容就来自这些培训资料。

平时他也写一些技术博客,你或许还能在IT168或者ChinaUnix技术社区看到它们。本书也有少数内容来自这些博客。

当林先生不在工作时,大部分时间都花在了园艺花卉上,尤其是欧洲月季。

本书特色

作为网络工程师的你,想摆脱给别人留下的木讷、沉闷、呆板、不善言谈……的印象么?作为高校伟大人民教师的你,想在枯燥乏味的课堂中添加一些乐趣,换回学生的注意力么?作为公司IT部门的老好人,想在给美女同事露一手的同时,并通过渊博的学识来征服她们么?

如果以上答案都为Yes,那么《Wireshark网络分析的艺术》是你的首选读物,这本诙谐幽默轻松易读……的IT技术图书可以解决上述的所有问题。《Wireshark网络分析的艺术》广度与深度齐备,诙谐幽默的文笔背后是作者多年以来的技术积淀的厚积薄发。

另外,《Wireshark网络分析的艺术》不同于其他枯燥的技术类图书,《Wireshark网络分析的艺术》不务虚,不注水,无阅读尿点,页页干货,篇篇精华,而这一切,均以给读者提供最佳阅读体验为出发点和宗旨。


有幸在出版前读到本书初稿,看完之后让我想到了电影“黑客帝国”(The Matrix)。在这个应用、协议日趋复杂的网络中,沛满抓几个包分析一下就能洞察网络问题的根源,就像Neo用手抓住迎面飞来的子弹那样驾轻就熟。他的上一本书介绍的是使用Wireshark来分析网络协议,这本书则站在了更为实用的角度来介绍他丰富的Wireshark使用经验和解决问题的独到思路与方法,因此非常值得学习。另外,虽然这两本书的侧重点各有不同,但是上一本书的风趣幽默的写作风格依然良好地传承到了这本书上——能让读者笑开怀的技术类图书真是不多见。作为学习、实践网络协议不可多得的参考书,我会向学生推荐这两本书。

——段海新,清华大学博士生导师

沛满长期做网络嗅探的工作,实战经验相当丰富,外加他强大的抽象分析能力和简单诙谐的写作风格,使本书中的每一篇技术文章都像看CSI科学探案一样过瘾。本书真正践行了许多技术图书宣称的“工程师写给工程师读”的宗旨,是解决(know-how)和分析(know-why)问题的硬功夫,我会将本书推荐给用到网络分析的任何一位技术人员。

——何万青,英特尔企业与高性能计算高级架构师

有些人对同胞撰著的技术书籍有一种莫名的不信任感,以前的我亦是如此,不过这种偏见在我看过林沛满写的书之后便烟消云散了。原本觉得很复杂的问题,经过他看似轻描淡写的叙述之后,一切豁然开朗。

——火丁笔记,知名技术博主

大约两年前,我对网络技术还一知半解,然后我认识了林沛满,被他强烈推荐了Wireshark,从此便打开了网络的黑箱。你还别说,这玩意儿还真的帮我解决了不少问题,效果杠杠的。然而,比工具更重要的是技术大牛分析和解决问题的思路,以及“很多看起来灵光乍现的Eureka!其实靠的都是积累”这条特别打击人的真理。哦对了,上面这些都是瞎说的,这其实是本悬疑推理小说。真的,不骗你!

——周自恒,资深技术图书译者

《Wireshark网络分析就这么简单》书评摘选

“这本书陪了我几个深夜。没有大部头的催眠和艰涩,每一节都精炼易读,和咖啡一样令人上瘾。我是网络小新人,但是不觉得特别难,很容易顺下来。里面很多干货,厚积薄发,都是实际环境中的情况。畅快淋漓读完大呼不过瘾,搜了一下作者就这一本书。遗憾!”

——亚马逊读者

“这本书是我2014年读过的10本好书之一,如果说我对这本书有什么不满的话,就只有一个:书写薄了,意犹未尽,读着完全不过瘾呀呀呀。或许这本书浅显易懂、幽默风趣的语言风格让你在无障碍阅读的同时,会让你有一种这书太浅、适合初学者的感觉,但是这本书实际上是越读越有味道,我就读了好几次。”

——豆瓣读者


Wireshark是当前最流行的网络包分析工具。它上手简单,无需培训就可入门。很多棘手的网络问题遇到Wireshark都能迎刃而解。

本书挑选的网络包来自真实场景,经典且接地气。讲解时采用了生活化的语言,力求通俗易懂,以使读者在轻松阅读的过程中,既可以学到实用的网络知识,又能形成解决问题的思路。

与大多网络图书的课堂式体验不同,阅读本书的感觉更像在听技术圈的朋友分享经验,除了知识,还有心情和想法。本书的覆盖范围从日常使用的手机App,到企业级的数据中心;从对付运营商的网络劫持,到开发自己的分析工具,不一而足。无论你是系统管理员、实施工程师、技术支持、网管、培训教师,还是开发和测试人员,都适合阅读本书。


林沛满,2005年毕业于上海交通大学,现任EMC网络存储部门的主任工程师。多年来为多个产品团队提供过技术咨询,范围包括网络、操作系统、文件系统和域等,这就是本书所涵盖的协议如此五花八门的原因。每年临近加薪的日子,他也会组织一些技术培训来提醒上司,本书的部分内容就来自这些培训资料。

平时他也写一些技术博客,你或许还能在IT168或者ChinaUnix技术社区看到它们,本书也有少数内容来自这些博客。他也是《Wireshark网络分析就这么简单》的作者。

当林先生不在工作时,大部分时间都花在了园艺花卉上,尤其是欧洲月季。


我那些没有技术背景的亲友只能读懂这一部分,所以要尽量写得好一些。

分析网络包占用了很多本应该和家人在一起的时光,因此要特别感谢他们的理解和支持。我妻子在每天忙碌的工作之余,还要弥补我的那份亲子时间,让小满享受到完美的亲情。她也是第一个审核书稿的人,包括文字和技术两方面,“贤内助”一词已经不足以形容她的贡献了。我父母分担了很多家庭劳动,否则花园里早就杂草丛生。他们可能至今还以为我坐在电脑面前就是在赶稿子。

技术圈的很多朋友帮忙检阅了本书部分章节,为我严把技术关。请给我一次招待你们吃大餐的机会。

我的老板从没有提出过KPI上的要求,因此我才有这么多时间研究工作之外的技术问题。

此外还要感谢很多读者长期的鼓励,请恕我无法一一列举你们的名字。要不是你们隔段时间就催一下,以我的拖延症不知道何日才能写完。


Wireshark已经用不着我来做广告了,它早已被多家权威机构评为最佳嗅探器,从事网络工作的工程师都知道它。即便我如实地列举它的种种好处,都涉嫌违反广告法。这也许就是我的上一本书《Wireshark网络分析就这么简单》得以多次重印的原因,是神器总会流行的。读者的评价也超乎我的想象,随手复制两条书评过来满足一下我的虚荣心:

“这本书陪了我几个深夜。没有大部头的催眠和艰涩,每一节都精炼易读,和咖啡一样令人上瘾。我是网络小新人,但是不觉得特别难,很容易顺下来。里面很多干货,厚积薄发,都是实际环境中的情况。畅快淋漓读完大呼不过瘾,搜了一下作者就这一本书。遗憾!”

——亚马逊读者

“这本书是我2014年读过的10本好书之一,如果说我对这本书有什么不满的话,就只有一个:书写薄了,意犹未尽,读着完全不过瘾呀呀呀。或许这本书浅显易懂、幽默风趣的语言风格让你在无障碍阅读的同时,会让你有一种这书太浅、适合初学者的感觉,但是这本书实际上是越读越有味道,我就读了好几次。”

——豆瓣读者

既然有这么多人喜欢,我有什么理由不再写一本呢?于是就有了这本新书。虽然我在写稿这件事情上的拖延症不亚于洗碗,不过读者们的鼓励显然起了作用,最后收笔时间只比原计划晚了6个月。和老读者们期望的一样,它是上一本书的延续,尤其是在写作风格上。不同之处在于这一本不再着重分析基础协议,而更专注于解决现实问题。另外,考虑到现在手机上网日趋流行,本书也增加了一些手机App的内容,相信读者会喜欢。

就如我常在培训课上所讲的,学会Wireshark这个软件只需要几个小时,掌握一个网络协议也用不了几天,而养成解决问题的思路却需要经年累月的练习和思考。本书正提供了很多练习和思考的机会,本书30多篇文章,几乎都用了Wireshark来分析网络包。我希望每一篇都能让读者产生这样的感触:“啊,原来Wireshark还可以这样用!”“读完整本书,自然而然会形成看包的习惯和思维方式。

就像时尚女郎每天都在看包包一样,我也每天都在看包。看到有趣又有价值的,就会记录下来,久而久之就形成了这本书。因此它有别于包罗万象的网络教材,而更像一个技术博客的合集。

全书根据素材来源可分为四个部分。

第一部分的选材来自老读者的咨询,相信很有代表性,说不定其他读者也会遇到。

第二部分是我自己在工作中遇到的网络问题。这部分讲得最细、最深,问题本身也最复杂。在阅读这一部分时,可能要多花点时间。

第三部分的选材是日常生活中的抓包,包括手机App。在未来一两年,可能会有越来越多的人去抓手机上的包,因为用得多了,问题也会跟着增加。

第四部分的内容很少,却花费了我不少时间,因为写的是两个项目/产品。

只需要具备网络常识,比如在学校里上过网络课或者考过CCNA就够了。如果读过《Wireshark网络分析就这么简单》是最好的,会觉得衔接顺畅。对于缺乏网络基础的Wireshark用户,建议先阅读Richard Stevens的《TCP/IP 详解 卷1:协议》。英文好的读者可以通过http://www.tcpipguide.com/free/index.htm页面免费阅读《The TCP/IP Guide》一书,里面的插图画得尤其好。由于读免费书籍很难坚持下去,你可以点击页面下方的Donate按钮给作者捐款,由此增加进一步学习的功力。

我写这本书是为了让读者学有所获,因此选材也从读者的兴趣点出发。比如现在流行手机上网,因此我增加了这部分的内容;又比如技术圈正在热议HttpDNS,所以我就去做了一系列实验……不同读者的关注点肯定会有所不同,如果某一篇的话题不是你感兴趣的,直接跳过也不影响后面的阅读。

人们读书时都会有这样的反应——读到自己不懂的内容时,就会觉得高大上;读到自己擅长的领域时,又会觉得太简单。这就是为什么有些作者喜欢把书写得很玄乎,然而我的风格恰恰相反,会尽可能地把复杂的问题简单化。我的技术培训也是坚持这样的风格,会假设所有听众都是刚毕业的文科妹子(嗯,这样也会使我的心情好一些)。

我也希望能把这本书里的网络包都共享出来,但由于大多是在客户的生产环境中抓到的,所以不适合公开。毕竟从包里能暴露出来的安全隐患太多了,希望读者能理解这个苦衷。为了方便阅读,我已经尽量把Wireshark截图做清晰。建议大家在自己的环境中抓包分析,这会比看示例包更有价值。

如果对书中的内容有疑问,或者自己抓了包却不知道怎么分析,都可以联系作者,邮箱地址为linpeiman@hotmail.com。你也可以在微博上@林沛满,但不建议关注,因为他是个整天晒园艺图片的话痨。


在过去几年中,有不少读者、同事和网友向我咨询过网络问题,其中大部分都记录在案。我一直把这些案例视为珍贵的财富,因为既真实又有广泛的代表性,比我自己在实验室中“制造”出来的好多了。本书从中选择了最经典的部分,希望读者会感兴趣。如果你在工作或生活中遇到网络问题,也欢迎抓个包来找我分析。


到今天为止,已经有5位读者向我求助过这个问题了。症状请看图1,他们通过SSH登录Linux服务器时,输完用户名就卡住了,要等待10秒钟才提示密码输入。这究竟是什么原因导致的呢?其实我也是Linux菜鸟,虽然尝试过搜索“ssh hang”等关键词,但是没找到相关信息。

图1

10秒钟的时间并不算长,吃个薯片喝口咖啡就过去了。但是作为强迫症患者,我还是容不得它的存在,因此便决定写篇文章,向大家演示一下怎样用Wireshark一步步解决这个问题。

首先是抓包,步骤如下。

1.在Linux服务器上启动抓包。

2.从笔记本SSH到Linux服务器,输入用户名并回车。

3.等待10秒左右,直到登录界面提示输入密码。

4.停止抓包。

这样就可以得到一个涵盖该现象的网络包了。一般在实验室中没有干扰流量,不用过滤也可以分析,不过我们最好在做实验时就养成过滤的习惯,以适应生产环境中抓到的包。因为我们是通过SSH协议登录的,所以可以直接用“ssh”来过滤,如图2所示。SSH包都是加密了的,因此我们看不出每个包代表了什么意思,不过这并不影响分析。从图2中可以看到,21号包和25号包之间恰好就相隔10秒。

图2

这两个包之间所发生的事件,可能就是导致这个现象的原因。于是我再用“frame.number> 21 && frame.number< 25”过滤,结果如图3所示。

图3

从图3中可以看到,Linux服务器当时正忙着向DNS服务器查询10.32.200.23的PTR记录(即反向解析),试图获得这个IP地址所对应的域名。该IP属于我们测试所用的笔记本,但由于DNS服务器上没有它的PTR记录,所以两次查询都等了5秒钟还没结果,总共浪费了10秒钟。

我们由此可以推出,这台Linux服务器在收到SSH访问请求时,会先查询该客户端IP所对应的PTR记录。假如经过5秒钟还没有收到回复,就再发一次查询。如果第二次查询还是等了5秒还没回复,就彻底放弃查询。我们甚至可以进一步猜测,如果DNS查询能成功,就不用白等那10秒钟了。

为了验证这个猜测,我在DNS服务器中添加了10.32.200.23的PTR记录,如图4所示,然后再次登录。

图4

这一次果然立即登录进去了。从图5的Wireshark截屏可见,DNS查询是成功的,所以21号包和26号包之间几乎是没有时间停顿的。

图5

明白了DNS查询就是问题的起因,接下来就知道怎么进一步研究了。只要在Google搜索“ssh dns”,第一页出来的链接都是关于这个问题的。随便挑几篇阅读一下,就连我这样的Linux初学者都能把这个问题研究透了。原来这个行为是定义在“/etc/ssh/sshd_config”文件中的,默认配置是这样的:

[root@Linux_Server ~]# cat /etc/ssh/sshd_config |grep -i usedns
#UseDNS yes

改成下面这样就可以解决了,不用去动DNS服务器上的配置:

[root@Linux_Server~]# cat /etc/ssh/sshd_config |grep -i usedns
UseDNS no

我经常说技能比知识更重要,这就是例子之一。学会了使用Wireshark,其他知识也会跟着来的。


有位读者在豆瓣上评论我的上一本书,说有阅读侦探小说的感觉。我对此并不觉得惊讶,因为用Wireshark排查问题,和侦探破案的思路是一致的。神探福尔摩斯的破案秘诀是“溯因推理”——先观察所有细节,比如鞋根上的泥疙瘩甚至烟灰;然后作出多种推理和假设;接着刨去各种不可能,最后剩下的“无论多么难以置信,肯定没错。”用Wireshark分析网络包时也类似,我们先要在网络包中寻找各种线索,然后根据网络协议作出推理,接着刨去人为(有意或无意)掩盖的证据,才能得到最后的真相。尤其是和保密机构打交道的时候,工程师进不了机房,文档也不能公开,所以一切线索只能自己在包里找,感觉就更像破案了。

我最近帮一位读者解决的问题就非常典型。他供职的机构内部网站有时候会发生诡异的现象,比如Web服务器的端口号会随机发生变化(具体症状就不多讲了,和本文关系不大)。后来做了排查,把客户端和Web服务器直连,问题就消失了,确认了Web服务器和客户端都没有问题。难道根本原因就出在网络路径上了?可是管理员又声称网络拓扑非常简单,不会出问题的。见图1,客户端和Web服务器在不同的子网里,中间由一个路由器转发。

图1

凭我的经验,这个网络拓扑的确简单到没有出问题的可能。可是已经到了山穷水尽的地步了,只好抓包试试。Web服务器不允许我们登录,所以只能在客户端抓,更糟糕的是抓包时那个诡异的现象并没有发生。你一定会纳闷,正常状况抓的包有什么看头啊?人在走投无路的时候,要求都是很低的,能抓到一点算一点。图2就是抓到的包,看起来一切都很正常:前3个包是三次握手,接着客户端发了个HTTP GET请求,服务器也确认收到了。

图2

既然表面上都是好的,我们再看看每个包的详细信息。1号包的详情见图3,客户端把包交给了一个叫c0:62:6b:e2:bd:88的MAC地址,该地址属于默认网关。将包交给默认网关是合理的,因为Web服务器在另一个子网中,需要路由转发。也就是说,从1号包中没有发现任何异常。

图3

再看看图4的2号包详情。这个包让人眼前一亮,信息量实在太大了。在阅读下面的文字之前,建议你自己先在图中找找亮点。

图4

首先这个包竟然是从MAC地址00:10:f3:27:61:86发过来的,而不是之前提到的默认网关c0:62:6b:e2:bd:88。我不知道这个MAC地址属于什么设备,但这至少说明2号包和1号包走了条不一样的路径。再看其Time to live(TTL)居然是64,理论上经过一次路由的包,TTL应该减去1,变成63才对。根据这两条信息,可以推测管理员提供的拓扑图有误。真正的网络包流向应该接近图5,即客户端发出去的包是经过路由的,而Web服务器发过来的包没经过路由。

图5

其实到这里就可以去找管理员说理了,不过别急,继续往下看。到了图6的第5号包,发现Identification竟然是49031,而同样是来自Web服务器的2号包(见图4)中,Identification却是0。一般发出Identification为0的机器永远都发0,不会一下子跳到49031。也就是说,其实2号包和5号包是两台不同的设备发出来的,这意味着在Web服务器和客户端之间,可能存在一台设备在代理三次握手,而能够代理握手的设备很可能是应对Syn flood攻击的防火墙。

图6

因此图5的拓扑图还不够准确,应该更正成图7的样子。管理员忽视了这台防火墙,可能就错过了发现问题根源的机会。

图7

把以上分析反馈给管理员之后,他果然通过MAC地址00:10:f3:27:61:86找到了一台防火墙。也正是防火墙上的一些错误配置,导致他们遇到了那些诡异症状,改正之后症状就消失了。本文的目的是演示如何在网络包中寻找被掩盖的线索,而不是防火墙知识,所以就不展开了。

从头到尾再复习一下整个过程,是不是很有当侦探的感觉?

注意:

为了保护客户隐私,本文截图里的IP地址和MAC地址都被PS过,这就是为什么有些截图看上去不太自然。


有位读者在VMware的知识库里找到一篇文章,觉得很像他正在遭遇的一个性能问题,便转发给我确认。作为好为人师的技术员,我当然不能让读者失望。

这篇文章大概讲了这样一件事。

某些iSCSI存储阵列在出现网络拥塞时处理不当,会严重影响VMware的读写性能。这和它们的TCP实现方式有关。

在VMware和存储阵列上关闭延迟确认(Delayed ACK)

VMware和iSCSI存储阵列是什么?我在知识库里找到一个网络拓扑,看起来很简单,大概如图1所示。我们无需理解得很深,只要把iSCSI存储阵列当作一台服务器,再把VMware当作其客户端就行了,两者通过以太网传输数据。

图1

乍一看,这个“问题描述”与“解决方式”简直风马牛不相及。网络拥塞怎么能靠关闭延迟确认来解决?不过出于对VMware的一贯信任,我决定还是好好研究一下。

我们先要明白什么叫延迟确认,它可以用一个简单的例子来说明:在上海的笔记本上启动Wireshark抓包,然后用Putty远程登录一台位于悉尼的服务器。由图2可见,在上海发出一个SSH请求之后,经过149毫秒左右(即1号包和2号包之间的时间差)收到了悉尼的回复,这是正常的往返时间。但是笔记本收到回复之后,却没有立即确认,而是延迟了200毫秒以上(即2号包和3号包之间的时间差)才确认。

图2

这个现象就是传说中的延迟确认,我在上一本书中也介绍过。为了让大家更好地理解它,我们再做个对比实验:我在笔记本上关闭了延迟确认,然后再次连接悉尼的服务器。从图3可见2号包和3号包之间几乎没有时间差了(只有0.000121秒,可以忽略)。

图3

启用延迟确认是有好处的,假如在这等待的200毫秒里,上海的笔记本恰好有数据要发,就可以在发数据时捎带确认信息,省去了一个纯粹的确认包。图4就符合这种情况。笔记本收到11号包之后,等了41毫秒左右(即11号包和12号包之间的时间差)恰好又有一个SSH请求要发,就顺便把确认捎带过去了,因此省掉了一个纯粹的确认包。之所以有很多TCP协议栈默认启用延迟确认,正是基于这个原因——少一些确认包可以节省带宽嘛。

图4

延迟确认的坏处也很明显,就是会凭空多出一段延迟。这个机制的作用很像你中午懒得去食堂吃饭,便等到下午出门上课时顺便去吃一点。结果就是少跑了一趟食堂,但是吃饭时间却被延后了。

理解了延迟确认的原理,我们再回顾VMware的那篇文章。一般来说,偶尔浪费200毫秒的等待时间并不算严重的问题,VMware为什么要这么在意呢?又不是等待很多个200毫秒。当我联想到“很多个”时,终于明白了——这世界上还真的存在一种很老的TCP的实现(RFC 2582),会导致拥塞时出现多个200毫秒的等待时间。详情且看下文分析。

图5从客户端的视角演示了启用延迟确认时,某些TCP协议栈在处理网络拥塞时的状况。

图5

这个传输过程发生了以下事件。

1.客户端在同一时刻(或者说同一窗口)发送了9个TCP包,其中3、4、5号因为拥塞丢失了。

2.到达服务器的6、7、8、9号包触发了4个“Ack 3”,于是客户端快速重传3号包,此时它并不知道4号包也丢了。

3.由于服务器上启用了延迟确认,所以它收到3号包之后,等待了200毫秒才回复Ack 4。

4.客户端重传4号包,然后服务器又等待了200毫秒才回复Ack 5。

5.客户端重传5号包,然后服务器又等待了200毫秒才回复Ack 10。

6.客户端传输新的10号包,自此该网络拥塞就完全恢复了。

由于当时没有抓包,因此以上分析仅是我的推测。还有另一种可能是在某个200毫秒的延迟过程中,那些丢包的RTO(Retransmission Timeout)已经被触发,所以进入了超时重传阶段。无论符合哪一种可能,性能都会严重下降,因此VMware建议关闭延迟确认是很有道理的,只不过没把原理说清楚。我甚至怀疑写这篇文章的人也没真正理解,因为里面还提到了慢启动之类不太相关的东西。

假如把延迟确认关闭掉,那该TCP协议栈处理拥塞的过程就变成图6所示。包还是那些包,不过浪费在延迟确认上的600毫秒就省下来了。只要往返时间不是太长,那些丢包也不会触发超时重传,所以避免了第二种可能。

图6

我把分析结果告诉了那位读者,确保这个修改没什么副作用。于是他壮着胆子关闭了延迟确认,果然VMware的性能就飙升了。图7是他在关闭之后抓的网络包,和上文分析的一模一样,果然连续丢了很多包,而且每个重传都需要确认一次。

图7

我以前分享的案例都是先在Wireshark中找到症状,然后再结合协议分析找到原因的。而这次纯粹是依靠协议分析,预测能从包里看到什么,然后再用Wireshark验证的。听起来似乎是完全靠灵感,但灵感不是天生的,它来自长期的训练。只有在Wireshark中看过了延迟确认和大量重传的样子,才可能意识到它们放在一起会出大问题。

注意:

如果对那篇VMware的文章感兴趣,可以在其知识库http://kb.vmware.com中搜索1002598来找到它。


前一篇文章发布后,被一些公众号转发了。于是就有资深技术人员找到我,说读完觉得不过瘾,希望来点有深度的。好吧,那篇的确只从表面上介绍了延迟确认在网络发生拥塞时的影响,要往深处分析的话还是有不少料的。

先发散一下思维:除了VMware所建议的关闭延迟确认,还有其他的方法可以解决这个问题吗?

答案是肯定的。既然VMware的文章说“某些提供iSCSI访问的存储阵列在出现网络拥塞时处理不当”,就说明还有些存储阵列是处理得当的,即使打开延迟确认也不怕。那它们又是如何处理的呢?我做了很多研究之后,发现它们其实就是启用了TCP SACK(Selective Acknowledgement)功能,因此在大量丢包的时候不需要每个重传包都确认一次,也就不怕延迟确认的影响了。图1从客户端的角度演示了同样丢包的情况下,启用SACK的TCP协议栈是怎样处理重传的。

图1

这个传输过程发生了以下事件。

1.客户端在同一时刻(或者说同一窗口)发送了9个TCP包,其中3、4、5号因为拥塞丢失了。

2.到达服务器的6、7、8、9号包触发了4个“Ack 3”。

3.由于启用了SACK,所以服务器可以在4个“Ack 3”中告知客户端哪些包已经收到了。

4.因为客户端已经知道哪些包丢了,哪些包已经收到,所以它可以一口气完成重传。

SACK信息在Wireshark中很容易看到。如图2所示,只要把“Ack=656925”和“SACK: 661857-663035”这两个因素结合起来,客户端就知道排在后面的数据段661857-663035已经送达,但排在前面的656925-661856(共4932字节)反而丢失了,因此它需要重传这段数据。从图3可以看到每个重传包的Len值,四个包加起来恰好就等于4932字节。

图2

图3

由此可见启用SACK其实比关闭延迟确认更高效,因为它可以一次性重传多个丢包,而不用每重传一个就等待一次Ack,白费多个往返时间。这在局域网环境中的优势还不太明显,如果是在远程镜像中,一个正常的往返时间都要花上百毫秒,那就更应该启用SACK了。我真的很好奇VMware为什么不提供这个建议。

说完SACK,再讲一个更加有深度的知识点:除了大量重传之外,延迟确认还会在什么场景下严重影响性能?

从本质上看,延迟确认之所以会在大量重传时影响性能,是因为它在该场景下会多次出现(甚至因为延迟太久而导致超时重传)。那么还有什么场景会导致延迟确认多次出现呢?凭空想象是很难得到答案的,不过当你看过的网络包足够多时,肯定会遇到一些。我个人遇到最多的是TCP窗口极小的情况,此时启用延迟确认简直就是雪上加霜。图4演示了服务器接收窗口只有2920字节(相当于两个MSS),且关闭了延迟确认时的场景。因为客户端每发两个包就会耗光窗口,所以不得不停下来等待服务器的确认。假如这时候在服务器上启用了延迟确认,那29号和30号之间、32号与33号之间……以及38号和39号之间都需要多等待200毫秒,意味着传输效率会下降数百倍。这个场景下的延迟确认杀伤力巨大,又非常隐蔽,所以第一次遇上的工程师根本不知所措。

图4

其他的场景我也遇到过一些,不过次数很少,就不一一列举了。更值得关注的,是如何在Wireshark中发现延迟确认,并计算它所带来的影响。

由于延迟确认是一个正常的TCP机制,有其积极的一面,所以Wireshark是不会把它当作问题标志出来的,而且点击AnalyzeExpert Info菜单也是不会统计延迟确认的。难道我们只能靠人工去计算每个确认包的等待时间吗?我几年前就因此吃过一次亏——有位同事找我分析一个性能相关的网络包,我用Wireshark看了半天都没有发现问题,所以就斩钉截铁地说跟网络无关。后来客户自己尝试关闭了延迟确认,性能居然就飙升了,导致我和同事都非常尴尬。最后写分析报告的时候才想到办法:只要用“tcp.analysis.ack_rtt > 0.2 and tcp.len==0”过滤一下,就可以把所有超过200毫秒的确认都筛出来了(当然筛出来的不一定全都是延迟确认,追求精确的话就逐个检查)。图5正是我当年遇到的那个网络包,只要把过滤出来的包数乘以0.2秒,就知道大概浪费了多少时间。

图5

这两篇文章所列举的案例,其实在现实环境中广泛存在。不过由于症状只是性能差,所以很多用户以为是带宽不足导致的,就一直忍着。用Wireshark抓个包看看吧,很可能无需升级硬件,也可以帮你的系统大幅度提升性能的。


我原本以为TCP三次握手不值得写,没想到在某技术社区上被提问好几次了。看来感兴趣的人还真不少,还是写一篇吧。

我们知道TCP需要通过三次握手来建立连接,过程如图1所示。

图1

从Wireshark上看到的握手过程就是图2这样的,你可以把Seq号和Ack号代入图1中,看看是否符合规律。

图2

当X和Y的值太大时,看起来就不太友好,尤其是需要对这些号码做加减运算时。于是Wireshark提供了一个功能——把Seq和Ack的初始值都置成0,即用“相对值”来代替“真实值”。我们可以在Edit→Preferences→Protocols→TCP菜单中勾上Relative Sequence Numbers来启用它。启用之后,图2的包就变成图3这样,是不是清爽了很多?

图3

成功的握手都是一样的,失败的握手却各有不同,因此解决起来还是需要一些技巧的。当我们遭遇TCP连接建立失败时,最稳当的排查方式就是用Wireshark来分析。网络包不多的时候很容易入手,用肉眼观察就行,但如果抓到的包特别大就需要过滤技巧了。根据我的经验,握手失败一般分两种类型,要么被拒绝,要么是丢包了。因此用两道过滤表达式就可以定位出大多数失败的握手。

表达式1:(tcp.flags.reset == 1) && (tcp.seq == 1)

从表面上看,它只是过滤出Seq号为1,且含有Reset标志的包,似乎与握手无关。但在启用Relative Sequence Numbers的情况下,这往往表示握手请求被对方拒绝了,结果如图4所示。接下来只需右键选中过滤出的包,再点击Follow TCP Stream就可以把失败的全过程显示出来,见图5。此次握手失败的原因是服务器没有在监听80端口,所以拒绝了客户端的握手请求。

图4

图5

表达式2:(tcp.flags.syn == 1) && (tcp.analysis.retransmission)

这道表达式可以过滤出重传的握手请求。一个握手请求之所以要重传,往往是因为对方没收到,或者对方回复的确认包丢失了。这个重传特征正好用来过滤,结果如图6所示。接下来右键点击过滤出的包,再用Follow TCP Stream就可以把失败过程显示出来,见图7。此次握手失败的原因是丢包,所以服务器收不到握手请求。

图6

图7

这两个表达式很好用,不过要最快排查出根本原因还需要另一个技巧,即在两端同时抓包来分析。为什么要两端同时抓呢?请考虑图8所示的两种状况。

图8

同样是握手失败,左图是客户端发出的包丢了,右图则是服务器回复的包丢了。不同的丢包往往意味着不同的问题根源,解决方式也不一样。如果只在客户端抓包,那这两种丢包的症状看起来就像是一样的,排查起来也会慢一些。

说完握手失败的排查技巧,我们再来讲讲和握手有关的安全问题。做运维的工程师们都知道,大规模DDoS(Distributed Denial of Service,分布式拒绝服务攻击)来临的时候最惊心动魄。DDoS的形式有很多种,其中最流行的就是基于三次握手的SYN flood,其原理是从大量主机发送SYN请求给服务器,假装要建立TCP连接。这些SYN请求可能含有假的源地址,所以服务器响应后永远收不到Ack,就会留下half-open状态的TCP连接。由于每个TCP连接都会消耗一定的系统资源,如果攻击足够猛烈,此类连接越建越多,服务器的资源就会被耗光,真正的用户访问也会被拒绝。

Wireshark可以轻易地发现SYN flood。有时一打开包就很显眼了,如图9所示,密密麻麻都是SYN。假如干扰包太多,那就点击AnalyzeExpert InfoChats菜单,可以看到SYN的总数量统计。

图9

我们可以把SYN flood看作TCP协议的设计缺陷,有办法可以防御,却无法根除。想知道大公司都是怎样防御的吗?手段有很多,其中有一些还可以在Wireshark中看出端倪。我假装攻击了全球最大的假药销售网站,然后把全过程的包抓下来。从图10可见,对方很快就识别了我的不良意图,所以Reset(RST)了大多数握手请求。如果有兴趣去研究RST包里的细节,比如网络层的TTL和Identification,也许还能判断出究竟是流量清洗还是TCP握手代理之类的。本书不是网络安全专著,所以就不展开分析了。

图10


人一旦形成某种思维定势,就很难再改变了。知道我收到最多的读者来信是问什么吗?“林工,有些TCP包发出去之后没有看到对应的Ack,算不算丢包啊?”这个问题让我很是好奇,明明RFC上没有这样的规定,为什么总有读者觉得每一个数据包都应该有对应的Ack呢?后来才注意到,很多提问者是做网站开发出身的,已经习惯了每个HTTP请求发出去,就一定会收到一个HTTP响应(见图1),因此就把这个模式套到了TCP上。其实不止HTTP,绝大多数应用层协议都采用这种一问一答的工作方式。

图1

TCP当然也可以采用这种方式,但并非必要。就像我们不用每天都跟公司算一次工钱,而是攒到月底结算一样,数据接收方也可以累积一些包才对发送方Ack一次。至于Ack的频率,不同的操作系统有不同的偏好,比如我实验室中的Linux客户端喜欢每收到两个包Ack一次,见图2。

图2

而Windows客户端则懒得多,隔好多个包才Ack一次,见图3的97号包。

图3

这两种方式都是正常的,但Linux对流量更“大手大脚”一点,因为纯Ack也算流量的。其实在网络带宽越来越大的今天,人们已经不在乎这种小流量了。不过手机操作系统还是要慎重考虑的,毕竟蜂窝数据是按流量计费的,能省一点是一点。我的安卓手机就是每收到一个包都会Ack的,想到这里我的心都在滴血。图4是我在微博上打开一张美女图时产生的流量,你看这些密密麻麻的纯Ack,每个都白费我40字节的流量。

图4

也许以后会有手机厂商优化它,然后以此作为卖点。如果是从我这本书里学到的,请为它命名“林朗台算法”。

既然接收方不一定收到每个包都要Ack,那发送方怎么知道哪些包虽然没有相应的Ack,但其实已经送达了呢?记住,Ack是有累积效应的,它隐含了“在此之前的其他包也已收到”的意思,比如图3中第97号包的Ack=65701不仅表示收到了96号包(其Seq+Len=64273+1428=65701),而且暗示之前的其他包也都收到了。因此86~95号包虽然没有被显式Ack,但发送方知道它们也已经被送达了。

另一个对TCP的广泛误解则和UDP相关。有不少技术人员认为TCP的效率低,因为其传输过程中需要往返时间来确认(Ack)。而UDP无需确认,因此能不停地发包,效率就高了。事实真的如此吗?这其实是对TCP传输机制的严重误解。我们可以假设一个场景来类比TCP的工作方式:有大批货物要从A地运往B地。如果只用一辆货车来运的话,马路上就只有一辆车在来回跑(回程相当于TCP的Ack包),效率确实很低,对TCP的误解可能也出自这个原因。但如果在不塞车的前提下尽量增加货车数量,使整条马路上充满车,总传输效率就提高了。TCP发送窗口的意义相当于货车的数量,只要窗口足够大,TCP也可以不受往返时间的约束而源源不断地传数据。这就是为什么无论在局域网还是广域网,TCP还是最受欢迎的传输层协议。

当然TCP确实也有因为往返时间而降低效率的时候,比如在传输小块数据的场景。本来能在1个往返时间完成的小事,却要额外耗费3次握手和4次挥手的开销,DNS查询就符合这种场景。目前HTTP基本建立在TCP连接上,所以也会因为TCP的三次握手而增加延迟。你可能听说过Google发布的QUIC(Quick UDP Internet Connection)协议,它就是为了消除TCP的延迟而设计的代替品。在某些领域可以视为TCP的竞争对手,目前在Google的网站上已经可以试用了。


相关图书

CTF快速上手:PicoCTF真题解析(Web篇)
CTF快速上手:PicoCTF真题解析(Web篇)
数字银行安全体系构建
数字银行安全体系构建
软件开发安全之道概念、设计与实施
软件开发安全之道概念、设计与实施
企业信息安全体系建设之道
企业信息安全体系建设之道
内网渗透技术
内网渗透技术
深入浅出密码学
深入浅出密码学

相关文章

相关课程