本节书摘来自异步社区《Wireshark网络分析的艺术》一书中的三次握手的小知识,作者林沛满,更多章节内容可以访问云栖社区“异步社区”公众号查看。
三次握手的小知识
Wireshark网络分析的艺术
我原本以为TCP三次握手不值得写,没想到在某技术社区上被提问好几次了。看来感兴趣的人还真不少,还是写一篇吧。
我们知道TCP需要通过三次握手来建立连接,过程如图1所示。
从Wireshark上看到的握手过程就是图2这样的,你可以把Seq号和Ack号代入图1中,看看是否符合规律。
当X和Y的值太大时,看起来就不太友好,尤其是需要对这些号码做加减运算时。于是Wireshark提供了一个功能——把Seq和Ack的初始值都置成0,即用“相对值”来代替“真实值”。我们可以在Edit→Preferences→Protocols→TCP菜单中勾上Relative Sequence Numbers来启用它。启用之后,图2的包就变成图3这样,是不是清爽了很多?
成功的握手都是一样的,失败的握手却各有不同,因此解决起来还是需要一些技巧的。当我们遭遇TCP连接建立失败时,最稳当的排查方式就是用Wireshark来分析。网络包不多的时候很容易入手,用肉眼观察就行,但如果抓到的包特别大就需要过滤技巧了。根据我的经验,握手失败一般分两种类型,要么被拒绝,要么是丢包了。因此用两道过滤表达式就可以定位出大多数失败的握手。
表达式1:(tcp.flags.reset == 1) && (tcp.seq == 1)
从表面上看,它只是过滤出Seq号为1,且含有Reset标志的包,似乎与握手无关。但在启用Relative Sequence Numbers的情况下,这往往表示握手请求被对方拒绝了,结果如图4所示。接下来只需右键选中过滤出的包,再点击Follow TCP Stream就可以把失败的全过程显示出来,见图5。此次握手失败的原因是服务器没有在监听80端口,所以拒绝了客户端的握手请求。
表达式2:(tcp.flags.syn == 1) && (tcp.analysis.retransmission)
这道表达式可以过滤出重传的握手请求。一个握手请求之所以要重传,往往是因为对方没收到,或者对方回复的确认包丢失了。这个重传特征正好用来过滤,结果如图6所示。接下来右键点击过滤出的包,再用Follow TCP Stream就可以把失败过程显示出来,见图7。此次握手失败的原因是丢包,所以服务器收不到握手请求。
这两个表达式很好用,不过要最快排查出根本原因还需要另一个技巧,即在两端同时抓包来分析。为什么要两端同时抓呢?请考虑图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的总数量统计。
我们可以把SYN flood看作TCP协议的设计缺陷,有办法可以防御,却无法根除。想知道大公司都是怎样防御的吗?手段有很多,其中有一些还可以在Wireshark中看出端倪。我假装攻击了全球最大的假药销售网站,然后把全过程的包抓下来。从图10可见,对方很快就识别了我的不良意图,所以Reset(RST)了大多数握手请求。如果有兴趣去研究RST包里的细节,比如网络层的TTL和Identification,也许还能判断出究竟是流量清洗还是TCP握手代理之类的。本书不是网络安全专著,所以就不展开分析了。
本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。