抓包分析RST报文

分析,rst,报文 · 浏览次数 : 254

小编点评

# 服务端代码修改 ```go // SetLinger sets the behavior of Close on a connection which still has data waiting to be sent or to be acknowledged. // // If sec < 0 (the default), the operating system finishes sending the // data in the background. // // If sec == 0, the operating system discards any unsent or unacknowledged data. // // If sec > 0, the data is sent in the background as with sec < 0. On some operating systems after sec seconds have elapsed any remaining unsent data may be discarded. func SetLinger(sec int) error 如果写缓冲区还有数据或者发送了数据但是没有被ack,当设置linger为0时,进行close,会直接将写缓冲区数据丢弃并且往对端发送RST信号。为了验证这种场景,我们将服务端的代码再改动下,将连接linger属性设置为0,并且在写入一段数据后马上关闭。 // 设置linger属性为0 conn.(*net.TCPConn).SetLinger(0) ``` # 服务端读缓冲区还有数据再看下最后一个RST信号触发的场景 ```go // 服务端读缓冲区还有数据再看下最后一个RST信号触发的场景 func SetLinger(sec int) error 如果写缓冲区还有数据或者发送了数据但是没有被ack,当设置linger为0时,进行close,会直接将写缓冲区数据丢弃并且往对端发送RST信号。为了验证这种场景,我们将服务端的代码再改动下,将连接linger属性设置为0,并且在写入一段数据后马上关闭。 ``` # 服务端客户端代码修改 ```go //客户端程序仍然保持在发送消息后,睡眠1小时的状态,防止进程结束 func SetLinger(sec int) error 如果写缓冲区还有数据或者发送了数据但是没有被ack,当设置linger为0时,进行close,会直接将写缓冲区数据丢弃并且往对端发送RST信号。为了验证这种场景,我们将服务端的代码再改动下,将连接linger属性设置为0,并且在写入一段数据后马上关闭。 ```

正文

大家好,我是蓝胖子,今天我们来分析下网络连接中经常出现的RST信号,连接中出现RST信号意味着这条链接将会断开,来看下什么时候会触发RST信号,这在分析连接断开的原因时十分有帮助。

本文的讲解视频已经上传 抓包分析RST报文

在开始分析触发RST的场景之前,我们先来准备下需要的客户端和服务端代码,以方便我们进行测试。

服务端代码目前先是在8080端口监听,然后将接收到的消息打印出来。

func main() {  
   listen, err := net.Listen("tcp", ":8080")  
   if err != nil {  
      log.Fatal(err)  
   }  
   go func() {  
      for {  
         conn, err := listen.Accept()  
         if err != nil {  
            log.Fatal(err)  
         }  
         buf := make([]byte, 1024)  
         n, err := conn.Read(buf)  
         if err != nil {  
            log.Fatal(err)  
         }  
         fmt.Println(string(buf[:n]))  
       
   }()  
   ch := make(chan int)  
   <-ch  
}

客户端代码,连接8080端口然后打印hello world

func main() {  
   conn, err := net.Dial("tcp", "192.168.2.3:8080")  
   if err != nil {  
      log.Fatal(err)  
   }  
   _, err = conn.Write([]byte("hello world"))  
   if err != nil {  
      log.Fatal(err)  
   }  
}

现在,来让我们测试下触发RST的各种场景。

什么时候会触发RST

对端没有监听端口时

这个场景比较容器,不启动服务端,然后对8080端口进行抓包,接着直接运行客户端程序,看看此时客户端收到的数据包是怎样的。

(base) ➜  ~ sudo tcpdump -i lo0 port 8080
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo0, link-type NULL (BSD loopback), capture size 262144 bytes


18:58:14.745651 IP xiongchongdembp.63558 > xiongchongdembp.http-alt: Flags [S], seq 1854765658, win 65535, options [mss 16344,nop,wscale 6,nop,nop,TS val 98239951 ecr 0,sackOK,eol], length 0
18:58:14.745699 IP xiongchongdembp.http-alt > xiongchongdembp.63558: Flags [R.], seq 0, ack 1854765659, win 0, length 0

从tcpdump的抓包结果可以看出,客户端程序发出了握手信号[S],直接被回复了[R.]RST信号,可见,服务端没有监听端口时,系统内核会对想要连接该端口的客户端回复RST信号。

一端关闭了连接,另一端还在发送数据

再来看看客户端关闭后,对端继续发送消息的场景,这样的场景分为两种情况,一种事服务端发送keepalive消息,一种是服务端发送业务字节数据。

客户端关闭,服务端发送keepalive

先来看看发送keepalive消息的场景,这次同样用tcpdump监听8080端口,不过为了更清晰的分析这次抓包文件,我将tcpdump的抓包文件存到了本地,之后wireshark再去打开,tcpdump抓包命名如下:

sudo tcpdump -i lo0 port 8080 -w lo.pcap

接着,用文章开头准备的代码段启动服务端,客户端,注意,此时服务端仅仅是打印了收到的消息,并没有对客户端进行回应,而客户端进程也是在发送消息后就被销毁了。来看看此时的抓包文件

当客户端进程关闭时,即使没有显示的调用close方法,内核也会帮助我们关闭连接,发送fin信号,此时客户端连接会进入fin wait1状态,在这个状态下,客户端还是可以正常回应keep alive消息,不过超过fin wait1状态的超时时间时,则会被系统内核自动回收掉,此时再发送keepalive消息就会回复RST 这个超时时间在linux内核上可以通过下面这个文件进行修改,默认是1min。

root@ecs-295280:~# cat /proc/sys/net/ipv4/tcp_fin_timeout
60

客户端关闭,服务端发送消息

接着来看下,服务端在客户端关闭(无论是主动调用close方法还是进程结束连接被内核关闭都一样)的场景下主动发送消息触发RST的场景。

此时需要修改下目前服务端的代码了。

func main() {  
   listen, err := net.Listen("tcp", ":8080")  
   if err != nil {  
      log.Fatal(err)  
   }  
   go func() {  
      for {  
         conn, err := listen.Accept()  
         if err != nil {  
            log.Fatal(err)  
         }  
         buf := make([]byte, 1024)  
         n, err := conn.Read(buf)  
         if err != nil {  
            log.Fatal(err)  
         }  
         fmt.Println(string(buf[:n]))  
		time.Sleep(time.Second)
         _, err = conn.Write([]byte("receive msg"))  
         if err != nil {  
            fmt.Println(err)  
         }  
  
   }()  
   ch := make(chan int)  
   <-ch  
}

这次的服务端不仅打印了收到的消息,还将消息发送给了客户端,为了确保服务端发送消息时,客户端已经关闭了,我还在服务端收到消息时故意停留了1s再发送消息。

此时用tcpdump抓包如下:

可以看到在连接关闭后,还往连接发送消息是会触发RST信号的。

当服务端缓冲区还有数据时,服务端关闭链接

服务端读缓冲区还有数据

接着来看下服务端读缓冲区有数据的情况下,服务端关闭连接的场景,这个场景服务端会直接发送RST信号,我们对客户端代码进行修改,让它发送完消息进程等待状态,防止进程结束。

func main() {  
   conn, err := net.Dial("tcp", "192.168.2.3:8080")  
   if err != nil {  
      log.Fatal(err)  
   }  
   _, err = conn.Write([]byte("hello world"))  
   if err != nil {  
      log.Fatal(err)  
   }  
   time.Sleep(time.Hour)  
}

然后对服务端代码进行修改,握手成功后等待2s来确保客户端发送的消息到达,然后关闭连接。

func main() {  
   listen, err := net.Listen("tcp", ":8080")  
   if err != nil {  
      log.Fatal(err)  
   }  
   go func() {  
      for {  
         conn, err := listen.Accept()  
         if err != nil {  
            log.Fatal(err)  
         }  
         time.Sleep(2 * time.Second)  
         conn.Close()  
      }  
  
   }()  
   ch := make(chan int)  
   <-ch  
}

对这个场景的抓包如下:

可见,服务端在关闭连接时直接发送了RST信号。

服务端写缓冲区还有数据

再来看下最后一个RST信号触发的场景,默认情况下,当写缓冲区还有数据时,如果调用close方法,会将写缓冲区的发送到对端然后再发送fin信号,但是如果设置了linger属性,那么情况会变得不同。

// SetLinger sets the behavior of Close on a connection which still// has data waiting to be sent or to be acknowledged.  
//  
// If sec < 0 (the default), the operating system finishes sending the  
// data in the background.  
//  
// If sec == 0, the operating system discards any unsent or  
// unacknowledged data.  
//  
// If sec > 0, the data is sent in the background as with sec < 0. On  
// some operating systems after sec seconds have elapsed any remaining  
// unsent data may be discarded.
func (c *TCPConn) SetLinger(sec int) error 

如果写缓冲区还有数据或者发送了数据但是没有被ack,当设置linger为0时,进行close,会直接将写缓冲区数据丢弃并且往对端发送RST信号。

为了验证这种场景,我们将服务端的代码再改动下,将连接linger属性设置为0,并且在写入一段数据后马上关闭。

func main() {  
   listen, err := net.Listen("tcp", ":8080")  
   if err != nil {  
      log.Fatal(err)  
   }  
   go func() {  
      for {  
         conn, err := listen.Accept()  
         if err != nil {  
            log.Fatal(err)  
         }  
         buf := make([]byte, 1024)  
         n, err := conn.Read(buf)  
         if err != nil {  
            log.Fatal(err)  
         }  
         conn.(*net.TCPConn).SetLinger(0)  
         fmt.Println(string(buf[:n]))  
         _, err = conn.Write([]byte("receive msg"))  
         if err != nil {  
            fmt.Println(err)  
         }  
         conn.Close()  
  
   }()  
   ch := make(chan int)  
   <-ch  
}

客户端程序仍然保持在发送消息后,睡眠1小时的状态,防止进程结束

func main() {  
   conn, err := net.Dial("tcp", "192.168.2.3:8080")  
   if err != nil {  
      log.Fatal(err)  
   }  
   _, err = conn.Write([]byte("hello world"))  
   if err != nil {  
      log.Fatal(err)  
   }  
   time.Sleep(time.Hour)  
}

对这种场景的抓包如下:

与抓包分析RST报文相似的内容:

抓包分析RST报文

大家好,我是蓝胖子,今天我们来分析下网络连接中经常出现的RST信号,连接中出现RST信号意味着这条链接将会断开,来看下什么时候会触发RST信号,这在分析连接断开的原因时十分有帮助。 本文的讲解视频已经上传 [抓包分析RST报文](https://bilibili.com/video/BV1rc411

Wireshark抓包分析理解DHCP协议及工作流程

文章详细描述了DHCP报文的封装格式和具体字段,包括操作类型、硬件地址类型、长度、随机数、标志位等,并对选项字段中的常见选项进行了解释。随后,文章列举了DHCP的八种报文类型,并解释了每种报文的含义和作用。 文章的核心部分是DHCP的工作流程,分为四个阶段:发现(Discover)、提供(Offe...

如何从抓包文件中分析慢请求

请求慢的原因很多,当出现前端反应接口慢时,而通过后端日志查看请求处理时间并不慢时,往往会手足无措,当面对网络问题出现手足无措时,这就是在提醒你该抓包分析了,那么一般如何根据抓包文件去分析慢请求呢,今天我们就来看看。 ## 抓包文件分析 准备用我在测试环境抓到的包去进行分析,首先执行抓包命令。 ```

利用Wireshark抓包分析DNS域名解析过程

一、DNS协议概述 DNS协议也可以称为DNS服务,全称是Domain Name System,即域名系统,和HTTP协议一样,也是一个位于应用层的协议(服务),它是基于运输层的UDP协议的。从DNS的名字我们就可以知道,它提供域名映射到IP地址的服务。 二、实验目的 掌握DNS域名解析过程 熟悉D

[转帖]抓包分析 TCP 握手和挥手

https://segmentfault.com/a/1190000042750447 前言 首先需要明确的是 TCP 是一个可靠传输协议,它的所有特点最终都是为了这个可靠传输服务。在网上看到过很多文章讲 TCP 连接的三次握手和断开连接的四次挥手,但是都太过于理论,看完感觉总是似懂非懂。反复思考过

《爆肝整理》保姆级系列教程-玩转Charles抓包神器教程(13)-Charles如何进行Mock和接口测试

1.简介 Charles最大的优势在于抓包分析,而且我们大部分使用的功能也在抓包的功能上,但是不要忘记了,Charles也可以做接口测试。至于Mock,其实在修改请求和响应数据哪里就已经介绍了,宏哥就是在这里简单的提一下介绍一下它的理论知识,今天主要介绍和分享的是使用Charles进行接口测试实操。

[转帖]Https、SSL/TLS相关知识及wireShark抓包分析

https://cloud.tencent.com/developer/article/1954070?areaSource=104001.56&traceId=7WZNP412yK3vh7ebw4th0 一、网络通信的三大风险 在HTTP协议中,所有报文的发送、接收都是以明文的形式进行的。也就是说

[转帖]Wireshark:又一个可以查看https消息内容的工具

https://www.jianshu.com/p/7c16474edd9b 我们在接口测试和故障诊断调试时,需要查看消息里边的内容,如果是http消息可以通过wireshark抓包分析软件看到,但https消息内容在传输过程中是加密的,怎样才能看到https加密后的消息呢? 从技术上来说,需要拿到

[转帖]Web技术(七):如何使用并实现MQTT 消息订阅-发布模型?

文章目录 一、什么是发布-订阅消息模型?二、订阅-发布消息模型有哪些应用?2.1 应用于IP 物联网络中的消息传递2.2 应用于操作系统进程间的消息传递2.3 应用于MESH 自组网中的消息传递 三、MQTT 如何实现订阅-发布消息模型?3.1 如何在本机实践MQTT 通信并抓包分析?3.2 MQT

聊聊wireshark的进阶使用功能

emmm,说起网络知识学习肯定离不来wireshark工具,这个工具能够帮助我们快速地定位网络问题以及帮助正在学习网络协议这块的知识的同学验证理论与实际的一大利器,平时更多的只是停留在初步的使用阶段。也是利用部门内部的网络兴趣小组的讨论机会,私下对wireshark的一些进阶功能,比如专家模式、图表等功能进行调研,并结合实际场景抓包分析对功能进行对照说明。