【问题标题】:How to identify a specific socket between User Space and Kernel Space?如何识别用户空间和内核空间之间的特定套接字?
【发布时间】:2013-09-21 00:30:38
【问题描述】:

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

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

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

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

谢谢。

【问题讨论】:

  • 你的最终目标是什么?也许有人可以提出更好的方法。
  • 为什么不引入一个新的套接字选项?
  • @artistoex 你真的能做到吗?如果有,有链接吗?
  • 是的。 tcp 的套接字选项在include/linux/tcp.h 中定义并在net/ipv4/tcp.c:do_tcp_setsockopt() 中处理
  • 我明白了。通过 ioctl 接口将套接字提交给内核模块怎么样? PID 加上套接字文件描述符明确地识别套接字。

标签: c linux sockets tcp linux-kernel


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    首先你需要知道所有现有的连接都存储在一个全局哈希表——“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 锁,即使它本质上是全局的,也不要重新实现这些功能,只需重用它们即可。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-02
      • 2011-09-25
      • 1970-01-01
      • 1970-01-01
      • 2017-05-17
      • 2011-03-02
      • 1970-01-01
      相关资源
      最近更新 更多