抓包分析序列号、确认号、三次握手、四次挥手

首先有下面几个问题:

  1. 序列号和确认号是怎么计算的?
  2. 序列号和确认号的作用?
  3. 序列号从零开始就不需要握手了,为什么要随机呢?
  4. 三次握手,四次挥手中,序列号确认号在实际数据包中是怎么变化的?
  5. 为什么需要三次握手,四次挥手?
  6. 三次握手中,可以携带数据吗?

一 、序列号和确认号计算方法

TCP序列号是两个方向的,每个方向有自己的序列号,这个序列号是随机产生的。

  • 客户端的序列号为上一个服务器端的确认号,同时也是上一个客户端的序列号+负载数据。
  • 客户端的确认号,是上一个服务器端的序列号+负载数据。

服务端序列号和确认号跟客户端一样。

这里说的客户端,服务器端都是发数据的一方。后面会通过抓包验证。

二、序列号和确认号的作用

在网络分析中,读懂TCP序列号和确认号在的变化趋势,可以帮助我们学习TCP协议以及排查通讯故障,如通过查看序列号和确认号可以确定数据传输是否乱序。

TCP协议工作在OSI的传输层,是一种可靠的面向连接的数据流协议,TCP之所以可靠,是因为它保证了传送数据包的顺序。顺序是用一个序列号来保证的。响应包内也包括一个序列号,表示接收方准备好这个序列号的包。在TCP传送一个数据包时,它会把这个数据包放入重发队列中,同时启动计时器,如果收到了关于这个包的确认信息,便将此数据包从队列中删除,如果在计时器超时的时候仍然没有收到确认信息,则需要重新发送该数据包。另外,TCP通过数据分段中的序列号来保证所有传输的数据可以按照正常的顺序进行重组,从而保障数据传输的完整。

                                                                                                                                                                       -----百度百科

TCP 协议为了实现可靠传输, 通信双方需要判断自己已经发送的数据包是否都被接收方收到, 如果没收到, 就需要重发。 为了实现这个需求, 很自然地就会引出序号(sequence number) 和 确认号(acknowledgement number) 的使用。 

  •  序列号:在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送一次数据,就累加一次该数据字节数的大小。用来解决网络包乱序问题。
  • 确认号:指下一次期望收到的数据的序列号,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。用来解决不丢包的问题。

这里来举个栗子:

客户端在发送数据包,假设大小为 10 byte 时, 假设上一个序列号为200,那么服务端收到这个数据包以后, 就会回复一个确认号210(参考上面的计算方法:客户端的确认号是上一个服务器端的序列号200+负载数据10210 = 200 + 10) ,告诉客户端我已经收到了序列号截止到509的数据,期待的下一个数据起点是510

这样发送方就可以知道哪些数据被接收到,哪些数据没被接收到, 需要重发。

三、序列号随机的作用

  • 防止接受网络上粘滞的TCP包,如果都从0开始的话,极其容易接受之前断开连接发送的粘滞包。虽然可以采用每次TCP会话都使用一个UUID作为标记,但是考虑到每次都要携带UUID,比较浪费流量,所以就采用随机序列号的方法。

  • 防止Hack猜测序列号,然后伪装TCP报文进行攻击。

 四、三次握手,四次挥手中,序列号和确认号变化规律

下表为TCP状态码列表,以S指代服务器,C指代客户端,S&C表示两者,S/C表示两者之一:

  • LISTEN S:服务器等待从任意远程TCP端口的连接请求。侦听状态。
  • SYN-SENT C:客户在发送连接请求后等待匹配的连接请求。通过connect()函数向服务器发出一个同步(SYNC)信号后进入此状态。
  • SYN-RECEIVED S:服务器已经收到并发送同步(SYNC)信号之后等待确认(ACK)请求。
  • ESTABLISHED S&C:服务器与客户的连接已经打开,收到的数据可以发送给用户。数据传输步骤的正常情况。此时连接两端是平等的。这称作全连接。
  • FIN-WAIT-1 S&C:(服务器或客户)主动关闭端调用close()函数发出FIN请求包,表示本方的数据发送全部结束,等待TCP连接另一端的ACK确认包或FIN&ACK请求包。
  • FIN-WAIT-2 S&C:主动关闭端在FIN-WAIT-1状态下收到ACK确认包,进入等待远程TCP的连接终止请求的半关闭状态。这时可以接收数据,但不再发送数据。
  • CLOSE-WAIT S&C:被动关闭端接到FIN后,就发出ACK以回应FIN请求,并进入等待本地用户的连接终止请求的半关闭状态。这时可以发送数据,但不再接收数据。
  • CLOSING S&C:在发出FIN后,又收到对方发来的FIN后,进入等待对方对己方的连接终止(FIN)的确认(ACK)的状态。少见。
  • LAST-ACK S&C:被动关闭端全部数据发送完成之后,向主动关闭端发送FIN,进入等待确认包的状态。
  • TIME-WAIT S/C:主动关闭端接收到FIN后,就发送ACK包,等待足够时间以确保被动关闭端收到了终止请求的确认包。【按照RFC 793,一个连接可以在TIME-WAIT保证最大四分钟,即最大分段寿命(maximum segment lifetime)的2倍】
  • CLOSED S&C:完全没有连接。

  还要知道TCP标志位的含义:

  • URG:紧急指针,告诉接收TCP模块紧要指针域指着紧要数据。
  • ACK:置1时表示确认号合法,为0的时候表示数据段不包含确认信息,确认号被忽略。
  • PSH:置1时请求的数据段在接收方得到后就可直接送到应用程序,而不必等到缓冲区满时才传送。
  • RST:置1时重建连接。如果接收到RST位时候,通常发生了某些错误。
  • SYN:置1时用来发起一个连接。
  • FIN :置1时表示发端完成发送任务。用来释放连接,表明发送方已经没有数据发送了。

注意:标志位的ACK和确认号ack是完全不一样的。 

 抓包分析序列号、确认号、三次握手、四次挥手_第1张图片

上图是三次握手的过程, 为了方便计算seq(序列号)和ack(确认号),我们把上面的公式先搬下来:

  • 客户端的序列号为上一个服务器端的确认号,同时也是上一个客户端的序列号+负载数据。
  • 客户端的确认号,是上一个服务端的序列号+负载数据。

结合上图和公式来理解下面的三次握手的过程: 

第一次握手:客户端将标志位 SYN 置为 1,并随机产生一个值 seq = x,然后将该数据包发送给服务端,客户端进入 SYN_SENT 状态,等待服务端确认。
第二次握手:服务端收到客户端发来的数据包,看到标志位 SYN = 1,从而知道客户端想要建立连接,于是服务端将标志位 ACK 置为 1(标志位 SYN 此时还是 1),设置 ack = x + 1随机产生一个值 seq = y,然后将该数据包发送给客户端以确认连接请求,服务端进入 SYN_RECVD 状态,客户端进入 ESTABLISHED 状态。
第三次握手:客户端收到确认数据包后,检查 ack 是否为 x + 1,标志位 ACK 是否为 1,如果都满足,则将标志位 ACK 置为 1,设置seq = x + 1, ack = y + 1,然后将该数据包发送给服务端,服务端检查 ack 是否为 y + 1,标志位 ACK 是否为 1,如果都满足,则连接建立成功。服务端进入 ESTABLISHED 状态 。

 对于上面三次握手的过程,你可能会有疑问:负载数据1是咋来的?

TCP规定,SYN报文段(即SYN = 1的报文段)不能携带数据,但要消耗掉一个序号。

这样是不是就理解那个“1”是咋来的了,接下来我们通过实际的数据包来验证序列号和确认号在TCP连接建立过程中的变化。

使用的抓包工具是科来网络分析系统技术交流版,有兴趣的可以下载分析一下,点我下载。

抓包分析序列号、确认号、三次握手、四次挥手_第2张图片

                                                                                                         图一

可以看到上图红框是三次握手的过程,下面我们具体看一下是怎么建立连接的 。

抓包分析序列号、确认号、三次握手、四次挥手_第3张图片

                                                                                                         图二 

 第一次握手:客户端将标志位 SYN 置为 1,并随机产生一个值 seq = 3066323072,此时ack = 0,然后将该数据包发送给服务端,客户端进入 SYN_SENT 状态,等待服务端确认。

抓包分析序列号、确认号、三次握手、四次挥手_第4张图片

                                                                                                         图三 

第二次握手:服务端收到客户端发来的数据包,看到标志位 SYN = 1,从而知道客户端想要建立连接,于是服务端将标志位 ACK 置为 1(标志位 SYN 此时还是 1),设置 ack =  3066323072 + 1(客户端的确认号,是上一个服务器端的序列号+负载数据),此时ack = 3066323073,随机产生一个值 seq = 1997685163,然后将该数据包发送给客户端以确认连接请求,服务端进入 SYN_RECVD 状态,客户端进入 ESTABLISHED 状态。 

抓包分析序列号、确认号、三次握手、四次挥手_第5张图片

                                                                                                         图四 

 第三次握手:客户端收到确认数据包后,检查服务器发来的 ack 是否为 3066323073,标志位 ACK 是否为 1,如果都满足,则将标志位 ACK 置为 1,设置seq = 3066323072 + 1(客户端的序列号为上一个服务器端的确认号,同时也是上一个客户端的序列号+负载数据), ack = 1997685163 + 1,此时seq = 3066323073, ack = 1997685164然后将该数据包发送给服务端,服务端检查 ack 是否为 1997685164,标志位 ACK 是否为 1,如果都满足,则连接建立成功。服务端进入 ESTABLISHED 状态 。

注意:“下一个序列号”(图片中序列号右边)是科来网络分析系统为了方便用户查找下一个连续数据包,而根据数据包序列号和确认号自动计算得出,该字段在实际数据包中是不存在的。这个数据(下一个序列号)在TCP三次握手(建立连接)和四次挥手(断开连接)中是不正确的。

这个数据(下一个序列号)在内部实现上没有考虑到SYN报文段和FIN报文段,虽然不能携带数据,但要消耗掉一个序号,前两次握手的负载数据应该是1,而不是图一的0。

 

后续待补。。。

你可能感兴趣的:(【计算机网络】)