关于C#:如何识别用户空间和内核空间之间的特定套接字?

How to identify a specific socket between User Space and Kernel Space?

我在用户空间中有一个库,可以拦截 socket()connect()accept() 等套接字层调用。我只处理 TCP 套接字。

在内核空间我有一个网络内核模块,它处理所有的 TCP 连接。我需要能够在驱动程序中识别用户空间库拦截了哪些套接字。

到目前为止,我一直在使用 struct sock(内核)中的 priority 字段,我可以在用户空间中使用 setsockopt() 进行设置。但那是一个相当肮脏的 hack。

是否有任何类型的 struct sock 私有字段我可以通过 setsockopt() 从用户空间安全使用和设置?

谢谢。


确实没有这样的"私有域"选项可以单独由用户空间和您的内核代码使用。

使用 SO_PRIORITY 选项似乎有点太侵入性,因为它可以改变堆栈处理数据包的方式,并且可能导致难以理解的结果。更安全的选择是将 SO_RCVBUFSO_SNDBUF 值从通常的默认值调整一些小的增量。 Linux 会将传入的值加倍,但您可以从默认值中查找增量,并知道增量的存在表明这是您的"拦截"套接字。


回答您最初的问题"我需要能够在驱动程序中识别用户空间库拦截了哪些套接字。"实际上有几个功能。

首先你需要知道所有现有的连接都存储在一个全局哈希表——"tcp_hashinfo"中,你可以在/proc/kallsyms中找到地址。

主要的函数是__inet_lookup_skb(),它调用了__inet_lookup(),分为__inet_lookup_established()(寻找已经建立的任何匹配的sockets)和__inet_lookup_listener()(寻找打开的监听器,但还没有建立连接) .

查找所需的主要输入是源/目标端口和 IP 地址信息,如果找到返回的指针是指向套接字的"struct sock *"。

IPv6 的名字和逻辑差不多。

函数 (__inet_lookup_skb()) 被声明为"静态内联" - 它无法从 /proc/kallsyms 中找到,驱动程序也无法看到它,因为它是内联编译的。但这没有问题,因为这调用了另外两个函数 - inet_lookup_listener() 和 inet_lookup_established() ,它们不是内联编译的。它的符号已导出,因此您可以安全地从内核模块中使用它。

读取此 hashinfo 表是一项关键操作,这一点很重要 - 多个 CPU 可能同时对其进行读取/写入,这就是为什么在读取完成时在函数的开头/结尾进行锁定的原因,以防止在阅读时被修改。由于很难访问这些 RCU 锁,即使它本质上是全局的,也不要重新实现这些功能,只需重用它们即可。