抓包分析RST报文
大家好,我是蓝胖子,今天我们来分析下网络连接中经常出现的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报文的更多相关文章
- ipv6地址抓包分析
拓扑图: 因为多路由,所以采用ospf配置将路由实现互通,从而进行抓包 ospf配置以R1为例 查看R4路由表 做完进行ping通测试 R4pingR3 R4pingR5 进行抓包分析 128报文 1 ...
- 计算机网络-DHCP协议抓包分析总结
前置问题:什么是(网络)协议? 网络协议为计算机网络中进行数据交换而建立的规则.标准或约定的集合. 而且: 一个网络协议至少包括三要素: 语法:用来规定信息格式;数据及控制信息的格式.编码及信号电平等 ...
- Wireshark抓包分析HTTPS与HTTP报文的差异
一.什么是HTTPS: HTTPS(Secure Hypertext Transfer Protocol)安全超文本传输协议 它是一个安全通信通道,它基于HTTP开发,用于在客户计算机和服务器之间交换 ...
- nmap参数原理抓包分析
nmap参数原理抓包分析 实验环境: Nmap7.70 实验步骤: 1.主机发现 2.端口扫描 3.服务版本探测 一.主机发现 主机发现,如果主机活跃,扫描1000个常用的tcp端口 1.Nmap i ...
- Wireshark抓包分析TCP 3次握手、4次挥手过程
Wireshark简介 更多有关Wireshark的教程.软件下载等,请见:http://www.52im.net/thread-259-1-1.html,本文只作简要介绍. 1Wireshark 是 ...
- 转:tcpdump抓包分析(强烈推荐)
转自:https://mp.weixin.qq.com/s?__biz=MzAxODI5ODMwOA==&mid=2666539134&idx=1&sn=5166f0aac71 ...
- WireShark抓包分析(二)
简述:本文介绍了抓包数据含义,有TCP报文.Http报文.DNS报文.如有错误,欢迎指正. 1.TCP报文 TCP:(TCP是面向连接的通信协议,通过三次握手建立连接,通讯完成时要拆除连接,由于TCP ...
- 聊聊tcpdump与Wireshark抓包分析
1 起因# 前段时间,一直在调线上的一个问题:线上应用接受POST请求,请求body中的参数获取不全,存在丢失的状况.这个问题是偶发性的,大概发生的几率为5%-10%左右,这个概率已经相当高了.在排查 ...
- 抓包分析TCP的三次握手和四次握手
问题描写叙述: 在上一篇<怎样对Android设备进行抓包>中提到了,server的开发者须要我bug重现然后提供抓包给他们分析.所以抓好包自己也试着分析了一下.发现里面全是一些TCP协议 ...
- 使用wireshark抓包分析-抓包实用技巧
目录 使用wireshark抓包分析-抓包实用技巧 前言 自定义捕获条件 输入配置 输出配置 命令行抓包 抓取多个接口 抓包分析 批量分析 合并包 结论 参考文献 使用wireshark抓包分析-抓包 ...
随机推荐
- git的Rebase和Merge之间的区别
有人会说Merge更好,因为它保留了最完整的工作历史.其他人则认为,Rebase变得更整洁,这使审阅者的生活更轻松,更高效.本文将解释合并和重新设置之间的区别是什么,使用它们之一有什么好处. 从根本上 ...
- 全渠道定价、库存决策,运筹混合整数规划建模求解,MNL选择模型,内附代码!
0. 写在前面 刊论文!模型简单,代码实现更简单,墙裂推荐!可为运筹建模提供参考,也可作为全渠道零售研究的入门资料ε٩(๑> ₃ <)۶з 全文有点长,前面先放一个博文结构和涉及内容: 第 ...
- 在 Vue 中控制表单输入
Vue中v-model的思路很简单.定义一个可响应式的text(通常是一个ref),然后用v-model="text"将这个值绑定到一个input上.这就创造了一个双向的数据流: ...
- Web前端开发必看的100道大厂面试题
1. 说说gulp和webpack的区别 开放式题目 Gulp强调的是前端开发的工作流程.我们可以通过配置一系列的task,定义task处理的事务(例如文件压缩合并.雪碧图.启动server.版本控制 ...
- 网络抓包 tcpdump 使用指南
在网络问题的调试中,tcpdump应该说是一个必不可少的工具,和大部分linux下优秀工具一样,它的特点就是简单而强大.它是基于Unix系统的命令行式的数据包嗅探工具,可以抓取流动在网卡上的数据包. ...
- python移动同名文件
import os import shutil def split_name(file): file_name, _ = file.split('.') return file_name def mo ...
- 带你用三种不同的工具体验AI作诗
摘要:本实验基于华为云API Arts和API Explorer,向用户介绍诗歌生成API,指导用户使用华为云工具,体验AI作诗的过程. 本文分享自华为云社区<AI语言能力体验:通过三种不同的工 ...
- Docker Compose 部署 Jenkins
Jenkins介绍 Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具 Jenkins应用广泛,大多数互联网公司都采用Jenkins配合GitLab.Docker.K8s作为实现D ...
- Midjourney:一步一步教你如何使用 AI 绘画 MJ
一步一步如何使用 Midjourney 教程:教学怎么用 MJ? 一.Midjourney(MJ)是什么? Midjourney是一款使用文字描述来生成高质量图像的AI绘画工具.这篇文章主要介绍了Mi ...
- 如何建设一个用于编译 iOS App 的 macOS 云服务器集群?
作者:京东零售 叶萌 现代软件开发一般会借助 CI/CD 来提升代码质量.加快发版速度.自动化重复的事情,iOS App 只能在 mac 机器上编译,CI/CD 工具因此需要有一个 macOS 云服务 ...