一招搞定TCP孤兒連接引起的端口占用!
周六群里大佬發了一篇文章,是關于TCP keepalive相關的,其中有一段是關于孤兒連接的,這里引用下
什么是孤兒連接?
以 redis 做實現吧,client 172.24.213.40, server 172.24.213.39. 在 client 端開啟兩個 session, 分別連接 server 和 tcpdump
會看到 client 每隔 15s 會發送空的 ACK 包給 server, 并收到 server 返回的 ACK, 實際上這就是 client 端的 tcp keepalive 在起作用。然后我們在 server 設置 iptables, 人為制造網絡隔離
- root@myali:~# iptables -I INPUT -s 172.24.213.40 -j DROP;iptables -I OUTPUT -d 172.24.213.40 -j DROP;iptables -nvL
過一會查看 client tcpdump 輸出
- 14:05:14.563481 IP 172.24.213.40.38470 > 172.24.213.39.6380: Flags [.], ack 11469, win 559, options [nop,nop,TS val 3222339035 ecr 1210531111], length 0
- 14:05:19.683482 IP 172.24.213.40.38470 > 172.24.213.39.6380: Flags [.], ack 11469, win 559, options [nop,nop,TS val 3222344155 ecr 1210531111], length 0
- 14:05:24.803489 IP 172.24.213.40.38470 > 172.24.213.39.6380: Flags [.], ack 11469, win 559, options [nop,nop,TS val 3222349275 ecr 1210531111], length 0
- 14:05:29.923486 IP 172.24.213.40.38470 > 172.24.213.39.6380: Flags [R.], seq 18, ack 11469, win 559, options [nop,nop,TS val 3222354394 ecr 1210531111], length 0
client 172.24.213.40 每 5s 發送一個 ACK 三次,最后發一個 RST 包銷毀連接。當然這個 RST redis-server 肯定也沒有接收到。過一會將 server 防火墻刪除
- root@myali:~# iptables -D INPUT -s 172.24.213.40 -j DROP;iptables -D OUTPUT -d 172.24.213.40 -j DROP;iptables -nvL
此時再分別查看網絡連接 ss -a | grep 6380, 會發現 client 端消失了,但是 server 端的還在,狀態仍然是 ESTAB
- root@myali:~# ss -a | grep 6380
- tcp ESTAB 0 0 172.24.213.39:6380 172.24.213.40:38470
這就是孤兒連接
孤兒連接會造成什么問題?
這種孤兒連接,首先會占用資源,然后如果你想處理,不管你通過什么方法,比如lsof查看占用該端口的進程,會發現,無法定位進程號,因為進程已經退出了,它不是進程層面的連接
還有一種運維常見的場景
此時如果你想啟動相同端口的應用,或者進程,還會發現端口已被占用,無法啟動,停止進程,會發現該TCP連接不屬于進程管理,無法停止
這個時候怎么做?介紹一款專門針對這種TCP連接的工具
Killcx
Killcx is a Perl script to close a TCP connection under Linux, whatever its state is (half-open, established, waiting or closing state).
這是官方的解釋,Killcx就是專門用來關閉Linux下TCP連接的,不管連接狀態是什么,半開、連接中、等待或關閉狀態
killcx的原理是要關閉的網絡連接,從TCP包中提取Acknowlegment和Sequence numbers,熟悉TCP四次揮手,結合上面孤兒連接造成的原因,你就能明白,其實就是client或者server端沒有收到SYN和ACK確認包,killcx就是通過偽造這兩個包,來完成最后沒完成的TCP交互
killcx使用方法如下:
- - syntax : killcx [dest_ip:dest_port] {interface}
- dest_ip : remote IP
- dest_port : remote port
- interface (optional) : network interface (eth0, lo etc).
- - example : killcx 120.121.122.123:1234
- killcx 120.121.122.123:1234 eth0
Killcx安裝
killcx的安裝包,可以直接從sourceforge下載,下載地址http://sourceforge.net/projects/killcx/files/
下載完成后,并不能直接執行,killcx官網介紹了它的依賴
- Perl modules needed :
- You need the following modules to run killcx :
- * Net::RawIP : needed to create spoofed packets.
- * Net::Pcap : needed to capture TCP packets.
- * NetPacket::Ethernet : needed to decode TCP/IP packets.
因為Killcx是perl腳本,它運行依賴三個Perl模塊,分別是Net::RawIp、Net::PCAP、NetPacket::Ethernet,這幾個模塊的安裝很簡單
- # 通過yum先安裝perl-CPAN
- yum -y install perl-CPAN
- # 利用CPAN安裝三個模塊
- perl -MCPAN -e shell
- cpan> install Net::RawIP
- cpan> install Net::Pcap
- cpan> install NetPacket::Ethernet
本文轉載自微信公眾號「運維研習社」,可以通過以下二維碼關注。轉載本文請聯系運維研習社公眾號。