Linux 网络:tcpdump 抓包示例

1. 前言

限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。

2. TCP 状态机

在这里插入图片描述

3. tcpdump 工作原理概述

在这里插入图片描述
tcpdump 通过 AF_PACKET 类型套接字、在 数据链路层(图中 NIC 处) 抓取进出数据包。在数据从网卡(NIC) 进入时,首先送入到抓包 socket 缓冲,然后再送入到网络协议栈送入到抓包 socket 缓冲的数据再经 BPF 钩子过滤后(如果 tcpdump 设置了过滤器),最终传递到 tcpdump。在数据从应用层往外发送 时,数据首先经过网络协议栈(假定数据在经过协议栈的过程中没被过滤掉),然后先送入抓包 socket 缓冲,再传递给网卡发送出去
从上述说明,我们了解到 tcpdump 是从 数据链路层 抓取数据,因此 tcpdump 能抓取所有进入网卡的数据,即使目的 MAC 地址不是网卡的数据。对于支持混杂模式的网卡,也可以开启混杂模式来抓取(在不开启混杂模式的情形下,网卡硬件电路会过滤掉目标 MAC 不是自身的包,广播包除外)。而对于发送出去的数据,如果还没有到达数据链路层之前就被过滤掉了(譬如被防火墙过滤的包等情形),tcpdump 将抓取不到它们。

4. tcpdump 常见选项说明

4.1 不将 IP 地址 转换为 主机名: -n

有时候我们发现,从 tcpdump 抓包开始到有内容输出,会存在一段时间的延迟。如果没有指定 -n 选项的话,可能 tcpdump 可能在查询 DNS 服务器将 IP 地址转换为主机名,这可能消耗很长的时间,导致输出的延迟。在不关心主机名的情形,加上 -n 选项,可以避免这种情形。相信大家使用 route 命令也会有相同的体验,直接使用 route 有时候会有很长的延迟,如果是使用 route -n 就可以避免这种延迟。

4.2 显示绝对序列号: -S

可以用 -S 选项显示 绝对(absolute)序列号,而不是 相对(relative)序列号

4.3 抓每个包的部分内容: -s

如果我们不想抓每个包的所有内容,可以用 -s 选项抓包的部分内容,譬如我们只抓取 以太网帧头 + IP 头,以减少抓包时间。默认抓包的长度为 262144 字节。

4.4 更多选项

更多选项请参考 tcpdump 官方链接:https://www.tcpdump.org/manpages/tcpdump.1.html

5. tcpdump 抓包示例

5.1 三握四挥 和 数据收发

5.1.1 抓连接握手包:三次握手

在这里插入图片描述
上图所示 TCP连接建立过程 如下:

1. 客户端 发送 序号为 x 的 SYN 请求给服务端;
2. 服务端 以 序号为 y 的 SYN 请求、确认号为 x+1 的 ACK 回应客户端的 SYN 请求;
3. 客户端 再回应 服务端 序号为 y 的 SYN 请求一个 ACK,ACK 的 序列号为 x+1, 确认号为 y+1 。

应该了解的是:包的序列号 seq 是 服务端 和 客户端 独自维护的,而回应给对端的 ack 的编号,是对端发送过来包的 seq + 1 。看实际 TCP连接建立过程 抓包例子(只截取了握手信息):

# tcpdump -xx -vvv -A -S tcp and host 192.168.10.211
[  162.969323] device eth0 entered promiscuous mode
tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
192.168.10.211.56925 > 192.168.10.198.8000: Flags [S], cksum 0xe487 (correct), seq 2305192361, win 64240, options [mss 1460,nop,wscale 8,nop,nop,sackOK], length 0
192.168.10.198.8000 > 192.168.10.211.56925: Flags [S.], cksum 0x738b (correct), seq 3370362890, ack 2305192362, win 64240, options [mss 1460,nop,nop,sackOK,nop,wscale 5], length 0
192.168.10.211.56925 > 192.168.10.198.8000: Flags [.], cksum 0x8f38 (correct), seq 2305192362, ack 3370362891, win 8212, length 0

从上面看到,有两台机器,IP 分别为 192.168.10.211192.168.10.198192.168.10.198 为 服务端,192.168.10.211 为客户端。> 指示了数据通信方向,如 192.168.10.211.56925 > 192.168.10.198.8000 表示 192.168.10.211192.168.10.198 发送数据。分析下抓包数据:

1. `Flags [S]` 标记 客户端 向服务端 发起连接 `SYN` 请求,即前面图中 TCP连接过程 中的 步骤1;
2. `[S.]` 标记 服务端 对 客户端 `SYN` 请求回应的 `ACK`,以及服务端发往客户端 SYN 请求,即前面
   图中 TCP连接过程 中的 步骤2;
3. `[.]` 标记 客户端回应服务端的 SYN 请求一个ACK,即前面图中 TCP连接过程 中的 步骤3。

5.1.2 抓数据包示例

在这里插入图片描述

192.168.10.211.56925 > 192.168.10.198.8000: Flags [P.], cksum 0x7121 (correct), seq 2305192362:2305192531, ack 3370362891, win 8212, length 169
192.168.10.198.8000 > 192.168.10.211.56925: Flags [.], cksum 0xa6d0 (correct), seq 3370362891, ack 2305192531, win 2003, length 0

5.1.3 抓终结连接:四次挥手

在这里插入图片描述

1. 客户端 调用 close() 主动关闭连接,向服务端发送序列号为 x 的 FIN 包;
2. 服务端 回应 客户端 序列号为 y、确认号为 x+1 的 ACK 。
3. 服务端 调用 close() 向 客户端 发送 序列号为 z、确认号为 x+1 的 FIN 包;
4. 客服端 回应 服务端 序列号为 x+1、确认号为 z+1 的 ACK,然后进入 TIME-WAIT 等待,
   超时后进入 CLOSED 终态。

数据抓包如下:

192.168.10.198.8000 > 192.168.10.211.57040: Flags [F.], cksum 0x941f (correct), seq 3223361884, ack 4164693292, win 2003, length 0
192.168.10.211.57040 > 192.168.10.198.8000: Flags [.], cksum 0x7bdf (correct), seq 4164693292, ack 3223361885, win 8211, length 0
192.168.10.211.57040 > 192.168.10.198.8000: Flags [F.], cksum 0x7bde (correct), seq 4164693292, ack 3223361885, win 8211, length 0
192.168.10.198.8000 > 192.168.10.211.57040: Flags [.], cksum 0x941e (correct), seq 3223361885, ack 4164693293, win 2003, length 0

其中,[F.] 标记带确认序号的 FIN 包,而 [.] 标记对 FIN 包的回应。

如果想了解 TCP 握手和挥手的内部细节,可参考博文 Linux:TCP三握四挥简析

5.2 零窗口 抓包

网络通信对端设备可能有着不同的硬件资源(CPU,内存,网卡,磁盘等)、不同的系统负载,这些都可能导致双方通信时发送和接收数据之间存在速度上的差异。TCP 协议中有一个 滑动窗口,其目的之一就是为了处理通信双发收发数据速度差异的问题,其工作原理简单来讲,就是通信双方的 socket 维护统计各自的收发缓冲(窗口)可用空间大小收到数据的一方在回复对方 ACK 时带上自己当前可用缓冲(窗口)大小,发送方根据接收方回复的当前可用缓冲(窗口)大小,来调整数据发送的数量。这就是所谓的 滑动窗口,很形象,一个动态变化的窗口。
当接收方处理数据不及时,将会导致接收方的缓冲(窗口)变小直至为 0,这时侯接收方如果再收到发送方的数据,会回复发送方一个 零窗口(Zero Window) 信息。看一下 tcpdump 抓包信息:

$ sudo tcpdump -# -S -vvv -w client.cap 'tcp and host 192.168.1.89'
......
   50  15:50:52.591981 IP (tos 0x0, ttl 64, id 31689, offset 0, flags [DF], proto TCP (6), length 2916)
    192.168.1.201.35320 > 192.168.1.89.8888: Flags [.], cksum 0x8fc9 (incorrect -> 0xca38), seq 4072327897:4072330761, ack 2817502359, win 502, options [nop,nop,TS val 1683157335 ecr 147045879], length 2864
   51  15:50:52.634926 IP (tos 0x0, ttl 64, id 31691, offset 0, flags [DF], proto TCP (6), length 1468)
    192.168.1.201.35320 > 192.168.1.89.8888: Flags [.], cksum 0x8a21 (incorrect -> 0x0405), seq 4072329345:4072330761, ack 2817502359, win 502, options [nop,nop,TS val 1683157378 ecr 147045879], length 1416
   52  15:50:52.635450 IP (tos 0x0, ttl 64, id 35240, offset 0, flags [DF], proto TCP (6), length 64)
    192.168.1.89.8888 > 192.168.1.201.35320: Flags [.], cksum 0x49a5 (correct), seq 2817502359, ack 4072330761, win 0, options [nop,nop,TS val 147045922 ecr 1683157335,nop,nop,sack 1 {4072329345:4072330761}], length 0
......

上面是 192.168.1.89.8888 作为数据接收方192.168.1.201.35320 作为数据发送方,接收方一直不从 socket 缓冲 读取数据,导致了最后接收缓冲耗尽,再有数据来时,只能向发送方回复 零窗口 信息(看 52 开头这行的 win 0 信息)。从这个抓包数据看起来可能不那么清晰,我们用 WireShark 来解析一下,看起来就一目了然了:
在这里插入图片描述

6. 参考资料

[1] https://www.rfc-editor.org/rfc/rfc793
[2] https://blog.csdn.net/vnjohn/article/details/129245099

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值