天天看点

如何干掉一条tcp 连接(活跃/非活跃)

最近在测试环境部署服务的时候老是会有端口被占用情况用netstat/ss 查看后发现端口一直被占用

同另外一个ip 建立了tcp 连接,类似于这样:

当然这个问题也不是最近才遇到,之前也遇到过,不过之前都是很快这个连接就自动消失,我就可以欢快

的使用我自己喜欢的12345 端口,无奈这次一直连续好几天这个连接一直存在导致我一直无法使用这个端口。

google 果然告诉我答案,有个叫tcpkill 的工具(可以自行搜索一下),看到之后立即将源码下下来

编译了一把,按照提示将几个确实的包安装后编译成功,然后按照tcpkill 的帮助文档进行操作

执行上述命令后发现tcpkill 感觉像是处于hang 住状态,运行了半天也没见把这个连接干掉,为什么这个连接没干掉? 于是用 nc 测试了下,发现如下情况

对于上述现象好奇的看了下tcpkill 的源码

不难看出是每抓到一个符合条件的包回调一次tcp_kill_cb 函数,也就是说tcpkill 只有在这条

连接上还有数据传输才有可能被tcpkill 感知并干掉。

至此为什么我想干掉的那条tcp 连接没被干掉原因已经比较明朗了。不外乎以下两个原因:

按照以上分析tcpkill 是可以干掉一调活跃连接,那么对于一条非活跃连接或者半连接要如何干掉?

看了tcpkill 的代码,大致原理是捕捉到tcp 报文之后就知道了这条连接信息,然后

利用libnet 构造一条rst报文发回去直接rst 掉连接。于是在tcpkill 代码之上根据netstat/ss

看到的tcp 四元组信息构造了一条tst发送出去。

运行之后用tcpdump 抓包可以看到构造的rst 报文被顺利的发送出去,但是连接并没有

消失,也就是说tcp 可能根本就没响应此报文。对比tcpkill reset 部分代码后发现

还需要设置正确的系列号,突然明白为啥tcpkill 只能干掉活跃连接了,原来是需要

捕获流动的报文才能获取正确的系列号,利用此序列号构造出rst包才能reset掉tcp 连接。

那么如何才能获取一条非活跃连接的序列号呢?

主动发送一条syn包,获取应答后计算出正确的序列号。为啥要发送一个syn 包呢,因为syn包是一调

tcp 连接的开始,此时序列号还未产生,因此可以随机选取一个,当tcp 的一端收到这条syn 包后

会以ack报文进行应答,应答报文中会携带正确的序列号,因此我们只需要根据此序列号发送rst 包

就可以将此连接reset 掉。

我们可以结合nc抓包看看:

前三个报文是正常建立tcp 连接的报文,至此nc 已经和服务器建立了一条连接,此时连接

上是没有任何数据的。

第四条报文是我们构造出来并主动发送的syn报文

第五条报文是针对第四条报文给出的应答

第六条报文是tcpkill 获取第五条应答报文后计算出正确的序列号发送的rst报文。

至此问题解决。

注:按照上述原理修改了tcpkill 源码,使其能够主动kill 掉非活跃连接及半连接

<a href="http://site-img-data.oss-cn-shanghai.aliyuncs.com/tcpkill/tcpkill_v2.tar.gz">http://site-img-data.oss-cn-shanghai.aliyuncs.com/tcpkill/tcpkill_v2.tar.gz</a>

继续阅读