当前位置: 首页 > Linux

如何终止TCP连接?

时间:2023-04-07 01:04:55 Linux

原创:按钮日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处。简介如果你的程序写错了,很多TCP连接打开但从未关闭,这是一种常见的连接泄漏场景,你可能想在排查过程中临时杀掉一波泄漏连接。又比如你想验证程序在遇到网络错误时的自愈能力,想手动kill一些正常的TCP连接,看程序是否能自动重连恢复运行。在这些场景下,需要手动kill一些TCP连接,那么linux下kill连接的方式有哪些呢?终止活动的TCP连接使用ngrep或tcpkill命令终止活动的TCP连接。用法如下:#ngrepkillconnections$sudongrep-dany-K3'''port54690'#安装tcpkill并用它来killConnect$sudoaptinstalldsniff$sudotcpkill-iany'port45308'如图上面可以发现,ngrep和tcpkill在kill连接的时候都会向连接端发送RST包。学过《计算机网络》的同学都知道,TCP协议是通过FIN包和ACK包挥手四次来断开TCP连接的。这是一个正常的TCP断开过程,但是TCP协议中也有RST。package,这个包是用来在异常情况下断开连接的,linux收到RST包后,会直接关闭本端的Socket连接,不需要经过四次挥手的过程。上面的ngrep和tcpkill命令通过向对方发送RST数据包来终止TCP连接。但是要发送一个正确的RST数据包,需要知道TCP连接交互使用的序号(seq),因为乱序的数据包会被TCP直接丢弃,所以ngrep和tcpkill也会监控上面交互的数据包要查找的网卡指定用于连接的序列号seq。因此,ngrep和tcpkill只能杀死有流量的活动TCP连接,无法处理空闲连接。killidleTCPconnections对于空闲的TCP连接,可以使用ss或hping3命令进行处理,如下:使用sskillconnectionss命令的-K选项可以用来killconnection,如下:#安装ss命令$sudoaptinstalliproute2#使用ss终止与目标端口65987的连接$sudoss-Kdport=65987注意使用这个功能需要你的内核版本>=4.9,并且开启CONFIG_INET_DIAG_DESTROY选项,所以在某些情况下可能无法使用。使用hping3kill连接如果不能使用ss命令,可以考虑使用hping3命令kill连接。hping3命令可以发送任何类型的TCP包,所以只要模拟一下tcpkill的原理即可,如下:通过发送一个SYN包得到上面的seq前面说过,TCP协议会直接丢弃乱序的数据包,但是它以不同方式处理SYN数据包。如果你向连接的Socket发送一个SYN包,它会用正确的seq序列回复一个ACK编号如下:#第一个参数表示发送包的目标ip地址#-a:设置源ip地址包的#-s:设置包的源端口#-p:设置包的目标端口#--syn:表示发送SYN包#-V:verbose输出,使hping3输出序列号seq#-c:设置发送包数$sudohping3172.26.79.103-a192.168.18.230-s8080-p45316--syn-V-c1usingeth0,addr:172.26.79.103,MTU:1500HPING172.26.79.103(eth0172.26.79.103):Sset,40headers+0databyteslen=40ip=172.26.79.103ttl=64DFid=16518tos=40sip45316flags=Aseq=0win=502rtt=13.4msseq=1179666991ack=1833836153sum=2acfurp=0在输出中可以查到,ack=1833836153是对方回复的序号,我们在后面中间用它来发送RST包。使用seq发送RST包#--rst:表示发送RST包#--win:设置TCP窗口大小#--setseq:设置包的seq序列包$sudohping3172.26.79.103-a192.168.18.230-s8080-p45316--rst--win0--setseq1833836153-c1HPING172.26.79.103(eth0172.26.79.103):Rset,40headers+0databytes---172.26.79.103hpingstatistic---1packetstransmitted,0packetsreceived,100%packetlossround-tripmin/avg/max=0.0/0.0/0.0ms整个过程如下:可以发现我们之前用lsof找到的连接发送完RST包后就找不到了,说明连接已经被阻塞kill掉了。整个操作看起来有点繁琐,可以自己写个脚本封装一下。