Originally from: http://rtomaszewski.blogspot.sk/2012/11/how-to-forcibly-kill-established-tcp.html
Here are some options:
- Attach with gdb and call close() on the fd. You can map from addr/port to inode number via /proc/net/tcp and from inode number to FD inside the process with ls -la /proc/$pid/fd.
- Spoof a RST packet. You'll need to generate it locally and guess the SEQ number somehow.
- Maybe setup an iptables rule to generate a RST on the next packet.
- Write a kernel module.
There doesn't seem to be a well supported way to do this. It is likely that processes will crash if their FDs are unexpectedly closed anyway.
To "kill" a socket, you must send a TCP reset packet. To send it (and be accepted by the other side), you must know the actual TCP sequence number.
1) The already mentioned tcpkill
method learns the SEQ number by passively sniffing on the network and waiting for valid packets of this connection to arrive. Then it uses the learned SEQ number to send RSET packets to both sides. However if the connection is idle/hanged and no data flows, it won't do anything and will wait forever.
2) Another method uses perl script called killcx
(link to Sourceforge). This actively sends spoofed SYN packets and learns the SEQ number from the answer. It then sends RSET packets the same way as tcpkill
.
Alternatively approach (based on what you want to achieve) is to use gdb
debugger to attach to a process owning this socket/connection and issue close()
syscall on its behalf - as detailed in this answer.
If you want to deal only with hanged connections (the other side is dead), there are various timeouts (TCP keepalive for example), which should automatically close such connections if configured properly on the system.
实际操作其实用iptable会更方便一点:
iptables -A INPUT/OUTPUT/FORWARD -p TCP ...(match元组信息) -j REJECT--reject-with tcp-reset
和9.98.31.137:22 建立了22端口连接:
root:~# netstat -tuanp|grep :22
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1334088/sshd
tcp 0 0 9.84.31.220:59834 9.98.31.137:22 ESTABLISHED 1337907/ssh
现在用iptables kill掉这个session 连接:
root:~# iptables -A OUTPUT -p tcp --dport 22 -d 9.98.31.137 -j REJECT --reject-with tcp-reset
root:~#
root:~#
root:~# iptables -nvL|grep '9.98.31.137'
2 164 REJECT tcp -- * * 0.0.0.0/0 9.98.31.137 tcp dpt:22 reject-with tcp-reset
session 已经不存在了:
root:~# netstat -tuanp|grep :22
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1334088/sshd
ssh terminal 断开了连接:
[root@cnwbzp3137 ~]# client_loop: send disconnect: Broken pipe
allen:~$
allen:~$
重新发起ssh 连接也会出现refuse:
allen:~$ ssh root@cnwbzp3137.cn.dst.ibm.com
ssh: connect to host cnwbzp3137.cn.dst.ibm.com port 22: Connection refused
如果使用drop:
root:~# iptables -A OUTPUT -p tcp --dport 22 -d 9.98.31.137 -j DROP
root:~#
root:~#
root:~# iptables -nvL|grep '9.98.31.137'
35 30112 DROP tcp -- * * 0.0.0.0/0 9.98.31.137 tcp dpt:22
root:~#
ssh session 出现timeout 退出:
[root@cnwbzp3137 ~]# Timeout, server cnwbzp3137.cn.dst.ibm.com not responding.
allen:~$
allen:~$
session先FIN_WAIT, 然后退出:
root:~# netstat -tuanp|grep :22
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1341464/sshd
tcp 0 1589 9.84.31.220:60362 9.98.31.137:22 FIN_WAIT1 -
root:~#
root:~# netstat -tuanp|grep :22
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1341464/sshd
SSH连接无任何响应(直接drop,无回应)最后timeout
allen:~$ ssh root@cnwbzp3137.cn.dst.ibm.com
allen:~$ ssh root@cnwbzp3137.cn.dst.ibm.com
ssh: connect to host cnwbzp3137.cn.dst.ibm.com port 22: Connection timed out
allen:~$
如果是用input,是没有效果的:
root:~# iptables -A INPUT -p tcp --dport 22 -d 9.98.31.137 -j REJECT --reject-with tcp-reset
root:~#
root:~# iptables -nvL|grep '9.98.31.137'
0 0 REJECT tcp -- * * 0.0.0.0/0 9.98.31.137 tcp dpt:22 reject-with tcp-reset
连接始终存在:
root:~# netstat -tuanp|grep :22
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1341464/sshd
tcp 0 0 9.84.31.220:32792 9.98.31.137:22 ESTABLISHED 1346751/ssh
root:~#
[root@cnwbzp3137 ~]# less /usr/local/ch.log
[root@cnwbzp3137 ~]#
[root@cnwbzp3137 ~]#
使用forward也是没有效果:
root:~# iptables -A FORWARD -p tcp -d 9.98.31.137 -j REJECT --reject-with tcp-reset
root:~#
root:~# iptables -nvL|grep '9.98.31.137'
0 0 REJECT tcp -- * * 0.0.0.0/0 9.98.31.137 reject-with tcp-reset
连接始终存在:
root:~# netstat -tuanp|grep :22
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1341464/sshd
tcp 0 0 9.84.31.220:32792 9.98.31.137:22 ESTABLISHED 1346751/ssh
[root@cnwbzp3137 ~]# uptime
10:35:36 up 39 days, 15:11, 3 users, load average: 0.60, 0.33, 0.29
[root@cnwbzp3137 ~]#
How to use tcpkill:
Linux: How to kill a TCP connection using netstat?You cannot kill a TCP connection using netstat utility. netstat is use for
However Linux support two other commands or utility that can be used to kill a TCP connection. tcpkill commandUse tcpkill command to kill specified in-progress TCP connections. It is useful for libnids-based applications which require a full TCP 3-whs for TCB creation. Syntax: tcpkill -i eth0 { expression } Examples: (a) Kill all outgoing ftp (port 21) connection:tcpkill -i eth0 port 21 (b) Kill all all packets arriving at or departing from host 192.168.1.2 (host12.nixcraft.com)tcpkill host 192.168.1.2 ORtcpkill host host12.nixcraft.com (c) To kill all IP packets between 192.168.1.2 and any host except 192.168.1.111, type the following: tcpkill ip host 192.168.1.2 and not 192.168.1.111 Since tcpkill expressions are based upon tcpdump command's filter expression, it is recommended that you read options with expression and examples. |
使用ss来kill
On linux kernel >= 4.9 you can use the ss
command from iproute2 with key -K
ss -K dst client1.something dport = 49987
the kernel have to be compiled with CONFIG_INET_DIAG_DESTROY
option enabled.