首页 > 其他分享 >抓包分析RST报文

抓包分析RST报文

时间:2023-06-14 10:47:50浏览次数:39  
标签:err nil 报文 服务端 conn RST Fatal 抓包

大家好,我是蓝胖子,今天我们来分析下网络连接中经常出现的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)  
}

对这种场景的抓包如下:

标签:err,nil,报文,服务端,conn,RST,Fatal,抓包
From: https://www.cnblogs.com/hobbybear/p/17479528.html

相关文章

  • 数学分析复习:Weierstrass 逼近定理, Müntz–Szász 定理
    本学期的“数学分析(不是实验班)”讲了一堆Approximationtheory,这是怎么绘事呢?定理1(Weierstrass).连续函数\(f\in\mathrmC[0,1]\)可被多项式一致逼近.对任意\(\varepsilon>0\)和\(x\in[0,1]\),设随机变量\(X\)服从二项分布\(\mathrmB(n,x)\),由Chebysh......
  • VMware虚拟化抓包
    在esxi环境下可以在不同的层面下抓包,需要明白在什么地方抓包,怎么抓包才是关键,否则可能导致抓包不完整,或无法抓到自己需要的包。了解抓包位置先研究下虚拟化的结构:  下面这张图是一台ESXi主机使用标准交换机的网络架构。简单来说分为四部分:  物理上联网卡  标准交换机......
  • 【保姆级教学】抓包工具Wireshark使用教程
    wireshark介绍今天讲一下另一款底层抓包软件,之前写过两篇抓包软件分别是fiddler抓包【https://www.cnblogs.com/zichliang/p/16067941.html】mitmdump抓包【https://www.cnblogs.com/zichliang/p/16067941.html】Wireshark(前身Ethereal)是一个网络包分析工具该工具主要......
  • 2023Fiddler抓包学习笔记 -- 环境配置及工具栏介绍
    一、Fiddler介绍Fiddler是位于客户端和服务器端的HTTP代理,常用来抓http数据包,可以监控浏览器所有的http和https流量,查看分析请求数据包和响应数据包,伪造请求和响应等功能。二、下载安装1、下载地址https://www.telerik.com/download/fiddler/fiddler42、一路下一步安装,安装完成后,发......
  • My First CRUD App With Fast API
    ImagebyauthorIt’sthedaybeforemyfastAPIlivestream.Idecidedtocreateaguideforthestreamandturnitintoablogpost.So,hereitis.Streamstructure:FastAPIvsDjangoInstallationCreateFirstAPP&RouteSwaggerUIPathParamete......
  • wireshark 抓包 过滤器表达式的规则
     https://www.wireshark.org/  DisplayFilter(显示过滤器),用于设置过滤条件进行数据包列表过滤。过滤器表达式的规则1、抓包过滤器语法和实例抓包过滤器类型Type(host、net、port)、方向Dir(src、dst)、协议Proto(ether、ip、tcp、udp、http、icmp、ftp等)、逻辑运算符(&&与、......
  • 微信PC端小程序抓包-Burp
    因为微信小程序基本都是基于HTTPS的,所以抓取HTTPS数据包就是最关键的一步。ProxifierProxifier是一款代理客户端软件,可以让不支持代理服务器工作的程序变的可行。支持各种操作系统和各代理协议,它的运行模式可以指定端口,指定程序的特点。1.下载及安装官网:http://proxifier.com/......
  • SNMP学习笔记之SNMP报文以及不同版本(SNMPv1、v2c、v3)的区别
    SNMP学习笔记之SNMP报文以及不同版本(SNMPv1、v2c、v3)的区别本篇文章将重点分析SNMP报文,并对不同版本(SNMPv1、v2c、v3)进行区别!四、SNMP协议数据单元在SNMP管理中,管理站(NMS)和代理(Agent)之间交换的管理信息构成了SNMP报文,报文的基本格式如下图1:        ......
  • wsexplorer——windows下的抓包工具 可以直接抓进程对应的网络流量
    软件标签:WSExplorer抓包工具  wsexplorer1.5版本是一款非常实用的抓包工具,用户能够直接通过软件直接获取更多的数据,同时还设计了选择功能,只需挑选自己需要的数据,需要的用户快来绿色资源网下载吧!wsexplorer抓包工具简介:wsexplorer是最好用的抓包工具,1.5版本添加新功能,分离二进......
  • Vue进阶(幺幺捌):CSS3 - 选择器first-child、last-child、nth-child、nth-last-child、nt
    (文章目录)1.first-child(IE7兼容)、last-child(IE8不兼容)html:<body><h2>列表</h2><ul><li>列表项目1</li><li>列表项目2</li><li>列表项目3</li><li>列表项目4</li></ul></body&g......