首頁 > 軟體

kill一條TCP連線實現方法詳解

2022-11-03 14:02:10

簡介

如果你的程式寫得有毛病,開啟了很多TCP連線,但一直沒有關閉,即常見的連線洩露場景,你可能想要在排查問題的過程中,先臨時kill一波洩露的連線。

又比如你要驗證程式在遇到網路錯誤時的自愈能力,想手動kill掉一些正常TCP連線,看程式是否能自動重連並恢復執行。

這些場景,都需要手動kill一部分TCP連線,那在Linux下有哪些kill連線的方法呢?

kill活躍的TCP連線

使用ngrep或tcpkill命令可以殺死活躍狀態的TCP連線,用法如下:

# ngrep殺死連線
$ sudo ngrep -d any -K3 '' 'port 54690'
# 安裝tcpkill,及使用其殺死連線
$ sudo apt install dsniff  
$ sudo tcpkill -i any 'port 45308'

如上所示,可以發現在殺死連線時,ngrep和tcpkill都向連線方傳送了RST包。

實現原理

學過《計算機網路》的同學都知道,TCP協定是通過FIN包與ACK包來做四次揮手,從而斷開TCP連線的,這是正常的TCP斷連過程,但TCP協定中還有RST包,這種包用於異常情況下斷開連線,Linux在收到RST包後,會直接關閉本端的Socket連線,而不需要經歷四次揮手過程。

而上面的ngrep與tcpkill命令,正是通過給對方傳送RST包,從而實現殺死TCP連線的。但要傳送一個正確的RST包,需要知道TCP連線互動時所使用的序列號(seq),因為亂序的包會被TCP直接丟棄,所以ngrep和tcpkill還會監聽網路卡上互動的包,以找到指定連線所使用的序列號seq。

所以,ngrep與tcpkill只能kill有流量的活躍TCP連線,對於空閒連線就無法處理了。

kill空閒的TCP連線

對於空閒狀態的TCP連線,可以用ss或hping3命令來處理,如下:

使用ss殺死連線

通過ss命令的-K選項可以用來kill連線,如下:

# 安裝ss命令
$ sudo apt install iproute2
# 使用ss殺死目標埠為65987的連線
$ sudo ss -K dport = 65987

注意,使用這個功能需要你的核心版本>=4.9,且開啟了CONFIG_INET_DIAG_DESTROY選項,因此某些情況下可能無法使用。

使用hping3殺死連線

如果無法使用ss命令,則可以考慮使用hping3命令來kill連線,hping3命令可以發任何型別的TCP包,因此只要模擬tcpkill的原理即可,如下:

  • 通過傳送SYN包來獲取seq

上面提到了,TCP協定會直接丟棄亂序的封包,但是對於SYN包卻區別對待了,如果你隨便發一個SYN包給已連線狀態的Socket,它會回覆一個ACK,並攜帶有正確的seq序列號,如下:

# 第一個引數,表示傳送包的目標ip地址
# -a:設定包的源ip地址
# -s:設定包的源埠
# -p:設定包的目標埠
# --syn:表示發SYN包
# -V:verbose output,使hping3輸出序列號seq
# -c:設定發包數量
$ sudo hping3 172.26.79.103 -a 192.168.18.230 -s 8080 -p 45316 --syn -V -c 1
using eth0, addr: 172.26.79.103, MTU: 1500
HPING 172.26.79.103 (eth0 172.26.79.103): S set, 40 headers + 0 data bytes
len=40 ip=172.26.79.103 ttl=64 DF id=16518 tos=0 iplen=40
sport=45316 flags=A seq=0 win=502 rtt=13.4 ms
seq=1179666991 ack=1833836153 sum=2acf urp=0

可以在輸出中找到,ack=1833836153即是對方回覆的序列號,我們用在後面的發RST包中。

  • 使用seq發RST包
# --rst:表示發RST包
# --win:設定TCP視窗大小
# --setseq:設定包的seq序列包
$ sudo hping3 172.26.79.103 -a 192.168.18.230 -s 8080 -p 45316 --rst --win 0 --setseq 1833836153 -c 1
HPING 172.26.79.103 (eth0 172.26.79.103): R set, 40 headers + 0 data bytes
--- 172.26.79.103 hping statistic ---
1 packets transmitted, 0 packets received, 100% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms

整個過程如下:

可以發現前面我們用lsof查到的連線,在傳送RST包後就查不到了,說明連線已經被kill了。整個操作看起來有點麻煩,可以自己寫個指令碼封裝一下。

以上就是kill一條TCP連線實現方法詳解的詳細內容,更多關於kill TCP連線的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com