用于确定进程拥有的套接字的 Linux API

Posted

技术标签:

【中文标题】用于确定进程拥有的套接字的 Linux API【英文标题】:Linux API to determine sockets owned by a process 【发布时间】:2010-12-31 02:56:58 【问题描述】:

是否有一个 Linux 库可以让我知道哪些 IP 套接字由哪些进程拥有?我想我正在寻找lsof -i 的程序等效项。最终,我想将通过libpcap 看到的数据包与进程相关联。

更新:有几个人建议使用/proc/<pid>/net/tcpudp,但在我的系统上,每个进程都显示相同的数据,所以没有帮助。 p>

【问题讨论】:

哇哦。我现在正在写一个程序来做这个,真是巧合 如果您有兴趣比较笔记,我现在有代码。我在 /proc 数据中看到了一些罕见的怪癖,但总体而言该方法有效。 【参考方案1】:

我认为您首先必须查看 /proc/*/fd 中打开的 fd,例如

4 -> socket:[11147]

然后在 /proc/net/tcp(或 /proc/net/udp)中查找引用的套接字(通过 inode),例如

12: B382595D:8B40 D5C43B45:0050 01 00000000:00000000 00:00000000 00000000  1000        0 11065 1 ffff88008bd35480 69 4 12 4 -1

【讨论】:

这是缺少的链接。谢谢! (由于某种原因不会让我投票。) 你在我写作的时候回答了这个问题,我没有注意到...干得好:) +1,因为 OP 显然不能。 如果两个示例中的 inode 相互匹配,这个答案可能会更好。 看/proc/XXX/net/tcp,里面只有pid为XXX的进程打开的socket。 fossilet, /proc//net/tcp 包含进程的网络命名空间中的所有 (tcp) 套接字,而不仅仅是进程打开的那些。【参考方案2】:

要确定进程拥有的套接字,您可以使用netstat。这是一个带有netstat 的输出(缩短)的示例,其中包含可以满足您需求的选项。

$ sudo netstat -apeen
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       User       Inode       PID/Program name
tcp        0      0 127.0.0.1:8118          0.0.0.0:*               LISTEN      138        744850      13248/privoxy   
tcp        0      0 127.0.0.1:5432          0.0.0.0:*               LISTEN      117        9612        2019/postgres   
udp        0      0 127.0.0.1:51960         127.0.0.1:51960         ESTABLISHED 117        7957        2019/postgres   
udp        0      0 0.0.0.0:68              0.0.0.0:*                           0          7740        1989/dhclient   
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags       Type       State         I-Node   PID/Program name    Path
unix  2      [ ACC ]     STREAM     LISTENING     7937     2019/postgres       /var/run/postgresql/.s.PGSQL.5432
unix  2      [ ACC ]     STREAM     LISTENING     958058   8080/emacs          /tmp/emacs1000/server
unix  2      [ ACC ]     STREAM     LISTENING     6969     1625/Xorg           /tmp/.X11-unix/X0
unix  2      [ ]         DGRAM                    9325     1989/dhclient       
unix  3      [ ]         STREAM     CONNECTED     7720     1625/Xorg           @/tmp/.X11-unix/X0

确保您以 root 身份运行 netstat,否则您将收到此消息:

(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)

netstat manpage 中-apeen 选项的解释:

-a, --all
    Show both listening and non-listening sockets. With the
    --interfaces option, show interfaces that are not up

-p, --program
    Show the PID and name of the program to which each socket
    belongs.

-e, --extend
    Display additional information. Use this option twice for
    maximum detail.

--numeric , -n
    Show numerical addresses instead of trying to determine symbolic host, port or user names.

--numeric-hosts
    shows numerical host addresses but does not affect the resolution of port or user names.

--numeric-ports
    shows numerical port numbers but does not affect the resolution of host or user names.

--numeric-users
    shows numerical user IDs but does not affect the resolution of host or port names.

【讨论】:

如果您向该进程的所有者发送 sudo(如果您无法获得 root),您可以获得 pid。对此解决方案 +1!谢谢! netstat 实际上会解析 /proc/net/tcp 等。参见,例如,here(/proc/net/tcp 的解析代码)。 lib/pathnames.h 中定义的 netstat 使用的路径。【参考方案3】:

/proc 文件系统提供每个进程的详细信息,包括网络信息。在/proc/net/tcp 中列出了打开的套接字信息。 IPv6 套接字在tcp6 文件中单独列出。套接字信息包括本地和远程端口、套接字inode号等信息,可以通过解析/proc/pid/fd/*信息映射回进程。

如果您不熟悉/proc 文件系统,它基本上是一个虚拟文件系统,允许内核将各种有用的信息发布到用户空间。这些文件通常是易于解析的简单结构化文本文件。

例如,在我的 Ubuntu 系统上,我使用 netcat 进行测试,并运行 nc -l -p 8321 监听 8321 端口。查看 tcp 套接字信息:

$ cat /proc/net/tcp
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode                                                     
   0: 00000000:2081 00000000:0000 0A 00000000:00000000 00:00000000 00000000  1000        0 26442 1 de0c8e40 300 0 0 2 -1                             
   1: 0100007F:0277 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 7019 1 de0c84c0 300 0 0 2 -1                              

第一行显示它正在监听到点 8321 (0x2081) 的所有地址。 inode 编号是 26442,我们可以使用它在/proc/pid/fd/* 中查找匹配的 pid,它由一堆从文件句柄编号到设备的符号链接组成。因此,如果我们查找netcat 的pid,并检查其fd 映射:

$ ls -l /proc/7266/fd
total 0
lrwx------ 1 gavinb gavinb 64 2009-12-31 09:10 0 -> /dev/pts/1
lrwx------ 1 gavinb gavinb 64 2009-12-31 09:10 1 -> /dev/pts/1
lrwx------ 1 gavinb gavinb 64 2009-12-31 09:10 2 -> /dev/pts/1
lrwx------ 1 gavinb gavinb 64 2009-12-31 09:10 3 -> socket:[26442]

我们看到这个进程中的文件描述符 3 被映射到 inode 26442 的套接字,正如我们所期望的那样。

显然,要构建完整的套接字映射,您需要首先枚举所有/proc/**/fd/* 文件,查找套接字符号链接,然后将套接字inode 与/proc/net/tcp 中具有端点信息的表进行匹配。

这就是lsof 工具的工作方式(请参阅lsof/dialects/linux/dsocket.c 了解实现)。

Wikipedia on procfs The Linux /proc filesystem as a Programmer's Tool

【讨论】:

与我对 Kimvais 的问题相同:/proc/*/net/tcp 目录为不同的 pid 显示相同的数据。如何将每个映射回源 pid? 我已经更新了答案,以包含有关如何将套接字映射到 pid 的完整描述。我希望这现在更清楚了——它基本上涉及为套接字 inode 构建一个 pid 表,并在 tcp 套接字表中查找这些 inode。让我知道是否有任何需要澄清的地方。【参考方案4】:

/proc/<pid>/net 等同于 /proc/net 与您在同一网络命名空间中的所有进程 - 换句话说,它是“全局”信息。

您可以执行 lsoffuser 所做的事情,即遍历 /proc/<pid>/fd/*/proc/net/* 寻找匹配的 inode。快速演示:

#!/bin/sh
pgrep "$@" | while read pid; do
    for fd in /proc/$pid/fd/*; do
        name=$(readlink $fd)
        case $name in
            socket:\[*\])
                ino=$name#*:
                for proto in tcp:10 tcp6:10 udp:10 udp6:10 unix:7; do
                    [[ ! -e /proc/net/$proto%:* ]] ||
                    awk "
                        \$$proto##*: == $ino:1:$#ino-2 
                            print \"$proto%:*:\", \$0
                            exit 1
                        
                    " /proc/net/$proto%:* || break
                done
                ;;
        esac
    done
done

您可以将其扩展到其他协议(我在 /proc/net/ 中也看到 ax25、ipx、packet、raw、raw6、udplite、udp6lite)或用您选择的语言重写。

【讨论】:

【参考方案5】:

您可以从 proc 文件系统中读取它们。您可能想要查看的“文件”位于 /proc/<pid>/net(即tcp、udp、unix)

这里有一些关于使用 proc 文件系统的examples

【讨论】:

也许我遗漏了一些东西,但是 /proc/*/net/tcp 为不同的 pid 显示了相同的数据。必须显示所有连接。如何将每个映射回源 pid?【参考方案6】:

您可以尝试使用 strace 运行 lsof 并查看它从 /proc 中的哪些文件获取数据。

【讨论】:

【参考方案7】:

我会去源头:

http://ubuntuforums.org/showthread.php?t=1346778

【讨论】:

以上是关于用于确定进程拥有的套接字的 Linux API的主要内容,如果未能解决你的问题,请参考以下文章

关闭 OTP 主管拥有的 gen_tcp 侦听套接字

Linux 进程间套接字通信(Socket)基础知识

线程与进程

Linux-进程间通信: 域套接字

linux高级编程之socket进程通信

Python 通过套接字发送命令