Jon*_*art 68 process lsof open-files socket
我想确定哪个进程具有 UNIX 套接字的另一端。
具体来说,我问的是用 来创建的socketpair(),尽管任何 UNIX 套接字的问题都是一样的。
我有一个程序parent可以创建一个socketpair(AF_UNIX, SOCK_STREAM, 0, fds), 和fork()s。父进程关闭fds[1]并保持fds[0]通信。孩子反其道而行之,close(fds[0]); s=fds[1]。然后孩子exec()的另一个程序,child1。两者可以通过这个 socketpair 来回通信。
现在,假设我知道parent是谁,但我想弄清楚是谁child1。我该怎么做呢?
有几种工具可供我使用,但没有一个可以告诉我套接字的另一端是哪个进程。我试过了:
lsof -c prognamelsof -c parent -c child1ls -l /proc/$(pidof server)/fdcat /proc/net/unix基本上,我可以看到两个套接字以及关于它们的所有内容,但无法判断它们是否已连接。我试图确定父进程中的哪个 FD 正在与哪个子进程通信。
Sté*_*las 52
注意:我现在维护一个
lsof包装器,它结合了此处描述的两种方法,并在https://github.com/stephane-chazelas/misc-scripts/blob/master/lsofc 上添加了环回 TCP 连接对等点的信息
在 Linux 上,由于内核版本 3.3(并且如果该UNIX_DIAG功能内置在内核中),可以使用新的基于netlink的 API获取给定 unix 域套接字(包括 socketpairs)的对等点。
lsof 因为 4.89 版可以使用该 API:
lsof +E -aUc Xorg
Run Code Online (Sandbox Code Playgroud)
将列出所有具有名称Xorg以任一端开头的进程的 Unix 域套接字,格式类似于:
Xorg 2777 root 56u unix 0xffff8802419a7c00 0t0 34036 @/tmp/.X11-unix/X0 type=STREAM ->INO=33273 4120,xterm,3u
Run Code Online (Sandbox Code Playgroud)
如果您的版本lsof太旧,还有更多选择。
在ss(从实用程序iproute2)利用相同的API来检索和UNIX域套接字的系统,其包括对等体的信息的列表的显示信息的。
套接字由它们的inode 编号标识。请注意,它与套接字文件的文件系统 inode 无关。
例如在:
$ ss -x
[...]
u_str ESTAB 0 0 @/tmp/.X11-unix/X0 3435997 * 3435996
Run Code Online (Sandbox Code Playgroud)
它说套接字 3435997(绑定到 ABSTRACT 套接字/tmp/.X11-unix/X0)与套接字 3435996 连接。该-p选项可以告诉您哪个进程打开了该套接字。它通过在readlink上执行一些s 来/proc/$pid/fd/*做到这一点,因此它只能在您拥有的进程上执行此操作(除非您是root)。例如这里:
$ sudo ss -xp
[...]
u_str ESTAB 0 0 @/tmp/.X11-unix/X0 3435997 * 3435996 users:(("Xorg",pid=3080,fd=83))
[...]
$ sudo ls -l /proc/3080/fd/23
lrwx------ 1 root root 64 Mar 12 16:34 /proc/3080/fd/83 -> socket:[3435997]
Run Code Online (Sandbox Code Playgroud)
要找出哪个进程有 3435996,您可以在以下输出中查找它自己的条目ss -xp:
$ ss -xp | awk '$6 == 3435996'
u_str ESTAB 0 0 * 3435996 * 3435997 users:(("xterm",pid=29215,fd=3))
Run Code Online (Sandbox Code Playgroud)
您还可以使用此脚本作为包装器lsof来轻松显示相关信息:
lsof +E -aUc Xorg
Run Code Online (Sandbox Code Playgroud)
例如:
$ sudo that-lsof-wrapper -ad3 -p 29215 命令 PID 用户 FD 类型 设备大小/关闭节点名称 xterm 29215 stephane 3u unix 0xffff8800a07da4c0 0t0 3435996 type=STREAM <-> 3435997[Xorg,3080,@/tmp/.X11-unix/X0]
用于检索 unix 套接字信息的旧 Linux API 是通过/proc/net/unix文本文件。它列出了所有 Unix 域套接字(包括 socketpairs)。kernel.kptr_restrict正如@Totor 已经解释的那样,其中的第一个字段(如果没有使用sysctl 参数对非超级用户隐藏)包含一个unix_sock结构的内核地址,该结构包含一个peer指向相应peer 的字段unix_sock。这也是Unix 套接字上列的lsof输出DEVICE。
现在获取该peer字段的值意味着能够读取内核内存并知道该peer字段相对于unix_sock地址的偏移量。
已经给出了几个gdb基于和systemtap基于的解决方案,但它们需要gdb/systemtap和 Linux 内核调试符号来安装正在运行的内核,这在生产系统上通常不是这种情况。
硬编码偏移量并不是一个真正的选项,因为它随内核版本而变化。
现在,我们可以将决定使用启发式方法的偏差:有我们的工具来创建一个虚拟的socketpair(后来我们知道,这两个同龄人的地址),并搜索的地址对周围的内存在另一端,以确定偏移。
这是一个概念验证脚本,它使用perl(在 i386 上使用内核 2.4.27 和 2.6.32 以及在 amd64 上使用 3.13 和 3.16 成功测试)。像上面一样,它作为一个包装器工作lsof:
例如:
$ that-lsof-wrapper -aUc nm-applet 命令 PID 用户 FD 类型 设备大小/关闭节点名称 纳米小应用程序4183的Stephane 4U UNIX 0xffff8800a055eb40 0t0 36888型= STREAM - > 0xffff8800a055e7c0 [DBUS守护,4190,@ / TMP / DBUS-AiBCXOnuP6] 纳米小程序4183的Stephane 7U UNIX 0xffff8800a055e440 0t0 36890型= STREAM - > 0xffff8800a055e0c0 [Xorg则3080,@ / TMP / .X11-UNIX / X0] 纳米小程序4183的Stephane 8U UNIX 0xffff8800a05c1040 0t0 36201型= STREAM - > 0xffff8800a05c13c0 [DBUS守护,4118,@ / TMP / DBUS-yxxNr1NkYC] 纳米小程序4183的Stephane 11U UNIX 0xffff8800a055d080 0t0 36219型= STREAM - > 0xffff8800a055d400 [DBUS守护,4118,@ / TMP / DBUS-yxxNr1NkYC] 纳米小程序4183的Stephane 12U UNIX 0xffff88022e0dfb80 0t0 36221型= STREAM - > 0xffff88022e0df800 [DBUS守护,2268,/ VAR /run/dbus/system_bus_socket] nm-applet 4183 stephane 13u unix 0xffff88022e0f80c0 0t0 37025 type=STREAM -> 0xffff88022e29ec00[dbus-daemon,2268,/var/run/dbus/system_bus_socket]
这是脚本:
Xorg 2777 root 56u unix 0xffff8802419a7c00 0t0 34036 @/tmp/.X11-unix/X0 type=STREAM ->INO=33273 4120,xterm,3u
Run Code Online (Sandbox Code Playgroud)
Gil*_*il' 34
从内核 3.3 开始,可以使用ss或lsof-4.89或更高版本 - 请参阅Stéphane Chazelas 的回答。
根据作者的说法,在旧版本中lsof是不可能发现这一点的:Linux 内核不会公开这些信息。来源:2003 年 comp.unix.admin 上的线程。
中显示/proc/$pid/fd/$fd的数字是虚拟套接字文件系统中套接字的 inode 编号。创建管道或套接字对时,每一端都会连续收到一个 inode 编号。数字按顺序分配,因此数字相差 1 的可能性很高,但这不能保证(因为第一个套接字是N并且N +1 由于包装已经在使用中,或者因为其他一些线程在两个 inode 分配之间调度,并且该线程也创建了一些 inode)。
我查看了内核2.6.39中的定义,socketpair socket的两端除了type-specificsocketpair方法外没有关联。对于 unix 套接字,unix_socketpair在net/unix/af_unix.c.
Tot*_*tor 10
# ss -xp
Run Code Online (Sandbox Code Playgroud)
现在您可以在Peer列中看到一个 ID(inode 编号),它对应于该Local列中的另一个 ID 。匹配的 ID 是套接字的两端。
注意:UNIX_DIAG必须在内核中启用该选项。
Linux 没有将此信息公开给用户空间。
但是,通过查看内核内存,我们可以访问此信息。
注意:此答案是通过使用 来实现的gdb,但是,请参阅@StéphaneChazelas 的答案,该答案在这方面进行了更详细的说明。
# lsof | grep whatever
mysqld 14450 (...) unix 0xffff8801011e8280 (...) /var/run/mysqld/mysqld.sock
mysqld 14450 (...) unix 0xffff8801011e9600 (...) /var/run/mysqld/mysqld.sock
Run Code Online (Sandbox Code Playgroud)
有 2 个不同的套接字,1 个侦听和 1 个建立。六进制数是对应内核unix_sock结构的地址,有一个peer属性是套接字另一端的地址(也是一个unix_sock结构实例)。
现在我们可以使用gdb来查找peer内核内存:
# gdb /usr/lib/debug/boot/vmlinux-3.2.0-4-amd64 /proc/kcore
(gdb) print ((struct unix_sock*)0xffff8801011e9600)->peer
$1 = (struct sock *) 0xffff880171f078c0
# lsof | grep 0xffff880171f078c0
mysql 14815 (...) unix 0xffff880171f078c0 (...) socket
Run Code Online (Sandbox Code Playgroud)
在这里,套接字的另一端由mysqlPID 14815 保存。
您的内核必须编译KCORE_ELF为使用/proc/kcore. 此外,您需要一个带有调试符号的内核映像版本。在 Debian 7 上,apt-get install linux-image-3.2.0-4-amd64-dbg将提供此文件。
如果您没有(或不想保留)系统上的调试内核映像,您可以提供gdb内存偏移量以“手动”访问该peer值。此偏移值通常因内核版本或架构而异。
在我的内核上,我知道偏移量为 680 字节,即 85 乘以 64 位。所以我可以这样做:
# gdb /boot/vmlinux-3.2.0-4-amd64 /proc/kcore
(gdb) print ((void**)0xffff8801011e9600)[85]
$1 = (void *) 0xffff880171f078c0
Run Code Online (Sandbox Code Playgroud)
瞧,结果和上面一样。
如果您在多台机器上运行相同的内核,则使用此变体会更容易,因为您不需要调试映像,只需要偏移值。
要(轻松)首先发现此偏移值,您确实需要调试映像:
$ pahole -C unix_sock /usr/lib/debug/boot/vmlinux-3.2.0-4-amd64
struct unix_sock {
(...)
struct sock * peer; /* 680 8 */
(...)
}
Run Code Online (Sandbox Code Playgroud)
给你,680 字节,这是 85 x 64 位,或 170 x 32 位。
这个答案的大部分功劳归功于MvG。
Erkki Seppala 实际上有一个工具可以用 gdb 从 Linux 内核中检索这些信息。它可以在这里找到。
这个解决方案虽然有效,但兴趣有限,因为如果你有一个足够新的 systemtap,你很可能会有一个足够新的内核,你可以在其中使用
ss基于 方法,如果你使用的是旧内核,那么其他解决方案,尽管更hacky更有可能工作并且不需要额外的软件。作为演示如何使用
systemtap此类任务仍然很有用。
如果在具有工作 systemtap(1.8 或更高版本)的最新 Linux 系统上,您可以使用下面的脚本对输出进行后处理lsof:
例如:
$ lsof -aUc nm-applet | 须藤那个脚本 命令 PID 用户 FD 类型 设备大小/关闭节点名称 纳米小应用程序4183的Stephane 4U UNIX 0xffff8800a055eb40 0t0 36888型= STREAM - > 0xffff8800a055e7c0 [DBUS守护,4190,@ / TMP / DBUS-AiBCXOnuP6] 纳米小程序4183的Stephane 7U UNIX 0xffff8800a055e440 0t0 36890型= STREAM - > 0xffff8800a055e0c0 [Xorg则3080,@ / TMP / .X11-UNIX / X0] 纳米小程序4183的Stephane 8U UNIX 0xffff8800a05c1040 0t0 36201型= STREAM - > 0xffff8800a05c13c0 [DBUS守护,4118,@ / TMP / DBUS-yxxNr1NkYC] 纳米小程序4183的Stephane 11U UNIX 0xffff8800a055d080 0t0 36219型= STREAM - > 0xffff8800a055d400 [DBUS守护,4118,@ / TMP / DBUS-yxxNr1NkYC] 纳米小程序4183的Stephane 12U UNIX 0xffff88022e0dfb80 0t0 36221型= STREAM - > 0xffff88022e0df800 [DBUS守护,2268,/ VAR /run/dbus/system_bus_socket] nm-applet 4183 stephane 13u unix 0xffff88022e0f80c0 0t0 37025 type=STREAM -> 0xffff88022e29ec00[dbus-daemon,2268,/var/run/dbus/system_bus_socket]
(如果您在上面看到 0x0000000000000000 而不是 0xffff...,那是因为kernel.kptr_restrict系统上设置了sysctl 参数,这会导致内核指针对非特权进程隐藏,在这种情况下,您需要以lsofroot 身份运行才能获得有意义的结果)。
该脚本不会尝试处理带有换行符的套接字文件名,但也不会lsof(也不lsof处理空格或冒号)。
systemtap这里用于转储内核中散列中所有unix_sock结构的地址和对等地址unix_socket_table。
仅在带有 systemtap 2.6 的 Linux 3.16 amd64 和带有 2.3 的 3.13 上测试。
$ lsof -aUc nm-applet | sudo that-script COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME nm-applet 4183 stephane 4u unix 0xffff8800a055eb40 0t0 36888 type=STREAM -> 0xffff8800a055e7c0[dbus-daemon,4190,@/tmp/dbus-AiBCXOnuP6] nm-applet 4183 stephane 7u unix 0xffff8800a055e440 0t0 36890 type=STREAM -> 0xffff8800a055e0c0[Xorg,3080,@/tmp/.X11-unix/X0] nm-applet 4183 stephane 8u unix 0xffff8800a05c1040 0t0 36201 type=STREAM -> 0xffff8800a05c13c0[dbus-daemon,4118,@/tmp/dbus-yxxNr1NkYC] nm-applet 4183 stephane 11u unix 0xffff8800a055d080 0t0 36219 type=STREAM -> 0xffff8800a055d400[dbus-daemon,4118,@/tmp/dbus-yxxNr1NkYC] nm-applet 4183 stephane 12u unix 0xffff88022e0dfb80 0t0 36221 type=STREAM -> 0xffff88022e0df800[dbus-daemon,2268,/var/run/dbus/system_bus_socket] nm-applet 4183 stephane 13u unix 0xffff88022e0f80c0 0t0 37025 type=STREAM -> 0xffff88022e29ec00[dbus-daemon,2268,/var/run/dbus/system_bus_socket]
| 归档时间: |
|
| 查看次数: |
44126 次 |
| 最近记录: |