gitbook/网络排查案例课/docs/501696.md
2022-09-03 22:05:03 +08:00

424 lines
20 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 25 | 抓包分析的回顾、拾遗,和提高
你好,我是胜辉。
在完成了三个实战模块之后我们已经把三层以上也就是网络层、传输层、应用层等的排查技术都比较完整地学习了一遍。在二十多节课里我们学习了对TCP的各种行为比如握手、挥手、拥塞、重传等行为进行排查的技巧也对tcpdump和Wireshark进行了深度使用。
除了这些技巧以外我们更是在TLS加解密和应用层HTTP协议等理论知识方面做了不少深入的研究。我想很多工具的使用技巧、案例的排查思路已经在我们的脑海中回荡那么如果我们来一次系统性的总结和提高对我们的学习效果一定是一种更大的促进。
所以在这节课里,我们就来对过去的二十多讲进行一次回顾、总结和提高吧。
## tcpdump和tshark等命令行工具的技巧
tcpdump是我们用得最多的抓包工具其中的基本技巧可以汇总为以下几个方面。
### tcpdump
我们做抓包一般都需要指定过滤条件这样才能保证对系统的CPU、内存、硬盘等资源不产生过大的影响。这里说的过滤条件又分基础参数和真正的过滤条件我们分别来看一下。
#### 基础参数
这类基础参数可能不算是用来过滤报文本身的参数,它们一般用于指定抓包的网口、报文长度等等。我们来逐个看一下。
要限定网络接口,可以用-i参数。比如
```bash
tcpdump -i eth0
```
> 补充:这里还有个小的注意点。当我们用 `-i any` 的时候,抓到的报文就不是标准以太网帧头格式了,这一点你需要知道一下。
如果我们要查看抓包过程中的详细信息,下面这三种参数任你选择:
```bash
tcpdump -v #提供TTL等信息
tcpdump -vv #提供更多信息
tcpdump -vvv #提供最详细的信息
```
> 补充:如果你还是用 `-w file.pcap` 存入了文件,加上 `-v` 参数可以每10秒打印一次抓取的报文数量。
默认情况下tcpdump会对IP进行反向域名查询等操作这些DNS查询等行为可能影响抓包的效率。这时候就可以加上 `-n` 参数:
```bash
tcpdump -n
```
为了节约抓包成本我们经常会指定要抓取的每个报文的长度。比如假如TCP没有启用扩展头部那么指定54字节即可抓取到从二层帧头部到TCP头部的这些信息了。
```bash
tcpdump -s 54
```
#### tcpdump过滤条件
抓包的过滤条件当然是重中之重的技巧了,这里我们再复习一下。
要限定IP可以用下面的过滤器
```bash
tcpdump host 10.10.10.10
tcpdump dst host 10.10.10.10
tcpdump src host 10.10.10.11
```
要限定端口,可以用这个:
```bash
tcpdump port 22
```
我们有时候也需要从已有的抓包文件中过滤出报文,然后存入一个新的文件。比如下面的例子:
```bash
tcpdump -r file.pcap 'tcp[tcpflags] & (tcp-rst) != 0' -w rst.pcap
```
### tshark
tshark是一个跟随Wireshark一起安装进系统的工具类似情况的工具还有editcap、mergecap、capinfos等等算是Wireshark大礼包了。这些工具都有很强大的功能这个大礼包真是物超所值。
我们先看tshark。在课程中我们主要用tshark实现了三个不同的需求场景。
第一个场景是**统计文件中的HTTP状态码**。我们可以到[Gitee](https://gitee.com/steelvictor/network-analysis/tree/master/17)里找到相关的抓包示例文件,然后运行下面的命令:
```bash
tshark -r lesson17-in-shorten.pcap -T fields -e http.response.code | grep -v ^$ | sort | uniq -c | sort -r
```
输出如下:
```bash
2931 200
 704 502
 227 304
 141 400
  45 301
  41 302
  16 408
  14 403
   6 503
   6 404
   2 206
```
可见HTTP状态码都非常整体地统计展现出来了。所以我们做抓包分析不仅要熟练掌握Wireshark同时也应该多了解这些命令行工具它们经常可以提供Wireshark以外的一种良好的补充。
第二个场景是**解析文件中的HTTP事务的耗时**。比如我们可以用下面的命令:
```bash
tshark -r 文件名 -T fields -e http.time | grep -v ^$
```
第三个场景是在找到HTTP耗时最高的事务然后找这个**事务所在的整个TCP流的所有报文**,我们可以用下面的命令:
```bash
tshark -r 文件名 -T fields -e frame.number -e http.time -e tcp.stream | sort -k2 -r | head -1 | awk '{print $3}' | xargs -n 1 -I {} tshark -r captured.pcap -Y "tcp.stream eq {}"
```
这个命令比较长,用到了多次管道符,特别是最后一个管道符后面,使用了 `tshark -Y "tcp.stream eq xx"`而这个过滤器就是把某个特定的TCP流给完整地展示出来这样的话我们不仅可以找到HTTP耗时最高的事务而且这个事务的完整的TCP流里的报文都展示了出来方便我们做进一步的分析。
tshark的功能有很多比如它还可以查看TCP初始往返时间
```bash
tshark -r file.cap -T fields -e tcp.analysis.initial_rtt | grep -v ^$
```
也可以统计TCP重传包的数量
```bash
tshark -n -q -r file.pcap -z "io,stat,0,tcp.analysis.retransmission"
```
最后tshark其实也经常用来直接抓包这时候它跟tcpdump是差不多的。比如下面这样
```bash
tshark -i "Wireless Network Connection" -w file.pcap host 123.45.66.77
```
### capinfos
这个工具主要是用来获取抓包文件的整体信息,比如我们使用下面这个命令,就获取到了抓包文件的报文数、文件大小、抓包时长等丰富的信息。
```bash
$ capinfos lesson17-in-shorten.pcap
File name:           lesson17-in-shorten.pcap
File type:           Wireshark/tcpdump/... - pcap
File encapsulation:  Ethernet
File timestamp precision:  microseconds (6)
Packet size limit:   file hdr: 65535 bytes
Packet size limit:   inferred: 150 bytes
Number of packets:   88 k
File size:           9769 kB
Data size:           115 MB
Capture duration:    297.564908 seconds
......
```
它的功能跟Wireshark里Statistics下拉菜单里的Capture File Properties是类似的
![图片](https://static001.geekbang.org/resource/image/1f/65/1ffa6ed19402ed396364c828b38bf065.png?wh=298x177)
### editcap
有时候我们需要传递抓包文件,同时又不想透露应用层数据等敏感信息,那么一个简便的做法,就是直接修改抓包文件中每个报文的长度。前面说过,`tcpdump -s` 是可以指定抓包大小的,而即使文件已经生成了,我们还是可以**通过editcap名把它改小**。是不是挺方便的?
比如要把原始文件 `old.pcap` 的每个报文截短为54字节可以执行下面的命令
```bash
editcap -s 54 old.pcap new.pcap
```
另外editcap也可以用来把TLS key文件跟抓包文件合并在一起这样你在分享文件的时候就不需要传送两个文件了而是一个合并过的文件就可以。比如下面的命令
```bash
editcap --inject-secrets tls,key.log in.pcap out.pcap
```
> 注意:命令中的 `tls` 跟后面的 `key.log` 文件名之间有一个逗号,虽然略有点奇怪,但这就是它的格式。
## Wireshark的技巧
Wireshark可以算是我们课程中最闪亮的明珠了。不过很多同学在学习这门课之前可能对Wireshark的了解很少一打开文件就晕了心里只有一个念头“不明觉厉”。当然通过课程的学习相信你对这方面已经积累了相当不错的经验。如果你现在看到Wireshark窗口甚至有“亲切”的感觉那就对了说明你有了长足的进步已经真正跟Wireshark成为密友了。
这里我们再来简单回顾一下相关的技巧。
### Wireshark的解读技巧
在解读抓包文件时第一步一般可以查看Expert Information。这个信息的解读方法是这样的
* Warning条目的底色是黄色意味着可能有问题应重点关注。
* Note条目的底色是浅蓝色是在允许范围内的小问题也要关注。
* Chat条目的底色是正常蓝色属于TCP/UDP的正常行为比如这次通信里TCP握手和挥手分别有多少次等可以作为参考。
* 一般来说,乱序可以重点关注。
在解读完Expert Information之后我们会找到可疑的报文展开进一步的分析。此时我们用得最多的技巧可能就是**Follow TCP Stream**了。我们可以选中一个报文后右单击然后选择Follow在二级菜单中选择TCP Stream这样就来到了这个报文所在的TCP流。基本上每次做抓包分析都会用到这一步的操作。
![图片](https://static001.geekbang.org/resource/image/7f/yy/7f82e0a848203641b591cbb7e1de76yy.png?wh=747x519)
另外Wireshark默认展示的列经常不能满足我们的需求所以我们也要学会**添加自定义列**的方法。简单来说就是选择一个报文后进入它的详情部分界面下方然后选中某一个属性右单击选择Apply as Column即可。比如下面这样
![图片](https://static001.geekbang.org/resource/image/5d/4a/5d3f3de2c419fd0ae2be8fc4085b754a.jpg?wh=819x416)
上图中我们通过添加TTL自定义列就可以让每个报文的TTL值都在主视图中展现极大地方便了对这些TTL的比较。所以我们除了掌握协议知识以外也要挖掘各类工具的使用技巧。所谓“工欲善其事必先利其器”也。
另外,在排查中,**时间**这个信息也是十分重要的。根据场景的不同我们需要不同的Time列的表示方式。比如
* 当我们关注**前后报文间的间隔时间**时我们会选择Delta time或者Delta time displayed。
* 当我们关注**跨度比较大的报文间隔**时最好选择Absolute time或者另外两个Absolute date的形式。
![图片](https://static001.geekbang.org/resource/image/bc/d9/bce1f5aa452d84c742dc6d9a119699d9.jpg?wh=602x195)
### 对TCP提示的解读
Wireshark很方便也很强大但如果我们脱离了对网络协议的理解那其实还是无从下手。比如我们做得最多的TCP排查就需要结合自己对TCP的掌握才能做好解读。
举个例子。同样是Wireshark关于TCP窗口方面的提示TCP Window Full跟TCP Zero Window都是什么含义有什么差别呢像这样的例子很多如果你真正地从Wireshark给你的众多信息中获取了有效的线索那你的排查能力必定有一个明显的提升了。
#### TCP Window相关的信息
就TCP Window Full而言它的意思是**一端的在途字节数等于另一端的接收窗口**。Wireshark会根据发送出去的数据量和已经确认的数量计算出在途字节数然后跟另一端的接收窗口进行比较。如果两者相等说明另一端的接收窗口已经被用满了。这个对于排查TCP传输速度相关的问题是很有帮助的。
然后是TCP Zero Window这个比较简单就是**接收窗口为零**。这是主动通告对端“自己的接收窗口已经为零不要再发送数据了”。所以你能看出来它跟TCP Window Full的区别了吗
它们的**区别**是TCP Zero Window是一个体现在TCP报文里的信息算是主动“投降”。而TCP Window Full不是在报文中的信息它是Wireshark自己分析出来的结论。知道了两者的区别相信你也知道在相应的场景下该如何结合这种解读来帮助排查了。
#### TCP传输状况信息
关于TCP传输速度也是一个热门话题我们在第9~11讲都做了比较深入的探讨。在Wireshark里我们可以利用下面几个图表来帮助排查。
* I/O Graph这个可以看到IP报文级别的传输速度。
* TCP Stream Graphs这里又分了几种子图表分别是
* Time Sequence (Stevens)查看TCP序列号随着时间的变化趋势。
* Throughput查看传输数据量的变化趋势。
* Round Trip Time查看传输中RTT的变化。
* Window Scaling查看接收窗口在传输中的变化还可以直观地找到TCP Window Full事件。
你可以在Statistics下拉菜单中找到上面的这些工具。
![图片](https://static001.geekbang.org/resource/image/e9/b3/e94dd4yydeb31d9f1f19511fdc1a3ab3.jpg?wh=457x101)
### Wireshark过滤器
过滤器这一块也是很丰富且很有价值的内容。有时候,能否写出一个高效准确的过滤器,几乎可以当做是区分我们抓包分析水准的量尺,所以对过滤器再重视也不为过。下面我们来回顾几个典型的过滤器。
在**匹配字符串**的时候,我们可以有以下这样的好几种选择,分别在不同的分层上实现了文本过滤。
```bash
tcp contains "abc"
ip contains "abc"
http contains "abc"
```
那如果要**匹配二进制数据**该如何做到呢我们知道每个字节是8位Wireshark用两个十六进制数字表示一个字节我们在每个字节之间加上破折号就可以了。比如下面这样也可以搜到带“abc”的报文
```bash
tcp.payload contains 61-62-63
```
当我们要根据TCP报文的标志位进行过滤的时候就可以用下面这种过滤器
```bash
tcp.flags.reset eq 1 #找到RST报文
tcp.flags.syn eq 1 #找到握手的SYN报文
tcp.flags.fin eq 1 #找到挥手的FIN报文
```
我们还可以根据时间匹配来过滤报文,比如:
```bash
frame.time >="Mar 28, 2022 00:00:00"
```
#### tcp.analysis类过滤器
此外Wireshark的过滤器中还有一个非常重要的部分是TCP分析器tcp.analysis当你在Wiresahrk过滤器栏输入tcp.analysis后就自动有很多的过滤器提示出来。这些过滤器经常能起到很大的帮助因为它们大多不是直接的报文内容而是从报文中推导出来的信息已经包含了一定的分析价值。
比如下面这个过滤器可以找到超过200ms才发回的确认报文
```bash
tcp.analysis.ack_rtt >0.2 and tcp.len == 0
```
当我们要找到所有的TCP Window Full的报文的时候就可以输入
```bash
tcp.analysis.window_full
```
更多的tcp.analysis过滤器你可以自己去Wireshark里摸索一下相信你会有很大的收获。
## 排查技巧
其实,网络排查很多人都在做,也都会抓包,那为什么不是每个人都可以从抓包文件中分析出有效的信息来呢?可能关键就在于我课程里提到过的**两大鸿沟**。
* 应用现象跟网络现象之间的鸿沟:你可能看得懂应用层的日志,但是不知道网络上具体发生了什么。
* 工具提示跟协议理解之间的鸿沟你看得懂Wireshark、tcpdump这类工具的输出信息的含义但就是无法真正地把它们跟你对协议的理解对应起来。
为了突破第一个鸿沟,我们需要熟悉抓包技术,知道什么时候抓包、抓哪些包,然后也有能力把抓包文件中的信息,跟应用层日志中的信息对应起来。
为了突破第二个鸿沟我们需要深刻理解网络协议知道TCP、IP、HTTP这些协议的行为和脾性然后结合Wireshark的各种技巧把网络协议跟实际现象结合起来从而推进排查工作。
当然,填平这两个鸿沟只是我们的目标,而手段就是这里要讨论的排查技巧了。这里的内容也比较多,我选了几个典型场景和思路,希望对你有所启发。
## 逐段测试法
我们经常会遇到一个请求从开始到结束会经过很多环节的情况,比如:
> 客户端-> 第四层LB -> 第七层LB -> 服务端
在这种时候,我们可以做逐段测试,比如从客户端直接访问服务端,这样可以很快地确定中间这两个环节是否跟问题有直接关系了。比如像下面这样:
![](https://static001.geekbang.org/resource/image/5d/0e/5d65cc33e0dcac560610779f92c2070e.jpg?wh=2000x435)
### 抓包分析思路
在进入抓包分析阶段后,从经验性的排查思路这个角度来说,一般的抓包分析可以用我们在[第5讲“定位防火墙”](https://time.geekbang.org/column/article/481042)中提到过的步骤,也就是:
* 查看 Expert Information
* 重点关注可疑报文比如Warining级别追踪其整个TCP流
* 深入分析这个可疑TCP流的第二到四层的报文再结合应用层表象综合分析其根因
* 结合两侧的抓包文件找到属于同一个TCP流的数据包对比分析得出结论。
下图就概括了这个过程,你可以来参考一下:
![](https://static001.geekbang.org/resource/image/dd/ac/dd1958be82b3ea019ffef41ffbc120ac.jpg?wh=2000x360)
### 整数值
在有整数值出现的时候,我们需要提起精神,务必重点调查这个整数值背后的原因。因为一般来说,这往往意味着**有人为的设置**在里面,比如某种客户端超时设置。这些设置经常会跟问题有直接或间接的关系。
比如在[第15讲](https://time.geekbang.org/column/article/488979)我们就发现客户端有5秒超时的机制并在Wireshark里体现了这一点。
![图片](https://static001.geekbang.org/resource/image/ea/cb/eab1ef276008a85d53f6a222034b89cb.jpg?wh=827x221)
### 偶发性问题
对于偶发性问题,我们可以采用这样的策略:
> 预估->开始抓包和观察->问题重现->停止抓包->分析
下图概括了这个过程,供你参考:
![](https://static001.geekbang.org/resource/image/2a/dd/2aa3b64b995d21037cb9323ccc57d9dd.jpg?wh=2000x1125)
### 对比分析
还有一个很关键的技术是“对比分析”。我们做抓包分析,经常要在多处抓包后做对比分析。比如以下两种典型场景:
* 同一个TCP流在客户端和服务端的抓包文件
* LB前后不同TCP连接的抓包文件。
对于第一种场景,我们可以**用报文本身的字段**作为匹配条件因为属于同一个TCP流它们的这些属性字段值一定不会变化。比如用裸序列号原始序列号像下面的过滤器
```bash
tcp.seq_raw eq 123456
```
找到同一个TCP流之后就可以把两个Wireshark窗口都打开放在一起进行比较。你可以回顾下第5讲的案例参考我们是如何做对比分析的。
![图片](https://static001.geekbang.org/resource/image/e8/94/e8c1561009a05c1c9523dbef2fd8bb94.png?wh=1303x303)
而对于第二种场景TCP连接就是完全不同的了所以无法像上面第一种场景那样把TCP报文里的字段值作为关联映射的条件。我们一般可以**寻找应用层的特征**比如某个uuid然后运用Wireshark过滤器在两侧不同TCP连接的抓包文件中找到同样包含这个uuid的报文。比如这些过滤器
```bash
http contains "uuidxxxxx"
tcp contains "uuidxxxxx"
ip contains "uuidxxxxx"
frame contains "uuidxxxxx"
```
## 小结
这节课,我们是对整个课程中,不少抓包分析的技术细节进行了回顾。我在[春节特别放送(三)](https://time.geekbang.org/column/article/484358)里其实提到过思维导图是一个很好的学习工具所以我就汇总整理了专栏中的核心内容。因为内容也比较多我分为了4个部分来分别展示你可以通过它们快速找到你需要的知识点。
* **排查技术**
![](https://static001.geekbang.org/resource/image/f0/c2/f034075fyybd5eccf3c61494dcf731c2.jpg?wh=4000x3615)
* **协议**
![](https://static001.geekbang.org/resource/image/22/fe/22b139be4e6a642ee0792152938c22fe.jpg?wh=4000x2482)
* **系统相关**
![](https://static001.geekbang.org/resource/image/c8/a3/c8d8628bdc9a7b5051b0bffddbb189a3.jpg?wh=4000x2493)
* **抓包分析**
![](https://static001.geekbang.org/resource/image/18/fb/18b39b2624bb23afd24f7fe52caf23fb.jpg?wh=4000x2022)
## 思考题
给你留两道思考题:
* 假设通信的一端发送了TCP Zero Window报文并且后续没有更多新的报文过来那么另一端是不是一直不能发送新的数据了呢
* 请写一个tshark命令用来过滤出抓包文件中的DupAck。
欢迎你把答案分享到留言区,我们一同进步、成长。