tcpkill工作原理分析

Easter79
• 阅读 595

此文已由作者张耕源授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。

日常工作生活中大家在维护自己的服务器、VPS有时会碰到这样的情况:服务器上突然出现了许多来自未知ip的网络连接与流量,我们需要第一时间切断这些可能有害的网络连接。除了iptables/ipset, blackhole routing这些常规手段,我们还可以借助一些更轻量级的小工具来临时处理这些情况,如tcpkill。

tcpkill使用简介

tcpkill是一个网络分析工具集dsniff中的一个小工具。在Debian/Ubuntu上可以直接通过dsniff包安装:

# aptitude install dsniff

tcpkill使用的语法和tcpdump几乎一致:

tcpkill [-i interface] [-1...9] expression

其中第一个参数 -i 指定网卡设备。

第二个参数指定“kill”的强制等级,越高越强,默认为3,我们在后面了解tcpkill的工作原理后会知道这个参数的具体作用。

第三个参数则是匹配需要kill的tcp连接通配表达式,语法与tcpdump使用的pcap-filter完全一样。

如果我们需要使用tcpkill临时禁止服务器与主机10.0.0.1的tcp连接,可以在服务器上输入命令:

# tcpkill host 10.0.0.1

tcpkill会一直阻止主机10.0.0.1与服务器的网络连接,直到你结束这个tcpkill进程为止。

tcpkill原理分析

在使用tcpkill时,会发现一件奇怪的事情,运行tcpkill命令后并不会马上中断匹配的tcp连接,只有当该连接有新的tcp包发送接收时,tcpkill才会“kill”这个tcp连接。这个奇怪的现象燃起了我们的好奇心,于是探索一下tcpkill到底是如何工作的。

下面以Linux下的nc命令为例。

我们在两个主机hostA与hostB间通过nc命令建立一个tcp连接:

hostA在本地tcp 5555端口监听

hostA$ nc -l -p 5555

hostB通过本地6666端口连接hostA的5555端口

hostB$ nc hostA 5555 -p 6666

此时在hostA上已经可以观察到一条与hostB的ESTABLISHED连接

hostA$ netstat -anp|grep 5555tcp        0      0 hostA:5555    hostB:6666     ESTABLISHED 19638/nc

在hostA上通过tcpdump也可以观察到3次握手已经完成

hostA# tcpdump -i eth1 port 5555IP hostB.6666 > hostA.5555: Flags [S], seq 750827752, ...IP hostA.5555 > hostB.6666: Flags [S.], seq 1191909671, ack 750827753, ...IP hostB.6666 > hostA.5555: Flags [.], ack 1, win 115, ...

如果此时运行tcpkill命令尝试“kill”这个tcp连接

hostA# tcpkill -1 -i eth1 port 5555tcpkill: listening on eth1 [port 5555]

会发现hostA与hostB上的nc命令并没有受到任何影响而退出,hostA上观察到该tcp连接还是ESTABLISHED状态,tcpdump与tcpkill也没有任何新的输出。

hostA$ netstat -anp|grep 5555tcp        0      0 hostA:5555    hostB:6666     ESTABLISHED 19638/nc

运行tcpkill命令后,建立好的tcp连接并没有受到任何影响。

如果我们此时在hostB的nc上输入任意字符发送,则会发现这时tcp连接中断,nc发送失败退出。

hostB$ nc hostA 5555 -p 6666a<CR>(exit)
hostB$

hostA上的nc监听进程也因为连接中断而退出

hostA$ nc -l -p 5555(exit)
hostA$

netstat已经观察不到这个tcp连接,而tcpdump此时则捕获了一个新tcp rst包:

hostA# tcpdump -i eth1 port 5555IP hostB.6666 > hostA.5555: Flags [S], seq 750827752, ...IP hostA.5555 > hostB.6666: Flags [S.], seq 1191909671, ack 750827753, ...IP hostB.6666 > hostA.5555: Flags [.], ack 1, win 115, ...IP hostA.5555 > hostB.6666: Flags [R], seq 1191909672, ...

此时tcpkill的输出

hostA# tcpkill -1 -i eth1 port 5555tcpkill: listening on eth1 [port 5555]hostB:6666 > hostA:5555: R 1191909672:1191909672(0) win 0hostA:5555 > hostB:6666: R 750827755:750827755(0) win 0

相信看到这里,已经可以明白tcpkill的工作原理,实际上就是通过双向fake tcp rst包重置目标连接双方的网络连接,和某墙的原理一样。

而之所以tcpkill不会马上中断目标tcp连接,是因为伪造tcp rst包时,需要填入正确的sequence number,这需要通过拦截双方的tcp通信才能实时得到。所以运行tcpkill后,只有目标连接有新tcp包发送/接受才会导致tcp连接中断。

最后分析一下tcpkill第二个参数的具体作用。manpage里的说明比较模糊,只能看出和receive window有关:

-1...9 Specify the degree of brute force to use in killing a connection. Fast connections may require a higher number in order to land a RST in the moving receive window. Default is 3.

直接看源代码(只有100多行)

...intmain(int argc, char *argv[]){
    ...    /* 通过libpcap抓取所有符合条件的包,回调函数为tcp_kill_cb */
    pcap_loop(pd, -1, tcp_kill_cb, (u_char *)&sock);

    ...
}static voidtcp_kill_cb(u_char *user, const struct pcap_pkthdr *pcap, const u_char *pkt){
    ...    /* 只处理tcp包 */
    ip = (struct libnet_ip_hdr *)pkt;    if (ip->ip_p != IPPROTO_TCP)        return;    /* 不处理tcp syn/fin/rst包 */
    tcp = (struct libnet_tcp_hdr *)(pkt + (ip->ip_hl << 2));    if (tcp->th_flags & (TH_SYN|TH_FIN|TH_RST))        return;            /* 伪造ip包 */
    libnet_build_ip(TCP_H, 0, 0, 0, 64, IPPROTO_TCP,
            ip->ip_dst.s_addr, ip->ip_src.s_addr,
            NULL, 0, buf);    /* 伪造tcp rst包 */
    libnet_build_tcp(ntohs(tcp->th_dport), ntohs(tcp->th_sport),            0, 0, TH_RST, 0, 0, NULL, 0, buf + IP_H);    /* fake tcp rst包的sequence number即为抓到的包的ack number */
    seq = ntohl(tcp->th_ack);

    ...    /* 这里Opt_severity即为tcpkill的第二个参数 */
    win = ntohs(tcp->th_win);    for (i = 0; i < Opt_severity; i++) {
        ip->ip_id = libnet_get_prand(PRu16);
        seq += (i * win);
        tcp->th_seq = htonl(seq);

        libnet_do_checksum(buf, IPPROTO_TCP, TCP_H);                    /* 发送伪造的tcp rst包 */
        if (libnet_write_ip(*sock, buf, sizeof(buf)) < 0)
            warn("write_ip");

        fprintf(stderr, "%s R %lu:%lu(0) win 0\n", ctext, seq, seq);
    }
}

从上面可以看出,tcpkill的第二个参数,实际上就是沿tcp连接窗口滑动而发送的tcp rst包个数。将这个参数设置较大主要是为了应对高速tcp连接的情况。

参数的大小从中断tcp连接的原理上没有区别,只是发送rst包数量的差异,通常情况下使用默认值3已经完全没有问题了。所以使用tcpkill时请不要像网络上某些中文教程中一样不适当的使用参数 -9 。

免费体验云安全(易盾)内容安全、验证码等服务

更多网易技术、产品、运营经验分享请点击

相关文章:
【推荐】 从互联网+角度看云计算的现状与未来

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
2年前
MySQL MGR实现分析
此文已由作者温正湖授权网易云社区发布。欢迎访问网易云社区(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fsq.163yun.com%2Fblog%3Ftag%3DM_tg_456_65),了解更多网易技术产品运营经验。MySQLGroupReplication(
Wesley13 Wesley13
2年前
DDoS防护之TCP防护
欢迎访问网易云社区(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fsq.163yun.com%2Fblog%3Ftag%3DM_tg_767_64),了解更多网易技术产品运营经验。TCP协议,相信对于每一个开发工程师都不陌生。由于该协议是一个面向连接,可靠的特性,广泛应用于
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
2年前
MySQL多线程备份工具mydumper
此文已由作者温正湖授权网易云社区发布。欢迎访问网易云社区(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fsq.163yun.com%2Fblog%3Ftag%3DM_tg_427_64),了解更多网易技术产品运营经验。一、RDS外部实例迁移需求RDS
Easter79 Easter79
2年前
TiDB和MongoDB分片集群架构比较
此文已由作者温正湖授权网易云社区发布。欢迎访问网易云社区(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fsq.163yun.com%2Fblog%3Ftag%3DM_tg_445_64),了解更多网易技术产品运营经验。最近阅读了TiDB源码的说明文档(https
Wesley13 Wesley13
2年前
35岁是技术人的天花板吗?
35岁是技术人的天花板吗?我非常不认同“35岁现象”,人类没有那么脆弱,人类的智力不会说是35岁之后就停止发展,更不是说35岁之后就没有机会了。马云35岁还在教书,任正非35岁还在工厂上班。为什么技术人员到35岁就应该退役了呢?所以35岁根本就不是一个问题,我今年已经37岁了,我发现我才刚刚找到自己的节奏,刚刚上路。
Stella981 Stella981
2年前
Spring Cloud使用总结
本文来自网易云社区(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fsq.163yun.com%2Fblog%3Ftag%3DM_tg_360_64),转载务必请注明出处。SpringCloud是spring团队推出的基于SpringBoot的分布式微服务框架,为开发者提
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k