我们在日常运维中,经常需要杀掉一个TCP连接,但情况是不一样的,有些是需要杀掉已经死了的TCP连接,有些是需要终止某个IP过来的连接。
对于死的TCP连接,这个TCP连接上已经没有数据包在传输了,这种连接用tcpkill是无法杀掉的,因为tcpkill杀连接时需要这个连接上有包传输才可以杀掉。
对于一直有包传输的TCP连接,我们可以使用tcpkill杀掉。
对于kill死连接或空闲连接,比较好用的工具为hping3。
网上很多文章介绍使用ss命令杀tcp连接,但是ss命令要求内核版本要>=4.9,而且打开了CONFIG_INET_DIAG_DESTROY选项,在Centos7.X下的内核都没有打开这个选项,所有在这些Linux平台下ss命令是无法杀连接的。所以还是建议使用hping3
要求操作系统已经安装了hping3工具,安装方法 :
yum install hping3
下面我们测试一下hping3杀连接的过程:
我们用psql与数据库建立一条连接:
psql -h 127.0.0.1 -p 5432 -Upostgres
然后看连接:
[root@csu06 ~]# netstat -an |grep 5432
tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:34724 127.0.0.1:5432 ESTABLISHED
tcp 0 0 127.0.0.1:5432 127.0.0.1:34724 ESTABLISHED
tcp6 0 0 ::1:5432 :::* LISTEN
unix 2 [ ACC ] STREAM LISTENING 58718 /var/run/postgresql/.s.PGSQL.5432
unix 2 [ ACC ] STREAM LISTENING 14877 /tmp/.s.PGSQL.5432
连接为127.0.0.1:34724 -> 127.0.0.1:5432
。
先用hping3给此socket发一个SYN包,然后此socket会返回一个ACK,从而获得此socket的正确seq序列号,然后再用此seq序列号发一个RST包,就把此连接给关闭了。
发SYN包:
hping3 127.0.0.1 -a 127.0.0.1 -s 37472 -p 5432 --syn -V -c 1
上面命令中的第一个参数127.0.0.1是目标IP,-a 127.0.0.1是源IP,-s 是源端口,-p 5412是目标端口, —syn是发送SYN包,-V显示详细信息(从详细信息中可以获得seq序列号), -c 1发送包1次。
[root@pgdev ~]# hping3 127.0.0.1 -a 127.0.0.1 -s 37472 -p 5432 --syn -V -c 1
using lo, addr: 127.0.0.1, MTU: 65536
HPING 127.0.0.1 (lo 127.0.0.1): S set, 40 headers + 0 data bytes
len=40 ip=127.0.0.1 ttl=64 DF id=4347 tos=0 iplen=40
sport=5432 flags=RA seq=0 win=0 rtt=0.1 ms
seq=0 ack=42230941 sum=14a3 urp=0
--- 127.0.0.1 hping statistic ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.1/0.1/0.1 ms
从上面可以获得ack=42230941,
发SYN包:
hping3 127.0.0.1 -a 127.0.0.1 -s 34724 -p 5432 --rst --win 0 --setseq 42230941 -c 1
[root@csu06 ~]# hping3 127.0.0.1 -a 127.0.0.1 -s 34724 -p 5432 --rst --win 0 --setseq 42230941 -c 1
HPING 127.0.0.1 (lo 127.0.0.1): R set, 40 headers + 0 data bytes
--- 127.0.0.1 hping statistic ---
1 packets transmitted, 0 packets received, 100% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms
再用netstat命令查看此连接,发现连接已经关闭,到psql中输入任何命令,发现连接被关闭了:
postgres=# \d
server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
The connection to the server was lost. Attempting reset: Succeeded.
如果可以支持“ss -K”的平台上,可以用下面命令kill tcp连接:
ss -K sport == 36474
非空闲连接是说此连接上一直有包在传送。使用ngrep或tcpkill命令可以完成此任务。ngrep或tcpkill当发现有包过来时,抓取了包中seq序列号,然后用此seq序列号给远端和目标端发送RST包来关闭tcp连接。
安装ngrep的方法:
yum install ngrep
安装tcpkill的方法:
yum install dsniff
查看连接:
[root@csu06 ~]# netstat -anp |grep 5432
tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN 6366/postgres
tcp 0 0 127.0.0.1:36474 127.0.0.1:5432 ESTABLISHED 15212/psql
tcp 0 0 127.0.0.1:5432 127.0.0.1:36474 ESTABLISHED 15213/postgres: pos
tcp6 0 0 ::1:5432 :::* LISTEN 6366/postgres
psql的连接为“127.0.0.1:36474 -> 127.0.0.1:5432”,
运行命令ngrep -d any -K3 '' 'port 36474'
,发现ngrep命令会等待socket上有包发送:
[root@csu06 ~]# ngrep -d any -K3 '' 'port 36474'
interface: any
filter: ( port 36474 ) and (ip || ip6)
#
然后到psql中运行\d
,然后再看ngrep的窗口,发现ngrep发现了发送的数据包,然后发送RST包,再切换回psql再运行\d
才发现连接被终止了:
postgres=# \d
Did not find any relations.
postgres=# \d
server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
The connection to the server was lost. Attempting reset: Succeeded.
如果是tcpkill,则命令为:
tcpkill -i any 'port 37018'