我有一个网络客户端,它被困在recvfrom不受我控制的服务器中,24 小时以上后,该服务器可能永远不会响应。该程序已经处理了大量的数据,所以我不想杀死它;我希望它放弃当前的连接并继续。(如果返回 EOF 或 -1,它将正确执行此操作recvfrom。)我已经尝试了几种不同的程序,这些程序声称能够通过伪造 RST ( tcpkill、cutter、killcx) 来断开陈旧的 TCP 通道;没有任何效果,程序仍然停留在recvfrom. 我也尝试过关闭网络接口;再次,没有效果。
在我看来,确实应该有一种方法可以在套接字 API 级别强制断开连接,而无需伪造网络数据包。我不介意可怕的黑客攻击,包括手动刺探内核数据结构;这是灾难恢复的情况。有什么建议么?
(为清楚起见,根据 ,此处涉及的 TCP 通道处于 ESTABLISHED 状态lsof。)
我不介意可怕的黑客攻击
这就是你要说的。我猜您尝试的工具不起作用,因为它们会嗅探流量以获得可接受的 ACK 编号来终止连接。如果没有流量,他们就无法控制它。
您可以尝试以下操作:
这些工具失败的地方你仍然可以做到。制作一个简单的 python 脚本,并使用 scapy,为每个序列号发送一个RST包含正确 4 元组(端口和地址)的段。最多有 40 亿(实际上假设有一个像样的窗口的话会更少 - 你可以使用 免费找到窗口ss -i)。
让内核模块获取 TCP 套接字列表:查找sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[i].chain)
识别你的受害者sk
此时,您可以亲密地访问您的套接字。所以
你可以打电话tcp_reset或者tcp_disconnect上就可以了。您将无法tcp_reset直接调用(因为它没有EXPORT_SYMBOL),但您应该能够模仿它:它调用的大多数函数都是导出的
或者你可以从中获取预期的ACK号tcp_sk(sk)并直接伪造一个RST数据包scapy
这是我用来打印已建立的套接字的函数 - 我从内核中搜寻了一些东西来制作它:
#include <net/inet_hashtables.h>
#define NIPQUAD(addr) \
((unsigned char *)&addr)[0], \
((unsigned char *)&addr)[1], \
((unsigned char *)&addr)[2], \
((unsigned char *)&addr)[3]
#define NIPQUAD_FMT "%u.%u.%u.%u"
extern struct inet_hashinfo tcp_hashinfo;
/* Decides whether a bucket has any sockets in it. */
static inline bool empty_bucket(int i)
{
return hlist_nulls_empty(&tcp_hashinfo.ehash[i].chain);
}
void print_tcp_socks(void)
{
int i = 0;
struct inet_sock *inet;
/* Walk hash array and lock each if not empty. */
printk("Established ---\n");
for (i = 0; i <= tcp_hashinfo.ehash_mask; i++) {
struct sock *sk;
struct hlist_nulls_node *node;
spinlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, i);
/* Lockless fast path for the common case of empty buckets */
if (empty_bucket(i))
continue;
spin_lock_bh(lock);
sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[i].chain) {
if (sk->sk_family != PF_INET)
continue;
inet = inet_sk(sk);
printk(NIPQUAD_FMT":%hu ---> " NIPQUAD_FMT
":%hu\n", NIPQUAD(inet->inet_saddr),
ntohs(inet->inet_sport), NIPQUAD(inet->inet_daddr),
ntohs(inet->inet_dport));
}
spin_unlock_bh(lock);
}
}
Run Code Online (Sandbox Code Playgroud)
您应该能够将其弹出到一个简单的“Hello World”模块中,在插入它之后,dmesg您将看到套接字(非常类似于ss或netstat)。