4

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

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

(为了清楚起见,这里讨论的 TCP 通道根据lsof.)处于 ESTABLISHED 状态。)

4

2 回答 2

4

我不介意可怕的黑客攻击

这就是你要说的。我猜您尝试的工具不起作用,因为它们会嗅探流量以获取可接受的 ACK 号以终止连接。如果没有流量,他们就无法掌握它。

您可以尝试以下方法:

探测所有序列号

在那些工具失败的地方,你仍然可以做到。使用 scapy 制作一个简单的 python 脚本,为每个序列号发送一个RST带有正确 4 元组(端口和地址)的段。最多有 40 亿个(假设一个像样的窗口实际上更少 - 你可以免费使用找到窗口ss -i)。

制作一个内核模块来获取套接字

  • 使内核模块获取 TCP 套接字列表:查找sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[i].chain)

  • 识别你的受害者 sk

此时,您可以密切访问您的套接字。所以

  • 你可以打电话tcp_resettcp_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);
    }
}

您应该能够将它弹出到一个简单的“Hello World”模块中,在安装它之后,dmesg您将看到套接字(很像ssor netstat)。

于 2013-09-25T21:54:30.207 回答
1

我知道您想要做的是自动化进行测试的过程。但是,如果您只想检查对 recvfrom 错误的正确处理,您可以附加 GDB 并使用 close() 调用关闭 fd。

在这里你可以看到一个例子。

另一种选择是使用 scapy 来制作适当的 RST 数据包(这不在您的列表中)。这是我在桥接系统中测试连接 RST 的方式(恕我直言,这是最好的选择),您还可以实现优雅关闭。

是 scapy 脚本的示例。

于 2013-09-26T08:10:10.593 回答