跳到主要内容

使用wireshark分析TCP

Wireshark 是一个免费开源的网络数据包分析软件,他能清楚地显示分层协议的状态,从物理层到应用层的数据传递以及相关协议的使用都能展示出来,十分强大!

用 Wireshark 分析 TCP 传输有很重要的两点使用方面的需要注意:

  • 左侧的状态条和小对勾能将 TCP 请求和响应的两条报文对应起来,当鼠标点击某一条后,作为该条的响应 TCP 前面就会有一个小对勾;而状态条这个虚线框就表示一条 TCP 连接;如果点了下一条发现虚线框没把它包含在刚才的虚线框内,就表示这一条和上一条选的不属于同一个 TCP 连接。

image-20200805110025903

  • 下面的 TCP 首部分析也会包含该条 TCP 是响应谁

image-20200805110414111

握手

TCP 连接建立的过程叫做握手(handshake),握手需要客户端和服务器之间交换三个 TCP 报文,其实准确来讲这是一次握手三报文交换的过程,但是流行上用语是三次握手

这个过程通过 wireshake 可以清楚的观察到,以浏览器请求 HTTP 协议的某个网站地址 106.3.45.11 为例,使用 wireshark 过滤请求ip.addr == 106.3.45.11经过下图的流程,在这个流程中有以下规定:

  • 同步位SYN1的报文不能携带数据,但是要消耗一个序号;
  • 服务端返回的SYNACK报文需要消耗掉一个序号;
  • 只有ACK1的报文才能携带数据,此时的确认号才有效;ACK报文不携带数据则不消耗序号

image-20200809162242700

客户端发起连接请求

首先,客户端想服务器发起连接请求,通过 wireshark 抓包工具,可以清楚的解析出 TCP 报文首部的所有字段值:

  • Source Port:来源端口,也就是浏览器发出请求连接的端口11374
  • Destination Port:80,也就是默认 HTTP 协议的响应端口80
  • Sequence number:0,这个序号是 wireshark 做的相对当前 TCP 建立连接的序号,不是真实的序号
  • Sequence number (raw): 3835654651,这个序号才是真实的 TCP 报文首部的序号,也就是seq = 3835654651,接下来的请求只看这个的变化
  • Acknowledgment number:0,确认号
  • Flags:也就是控制位部分,可以看到此时的标志位是SYN1;而确认连接控制位ACK0

image-20200804221646631

服务端同意建立连接

接下来服务端收到客户端的请求,同意建立连接,发送自己的确认连接 TCDP 报文,可以看到此时的 TCP 首部字段变成了以下这些:

  • Source Port:来源端口,从服务器往客户端发,所以端口就是服务器的端口80
  • Destination Port: 11374,也就是客户端的接收端口
  • Sequence number (raw): 1610539220,此时的服务端的seq = 1610539220
  • Acknowledgment number (raw): 3835654652,服务端的确认号ack = 3835654652,是上次客户端请求的序号 + 1
  • Flags:也就是控制位部分,可以看到此时的标志位是SYN1;而确认连接控制位ACK也置1

image-20200804222154838

客户端回应准备建立连接

客户端收到服务端建立连接的响应,还需要再次发送确认自己也能建立连接的回应,此时的 TCP 首部信息如下:

  • Sequence number (raw): 3835654652,seq = 3835654652,是上次服务端响应 TCP 报文首部的确认号 + 1
  • Acknowledgment number (raw): 1610539221,ack = 1610539221,指示服务端下次发送报文的序号,也就是上次服务端 TCP 报文首部的序号 + 1
  • Flags:此时客户端的确认连接控制位ACK也置为1了,而SYN又置为0

image-20200804222745939

注意事项

从 TCP 建立连接的过程中不难得出:

  • 在 TCP 从建立连接到最后释放连接的过程中,只有第一次传递 TCP 报文时ACK = 0,也就是只要看到单独的SYN而没有其他控制位,那么就表示这个 TCP 传输是建立连接的第一个请求;
  • 在传输数据的过程中,始终有以下等式成立:

ack = 接收的最后一个 TCP 报文的seq + 数据长度

seq = 接收的最后一个 TCP 报文的ack

数据传输

在 wireshark 中观察到,客户端发起 HTTP GET 请求,这时底下的分析框就会多出来一个 HTTP 协议的请求头分析,不看这个还是看运输层的 TCP 协议,此时的 TCP 报文首部如下:

  • Sequence number (raw): 1354298230,seq = 1354298230
  • Acknowledgment number (raw): 3832919684,ack = 3832919684
  • Flags:控制位ACK = 1
  • TCP payload (458 bytes):最后还有一个 TCP payload,这也就是 TCP 报文携带的数据部分的字节长度,也就是 HTTP 协议的报文长度

image-20200804231623936

接下来开始找 wireshark 中 HTTP OK 的响应,可以看到 TCP 报文的首部如下:

  • Sequence number: 3832919684,seq = 3832919684
  • Acknowledgment number: 1354298688,ack = 1354298688,对应 HTTP 请求时 TCP 首部的序号加上数据长度,即1354298230+458 = 1354298688
  • Flags:ACK = 1

image-20200804233155214

断开连接

TCP 连接释放的过程相比握手要复杂一点,释放连接的过程双方都可以发起,释放连接的信号就是FIN控制位的切换,当遇到 TCP 报文首部FIN = 1时就表示发送方要进行释放连接的操作了。

现在使用 wireshark 观察释放连接的过程,连接释放的过程一定要看 Wireshark 左侧虚线框包裹的完整的 TCP 连接过程,不在虚线框内的请求都不属于该条 TCP 连接的,所以一般都是找最后一条ACK

客户端发起释放连接请求

以客户端发起释放连接请求为例,一般也就是主动关闭浏览器页面就会由客户端发起断开连接请求,观察到 TCP 首部如下:

  • Sequence number: 1280378407,seq = 1280378407
  • Acknowledgment number: 4092453323,ack = 4092453323
  • Flags:ACK = 1FIN = 1

image-20200805110741358

####服务端同意释放

在 Wireshark 中找到 138 的响应报文时 152,此时服务端的 TCP 首部是:

  • Sequence number: 4092453323,seq = 4092453323
  • Acknowledgment number: 1280378408,ack = 1280378408
  • Flags:ACK = 1

image-20200805111104178

服务端确认释放连接

紧接着 ACK,服务端会再次发送一条确认自己也要释放连接的请求,让客户端同意,可以看到此时的序号还有确认号都和上一条完全一样

  • Sequence number: 4092453323,seq = 4092453323
  • Acknowledgment number: 1280378408,ack = 1280378408
  • Flags:ACK = 1FIN = 1

image-20200805111400346

客户端确认释放连接

客户端要对服务端确认释放连接的请求做出响应,这样双方都确认释放连接,就进入TIME-WAIT(时间等待)状态

  • Sequence number: 1280378408,seq = 1280378408
  • Acknowledgment number: 4092453323,ack = 4092453323,和上一条服务端返回的序号一致
  • Flags:ACK = 1

image-20200805111928369

TIME-WAIT

梳理一下上述关闭连接的请求流程,双方一共收发了 4 个报文:

  • 客户端请求关闭连接,发送FIN = 1的 TCP 报文;
  • 服务端收到关闭连接请求表示同意,让主动方不会因为没有收到应答而继续发送断开连接的请求;于是服务端发送同意关闭连接的响应ACK = 1;客户端在收到这个响应报文以后,因为是客户端主动发起的关闭请求也就表示客户端没有数据要传输了,但是它不知道服务端还有没有数据要传,所以客户端要进入一个等待的状态FIN-WAIT-1
  • 当服务端没有数据要传输的时候,就会向客户端也发送一个请求关闭连接的报文FIN = 1,让客户端知道服务端没有数据要传了,放心关闭连接吧,同时也表示自己也要关闭连接了;
  • 客户端在收到服务端关闭连接的请求后也会表示同意ACK = 1,然后客户端会进入一个定时等待TIME-WAIT的状态,等待啥呢?设想如果客户端同意服务端关闭 TCP 连接的请求没送到呢?那服务端会一直处于等待状态,它不知道客户端同不同意它关啊,所以在这个等待时间内,如果服务端没有收到客户端的确认,那么会重传上一条关闭连接的请求报文;
  • 最后当服务端收到客户端的确认关闭连接ACK后,就真的关闭连接了;而客户端则在等待TIME-WAIT的时间后也关闭连接,双方都进入CLOSED状态。