强制套接字断开而不伪造RST,Linux

zwo*_*wol 4 sockets linux tcp

我有一个网络客户端,它被困在recvfrom不受我控制的服务器中,24 小时以上后,该服务器可能永远不会响应。该程序已经处理了大量的数据,所以我不想杀死它;我希望它放弃当前的连接并继续。(如果返回 EOF 或 -1,它将正确执行此操作recvfrom。)我已经尝试了几种不同的程序,这些程序声称能够通过伪造 RST ( tcpkillcutterkillcx) 来断开陈旧的 TCP 通道;没有任何效果,程序仍然停留在recvfrom. 我也尝试过关闭网络接口;再次,没有效果。

在我看来,确实应该有一种方法可以在套接字 API 级别强制断开连接,而无需伪造网络数据包。我不介意可怕的黑客攻击,包括手动刺探内核数据结构;这是灾难恢复的情况。有什么建议么?

(为清楚起见,根据 ,此处涉及的 TCP 通道处于 ESTABLISHED 状态lsof。)

cni*_*tar 5

我不介意可怕的黑客攻击

这就是你要说的。我猜您尝试的工具不起作用,因为它们会嗅探流量以获得可接受的 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您将看到套接字(非常类似于ssnetstat)。