写点什么

跨平台应用开发进阶 (四十三) 一文走近网络层抓包工具:WhireShark

  • 2023-04-14
    上海
  • 本文字数:7457 字

    阅读完需:约 24 分钟

跨平台应用开发进阶(四十三)一文走近网络层抓包工具:WhireShark

一、前言

网络是移动应用生命线,网络层面的各种问题会给移动应用带来许多迷惑的行为和症状。通过抓取网络包数据,可以针对性地分析由网络层面问题引起的各种症状,包括连接中断TLS 握手失败DNS 解析失败等错误。


CharlesFiddler 可以帮助捕获和分析 HTTP 层面的问题,如果问题发生在 TCP/IP 层面,则需要 TCP 报文的捕获和分析工具。Wireshark(支持 Mac/Windows 平台)、Network Monitor(Windows 平台)和 TCPDUMP 是常用的三种网络层抓包工具。比较常见的网络层问题包括 SSL 握手失败TCP 链接中断重发等。


本节介绍 Wireshark基本使用方法。


wireshark是非常流行的网络封包分析软件,功能十分强大。可以截取各种网络封包,显示网络封包的详细信息。使用wireshark的人必须了解网络协议,否则就看不懂wireshark抓包信息。


为了安全考虑,wireshark只能查看封包,而不能修改封包的内容或者发送封包。 wireshark能获取HTTP,也能获取HTTPS,但是不能解密HTTPS。所以wireshark看不懂HTTPS中的内容。如果是处理HTTPHTTPS 还是用Fiddler,其他协议比如TCPUDP 就用wireshark

二、条件过滤

  • 过滤源 ip、目的 ip


  ip.dst==192.168.101.8 #查找目的地址为192.168.101.8的包    ip.src==1.1.1.1 #查找源地址为1.1.1.1 的包
复制代码


  • 端口过滤


  tcp.port==80 #把源端口和目的端口为80的都过滤出来    tcp.dstport==80 #只过滤目的端口为80的    tcp.srcport==80 #只过滤源端口为80的包
复制代码


  • 协议过滤


  arp #ARP协议    icmp || icmpv6 #ICMP协议    smb || nbss || nbns || nbipx || ipxsap || netbios #Server Message Block类协议    http || tcp.port == 80 || http2 #HTTP协议,这是很简陋的识别方法    tcp.flags & 0x02 || tcp.flags.fin == 1 #TCP连接的起始和关闭报文    hsrp || eigrp || ospf || bgp || cdp || vrrp || carp || gvrp || igmp || ismp #路由类协议    eth.fcs_bad==1 || ip.checksum_bad==1 || tcp.checksum_bad==1 || udp.checksum_bad==1 || sctp.checksum_bad==1 || mstp.checksum_bad==1 || cdp.checksum_bad==1 || edp.checksum_bad==1 || wlan.fcs_bad==1 #条件中的各类协议的checksum异常    ! ip.dst == 224.0.0.0/4 && ip.ttl < 5 && !pim) || (ip.dst == 224.0.0.0/24 && ip.dst != 224.0.0.251 && ip.ttl != 1 && !(vrrp || carp) #TTL异常报文    tcp.flags.reset eq 1 #TCP流被RESET报文    icmp.type eq 3 || icmp.type eq 4 || icmp.type eq 5 || icmp.type eq 11 || icmpv6.type eq 1 || icmpv6.type eq 2 || icmpv6.type eq 3 || icmpv6.type eq 4 #ICMP协议错误,协议的type字段值错误报文
复制代码


  • http 模式过滤


  http.request.method=="GET" #过滤get请求的包    http.request.method=="POST" #过滤post请求的包
复制代码


  • 两个过滤条件连接符 and 的使用


  ip.src==192.168.101.8 and http #过滤ip为192.168.101.8并且为http协议
复制代码


  • 过滤http握手的空报文

  • 使用 wireshark 打开 pcap 包,通过条件过滤数据长度为 0 的包,命令如下:


  tcp.len > 0
复制代码


  • 过滤重复数据包

  • 使用 cmd 命令窗口,进入 wireshark 安装目录,找到 editcap.exe 程序。执行 editcap.exe -d 命令,指定源文件(d:\input.pcap)和目标文件(d:\output.pcap),命令如下:


  C:\Program Files\Wireshark>editcap.exe -d d:\input.pcap d:\output.pcap
复制代码


  • 过滤 TCP 重传数据包

  • 使用 wireshark 打开 pcap 包,通过条件过滤 tcp.analysis.retransmission 的包,命令如下:


  http && !(tcp.analysis.retransmission)
复制代码


  • 过滤 TCP 解析错误数据包

  • 使用 wireshark 打开 pcap 包,通过条件过滤 TCP 重传,乱序,丢包,重复响应的包,命令如下:


  tcp.analysis.flags && !tcp.analysis.window_update
复制代码

三、字段含义

在 TCP 层,字段有以下⼏个标识:SYN、FIN、ACK、PSH、RST、URG。


它们的含义是:


  • SYN表⽰建⽴连接;

  • FIN表⽰关闭连接;

  • ACK表⽰响应;

  • PSH表⽰有数据传输;

  • RST表⽰连接重置。

  • URG:Urget pointer is valid (紧急指针字段值有效)


其中,ACK是可能与SYNFIN等同时使⽤的,⽐如SYNACK可能同时为 1,它表⽰的就是建⽴连接之后的响应,如果只是单个的⼀个SYN,它表⽰的只是建⽴连接。TCP 的⼏次握⼿就是通过这样的ACK表现出来的。但 SYN 与 FIN 是不会同时为 1 的,因为前者表⽰的是建⽴连接,⽽后者表⽰的是断开连接。


RST⼀般是在FIN之后才会出现为 1 的情况,表⽰的是连接重置。⼀般地,当出现FIN包或RST包时,我们便认为客户端与服务器端断开了连接;⽽当出现SYNSYN+ACK包时,我们认为客户端与服务器建⽴了⼀个连接。PSH为 1 的情况,⼀般只出现在 DATA 内容不为 0 的包中,也就是说PSH为 1 表⽰的是有真正的 TCP 数据包内容被传递。


wireshark 抓包过滤条件:


(ip.src == 127.0.0.1) && (tcp.srcport == 27015 || tcp.dstport == 27015) && (tcp.flags.push == 1)
复制代码

四、TCP 连接

三次握手 Three-way Handshake



一个虚拟连接的建立是通过三次握手来实现。


  1. (B) --> [SYN] --> (A)

  2. 假如服务器 A 和客户机 B 通讯. 当 A 要和 B 通信时,B 首先向 A 发一个SYN (Synchronize) 标记的包,告诉 A 请求建立连接.。

  3. 注意⚠️: 一个 SYN包就是仅SYN标记设为 1 的 TCP 包(参见 TCP 包头 Resources)。认识到这点很重要,只有当 A 受到 B 发来的 SYN 包,才可建立连接,除此之外别无他法。因此,如果你的防火墙丢弃所有的发往外网接口的 SYN 包,那么你将不 能让外部任何主机主动建立连接。

  4. (B) <-- [SYN/ACK] <--(A)

  5. 接着,A 收到后会发一个对 SYN 包的确认包(SYN/ACK)回去,表示对第一个SYN包的确认,并继续握手操作。

  6. 注意⚠️: SYN/ACK包是仅 SYN 和 ACK 标记为 1 的包。

  7. (B) --> [ACK] --> (A)

  8. B 收到SYN/ACK 包,B 发一个确认包(ACK),通知 A 连接已建立。至此,三次握手完成,一个 TCP 连接完成。

  9. 注意⚠️: ACK 包就是仅 ACK 标记设为 1 的 TCP 包。需要注意的是当三此握手完成、连接建立以后,TCP 连接的每个包都会设置 ACK 位。


这就是为何连接跟踪很重要的原因了。没有连接跟踪,防火墙将无法判断收到的 ACK 包是否属于一个已经建立的连接。一般的包过滤(Ipchains)收到 ACK 包时,会让它通过(这绝对不是个好主意)。而当状态型防火墙收到此种包时,它会先在连接表中查找是否属于哪个已建连接,否则丢弃该包。

4.1 三次握手示例

通过 TCP 三次握手:SYN-SYN ACK-ACK,建立连接以抓取 443 为例(加密,端口不一定为 443):



先:DNS 请求


DNS 请求:



DNS response:



客户端发起 TCP 三次握手:



第一次:SYN=1,ACK=0,端口 61020–443



第二次:SYN=1,ACK=0+1,端口 443-61020,确认序号=序列号+1



第三次:ACK=1,端口 61020–443



Client 发送 hello 包:



  • Random:随机生成数,用于生成最终密钥

  • Session ID:会话标识符

  • Cipher Suites:加密套件,

  • Compression Merhods:压缩方法 Server hello:



服务器也生成了一个随机数发送给客户端,双方同时拥有两个随机数服务器返回证书,客户端收到后根据证书链辨别真伪,服务器中有公钥,用于加密后面生成的 Prenaster secret(会话密钥)安全连接建立,发送数据:Application Data


TLS 传输过程:



①-④:握手阶段⑤:握手后双方使用协商好的密钥进行通讯②中有多个类型,是因为它是一个多握手信息,一次性发送多个握手协议包 SNI:TLS 的扩展,用来解决一个服务器拥有多个域名的情况 TLS 握手信息中并不携带客户端要访问的目标地址,若一台服务器用多个虚拟主机,且域名不同,使用了不一样的证书,TLS 使用添加 host 的方法识别访问那台虚拟主机,在握手第一阶段 ClientHello 的报文中添加 SNI 中包含 Server NAME,即 Host 内容。

五、色彩规则


黑色:报文错误(TCP 解析错误、重传、乱序、丢包、重复响应)



  • TCP dup ack:重复应答

  • TCP Retransmission:TCP 重传,TCP 有超时重传机制

  • TCP Otu-of-Order:乱序,网络拥塞导致包到达时间不同,时延长,导致包丢失

  • TCP Previous segment not captured:前一段未捕获,丢失

  • TCP Dup ACK:TCP 重复应答,#前表示丢失序号,后表示丢失次数

  • TCP Retransmission:TCP 重传

  • TCP ACKed unseen segment:报文没抓全,此报文是 ACK 报文

  • TCP ZeroWindow 与 TCP Window Full:

  • TCP ZeroWindow:告诉对方,我的接收窗口的大小,即出现时告诉对方不要在发送数据

  • TCP Window Full:当待发送数据为 0,出现 Full,表示我不能再发送数据了

  • HSRP State Change:HSRP(热备份协议),表示状态非 active 和 standby

  • Spanning Tree Topology Change:生成树协议状态为 0x80,拓扑发生变化

  • OSPF State Chang:OSPF 的 msg 类型不是 hello

  • ICMP errors:ICMP 协议错误,协议 type 字段值错误


红色:各类异常


  • TCP RST:TCP 流被 RESET,出现原因:1、端口未打开 2、请求超时 3、提前关闭连接 4、在一个已关闭的 socket 上收数据。断开连接,远端服务器尝试打开链接但无结果时,也会初心 RST 信号,这是防火墙阻隔连接的情况,每个 SYN 都返回一个 RST。

  • SCTP ABORT:串流控制协议的 chunk_type 为 ABORT

  • TTL low or unexpected:TTL 异常

  • Checksum Errors:条件中的各类 checksum 异常,在 PC 上抓包时网卡的一些设置经常会使 Wireskark 显示此错误


其他:正常


  • SMB:Server Message Block 类协议

  • IPX:互联网数据包交换类协议

  • TCP SYN/FIN:TCP 连接的起始和关闭

  • TCP/ARP/ICMP/UDP/HTTP/Routing/Broadcast:TCP/ARP/ICMP/UDP/HTTP/路由协议/广播数据

六、分析方法

6.1 Packet size limited during capture

当你看到这个提示,说明被标记的那个包没有抓全。以下图的 4 号包为例,它全长有 171 字节,但只有前 96 个字节被抓到了,因此 Wireshark 给了此提示。



这种情况一般是由抓包方式引起的。在有些操作系统中,tcpdump 默认只抓每个帧的前 96 个字节,我们可以用“-s”参数来指定想要抓到的字节数,比如下面这条命令可以抓到 1000 字节。


[root@my_server /]# tcpdump -i eth0 -s 1000 -w /tmp/tcpdump.cap
复制代码

6.2 TCP Previous segment not captured

在 TCP 传输过程中,同一台主机发出的数据段应该是连续的,即后一个包的 Seq 号等于前一个包的 Seq Len(三次握手和四次挥手是例外)。如果 Wireshark 发现后一个包的 Seq 号大于前一个包的 Seq Len,就知道中间缺失了一段数据。假如缺失的那段数据在整个网络包中都找不到(即排除了乱序),就会提示[TCP Previous segment not captured]。比如在下图这个例子中,6 号包的 Seq 号 1449 大于 5 号包的 Seq Len=1 0=1,说明中间有个携带 1448 字节的包没被抓到,它就是“Seq=1, Len=1448”。



网络包没被抓到还分两种情况:一种是真的丢了;另一种是实际上没有丢,但被抓包工具漏掉了。在 Wireshark 中如何区分这两种情况呢?只要看对方回复的确认(Ack)就行了。如果该确认包含了没抓到的那个包,那就是抓包工具漏掉而已,否则就是真的丢了。


顺便分析一下图中这个网络包,它是 HTTPS 传输异常时在客户端抓的。因为“Len: 667”的小包(即 6 号包)可以送达,但“Len: 1448”的大包却丢了,说明路径上可能有个网络设备的 MTU 比较小,会丢弃大包。后来的解决方式证实了这个猜测,只要把整个网络路径的 MTU 保持一致,问题就消失了。

6.3 TCP ACKed unseen segment

当 Wireshark 发现被 Ack 的那个包没被抓到,就会提示 [TCP ACKed unseen segment]。这可能是最常见的 Wireshark 提示了,幸好它几乎是永远可以忽略的。以图 3 为例,32 号包的 Seq Len=6889 1448=8337,说明服务器发出的下一个包应该是 Seq=8337。而我们看到的却是 35 号包的 Seq=11233,这意味着 8337~11232 这段数据没有被抓到。这段数据本应该出现在 34 号之前,所以 Wireshark 提示了[TCP ACKed unseen segment]。



不难想象,在一个网络包的开头会经常看到这个提示,因为只抓到了后面的 Ack 但没抓到前面的数据包。

6.4 TCP Out-of-Order

在 TCP 传输过程中(不包括三次握手和四次挥手),同一台主机发出的数据包应该是连续的,即后一个包的 Seq 号等于前一个包的Seq + Len。也可以说,后一个包的 Seq 会大于或等于前一个包的 Seq。当 Wireshark 发现后一个包的 Seq 号小于前一个包的Seq + Len时,就会认为是乱序了,因此提示 [TCP Out-of-Order] 。如下图所示,3362 号包的 Seq=2685642 小于 3360 号包的 Seq=2712622,所以就是乱序。



小跨度的乱序影响不大,比如原本顺序为 1、2、3、4、5 号包被打乱成 2、1、3、4、5 就没事。但跨度大的乱序却可能触发快速重传,比如打乱成 2、3、4、5、1 时,就会触发足够多的Dup ACK,从而导致 1 号包的重传。

6.5 TCP Dup ACK

当乱序或者丢包发生时,接收方会收到一些 Seq 号比期望值大的包。它每收到一个这种包就会 Ack 一次期望的 Seq 值,以此方式来提醒发送方,于是就产生了一些重复的 Ack。Wireshark 会在这种重复的 Ack 上标记[TCP Dup ACK] 。


以下图为例,服务器收到的 7 号包为“Seq=29303, Len=1460”,所以它期望下一个包应该是 Seq Len=29303 +1460=30763,没想到实际收到的却是 8 号包 Seq=32223,说明 Seq=30763 那个包可能丢失了。因此服务器立即在 9 号包发了 Ack=30763,表示“我要的是 Seq=30763”。由于接下来服务器收到的 10 号、12 号、14 号也都是大于 Seq=30763 的,因此它每收到一个就回复一次 Ack=30763,从图中可见 Wireshark 在这些回复上都标记了[TCP Dup ACK]。


6.6 TCP Fast Retransmission

当发送方收到 3 个或以上[TCP Dup ACK],就意识到之前发的包可能丢了,于是快速重传它(这是 RFC 的规定)。以图 6 为例,客户端收到了 4 个 Ack=991851,于是在 1177 号包重传了 Seq=991851。


6.7 TCP Retransmission

如果一个包真的丢了,又没有后续包可以在接收方触发[Dup Ack],就不会快速重传。这种情况下发送方只好等到超时了再重传,此类重传包就会被 Wireshark 标上[TCP Retransmission]。以下图为例,客户端发了原始包(包号 1053)之后,一直等不到相应的 Ack,于是只能在 100 多毫秒之后重传了(包号 1225)。


6.8 TCP zerowindow

TCP 包中的“win=”代表接收窗口的大小,即表示这个包的发送方当前还有多少缓存区可以接收数据。当 Wireshark 在一个包中发现“win=0”时,就会给它打上“TCP zerowindow”的标志,表示缓存区已满,不能再接受数据了。比如下图就是服务器的缓存区已满,所以通知客户端不要再发数据了。我们甚至可以在 3258~3263 这几个包中看出它的窗口逐渐减少的过程,即从 win=15872 减小到 win=1472。


6.9 TCP window Full

当 Wireshark 在一个包中打上[TCP window Full]标志时,就表示这个包的发送方已经把对方所声明的接收窗口耗尽了。以下图为例,Britain 一直声明它的接收窗口只有 65535,意味着 Middle East 最多能给它发送 65535 字节的数据而无需确认,即“在途字节数”最多为 65535 字节。当 Wireshark 在包中计算出 Middle East 已经有 65535 字节未被确认时,就会发出此提示。



[TCP window Full]很容易跟[TCP zerowindow]混淆,实际上它们也有相似之处。前者表示这个包的发送方暂时没办法再发送数据了,后者表示这个包的发送方暂时没办法再接收数据了,也就是说两者都意味着传输暂停,都必须引起重视。

6.10 TCP segment of a reassembled PDU

当你收到这个提示,肯定已经在 EditàPreferencesààTCP 菜单里启用了 Allow sub dissector to reassemble TCP streams。它表示 Wireshark 可以把属于同一个应用层 PDU(比如 SMB 的 Read Response 和 Write Request 之类)的 TCP 包虚拟地集中起来。如下图所示,这一个 SMB Read Response 由 39~48 号包共同完成,因此 Wireshark 在最后一个包中虚拟地把所有包集中起来。这样做有个好处,就是可以右键点击下图底部的方框,选择 CopyàBytesàPrintable Text Only,从而复制整个应用层的 PDU。做研发的同学可能比较需要这个功能。


6.11 Continuation to

看到这个提示,说明已经在 EditàPreferencesàProtocolsàTCP 菜单里关闭了 Allow sub dissector to reassemble TCP streams。比如上图的那些包,一关闭就变成下图这样。



仔细对比 2 图,你会发现 Read Response 在图 10 中被算在了 48 号包头上,而在图 11 中被算到了 39 号包头上。这样会带来一个诡异的结果:图 10 的读响应时间为 2.528 毫秒(38 号包和 48 号包的时间差),而图 11 的读响应时间为 2.476 毫秒(38 号包和 39 号包的时间差)。究竟哪个算正确呢?这个问题很难回答,如果在乎的是实际的总性能,那就看前者;如果想忽略 TCP/IP 协议的损耗,单看服务器的响应速度,那就看后者。在某些特殊情况下,这两者相差非常大,所以必须搞清楚。

6.12 Time-to-live exceeded (Fragment reassembly time exceeded)

ICMP 的报错有好多种,大都不难理解,所以我们只举其中的一种为例。 [Fragment reassembly time exceeded]表示这个包的发送方之前收到了一些分片,但是由于某些原因迟迟无法组装起来。比如在图 12 中,由于上海发往北京的一些包被分片传输,且有一部分在路上丢失了,所以北京方无法组装起来,便只好用这个 ICMP 报错告知上海方。


七、问题追踪

从上述案例的分享和实践中可以看到,TLS 层面的问题在客户端的症状表现上有相似之处,但是问题的根因却大相径庭。这里例举的问题虽不能覆盖所有的问题场景,但可以看到基本的排查思路如下:


  1. 判断问题是否属于 TLS/SSL 层面的问题。

  2. 抓取网络包;有条件的情况下,可以针对正常和异常情况抓取两份网络包,以便后续进行对比分析。

  3. 根据网络包探寻问题发生的直接原因,进而进一步探究问题的根本原因。

  4. 根据分析结论并结合业务场景,选择合适的解决方案。


这类问题的排查基础是对 HTTPS 和 TLS/SSL 协议的理解以及对分析工具的掌握。在移动领域,这类问题存在一定的共性,直接了解上述结论和分析方法可以帮助开发者快速“出坑”。

7.1 案例分析

抓取的应用报文如下:



其中,TCP 报文的一些主要信息如下:


35973 → 8888 [SYN] Seq=0 Win=65535 Len=0 MSS=1460 SACK_PERM=1 TSval=15986187 TSecr=0 WS=256
复制代码


  • 源端口和目的端口,35973->8888。

  • 序号,Seq=0,这是一个相对值而非绝对值,相对第一个包的序列号。因为是整个 TCP 流的第一包,所以 Wireshark 认定该包的序列号为 0。

  • 窗口大小,win=65535,也就是发送端的当前窗口最多容纳 65535 个字节。

  • 数据部分大小,Len=0,不带数据。

  • 最大报文大小选择,MSS=1460,数据部分最多有 1460 个字节。

  • 选择确认选项,SACK_PERM=1。

  • 发送时间戳,TSval=15986187,发出这个数据包的时候的时间戳。

  • 应答时间戳,TSecr=0,当前要发送的包应答的那个包的发送时间戳,因为是第一个包,应答的时间戳为 0。

  • 窗口扩大,WS=256。

八、拓展阅读

发布于: 刚刚阅读数: 3
用户头像

No Silver Bullet 2021-07-09 加入

岂曰无衣 与子同袍

评论

发布
暂无评论
跨平台应用开发进阶(四十三)一文走近网络层抓包工具:WhireShark_网络层_No Silver Bullet_InfoQ写作社区