4

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

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

到目前为止,我一直在使用可以在用户空间中设置的(内核)priority字段。但这是一个相当肮脏的黑客。struct socksetsockopt()

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

谢谢。

4

2 回答 2

6

确实没有这样的“私有字段”选项可以仅由用户空间和您的内核代码使用。

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

于 2013-09-16T20:00:15.063 回答
1

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

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

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

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

IPv6 具有相同的名称和相同的逻辑。

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

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

于 2015-03-03T00:22:46.473 回答