Introduction
Wireshark
作为网络分析的利器,在很多网络问题中,我们都可以游刃有余的解决问题。
但这并不意味着有了Wireshark
就万事大吉了,远远不够。
当我们抓到了感兴趣的包,按图索骥的探查问题,为了找到根因,一般来说,我们必须要克服这两个问题:
1、网络协议各层之间的鸿沟
2、Wireshark
提示与协议之间的鸿沟
你可能会想,oh no
,什么叫做鸿沟啊?为什么说有鸿沟呢?我怎么没有感觉到呢,下面请听我为您细细道来。
Gap 1、网络层与层
为了说明网络协议之间可能存在的鸿沟之前,我们需要回答一个问题:网络为什么要分层?
计算机网络的目的是提供端与端之间的通信。
比如redis
客户端与redis
服务器、mysql
客户端与mysql
服务器等类似的事物,想要进行网络通信,如果不进行分层,那么redis、mysql
都需要一整套通信协议的实现,包括但不限于通信的连结方式、路由选择、传输可靠性和效率等功能。更可怕的是,等你有一种新的应用,你需要重新再搞一套。
但是一种新的服务,其实只有"应用层"的协议需要定制化,它所依赖的底层是不变的,只是重复的在造轮子。
所以网络分层好处多多。目前的做法就是各个应用实现自己的应用层协议,传输层以及网络层等协议的实现交给操作系统即可。
说完了网络分层的好处,现在来讲一下网络分层带来的问题,也就是网络曾与层之间的"鸿沟"。
为什么说有鸿沟呢?
比如很多时候传输层报错,并不会将详细信息传递给应用层,如果此时我们只能看应用层,就无法对问题就行断定。
Case:connection reset by peer
connection reset by peer
这是一个nginx
常见的报错问题。但正如字面所言,我们只知道连接被断掉,我们不知道为什么会断开连接?服务端逻辑是否处理完毕?(没错有时候虽然connection reset by peer
,但并不会影响服务哦)
仔细观察图中的数据包,我们可以得到:
1.11022
号包,client
发送POST
请求
2.11446
号包,server
发送响应,表示完成这次处理
3.11448
号包,client
居然发送了一个RST
最起码这次请求被服务端完美的处理了,但是client
居然马上就rst
掉。
我们需要继续查看client
代码才能确定是否影响了本次请求。如果没有抓包,我们很可能得出是服务端直接拒绝了请求,或者服务端没有处理完毕本次请求。
Gap 2、Wireshark提示与协议
这一部分说的是工具提示跟协议理解之间的鸿沟。
比如wireshark
展示的提示与网络协议本身之间是存在知识壁垒的。
Case:ICMP显式port字段
ICMP
是网络层协议,它没有、也不应该有上层协议------传输层的port
字段。
但是还真发现了!
是不是有些凌乱,身为网络层协议的ICMP
居然先是端口号为80
!
其实也没有那么神奇,这只是wireshark
的展示策略,我们点开2
号包的详情即可
原来只是icmp
包的payload
携带了1
号包的内容,然后wireshark
解析的时候才会在icmp
协议中展示端口号。
Case:只有一次挥手的"四次挥手"
我们先来复习一下四次挥手的过程。
但是有时候,你会抓到只有"一次"FIN报文的挥手过程。比如下图:
不论再怎么仔细观察这几个包,你都会发现,只有在7号包中你才能发现FIN
报文标志。
挥手阶段不是得有两个FIN
报文吗?难道网络的水太深,我们摸不准?
不是的。
Wireshark
展示报文细节时,有一个规定:Info
列优先展示应用层的信息。
我们查看6
号包的详情
原来这个FIN
报文搭了一次便车。
真实的回收过程如下:
Case:发送超过对方接收窗口的数据
请看这个例子,端口为47390
的一端声称自己的接收窗口大小为"190
"字节,然后立马另一端给它发送了308
字节的数据。
啊?
冷静一下,冷静一下。TCP
的实现绝不是如此,仔细想一下,接收窗口大小有什么决定呢?
TCP
协议头的Window
但这就是故事的全部吗?
并不是,还有TCP Options
中的window scale
。
首先让我们来看看window scale
的目的:
The TCP window scale option is an option to increase the receive window size allowed in Transmission Control Protocol above its former maximum value of 65,535 bytes. This TCP option, along with several others, is defined in RFC 7323 which deals with long fat networks (LFNs). ------ wikipedia
也就是随着现代网络的建设,为了应对大带宽高延迟的场景,TCP
协议头中window
字段已经不够用了。因为它只有2
字节长,接收窗口最多为65535
个字节。所以为了声明更大的接收窗口,只能在TCP Options
动动手脚了,这就是window scale
的由来。
下面是一个window scale
的例子
上述的值表示接收窗口为TCP
头部里面window
的大小乘以4
。
然后回到我们开始的例子中来,发现原来是没有抓到三次握手的包。
没有抓到三次握手的包,有什么问题吗?
问题大了,window scale
是否开启、开启的值大小,只在三次握手中传递。
假如我们并没有抓到三次握手的包,我们无从得知window scale
的值大小,wireshark
也就不能够将window
的值乘以window scale
,以此得到最终的接收窗口大小了。
如果不熟悉tcp
协议以及wireshark
的展示,你可能会大声疾呼计算机网络的水太深了!哈哈。
Summary
- 很多时候,只有应用层的日志不能够解决甚至定位问题,还需要抓取网络层和传输控制层的数据包,综合一起来看才能顺利解决问题。
wireshark
的提示与协议本身之间是有理解成本的,需要多多使用wireshark
进行抓包,反复练习,摸清楚wireshark
的脾气。
这两大鸿沟的说法来自于极客时间的一门课《网络排查案例课》(对我来说,这是极客时间上最精彩的一门课),我深表赞同。
我想之所以如此,那是因为即便Wireshark
是一门利器,考虑到网络本身是如此的复杂,想要庖丁解牛般解决网络问题,不可不下功夫!
Reference
- 📚《TCP/IP Illustrated》
- 极客时间《网络排查案例课》