繁体   English   中英

找到Linux套接字的原始拥有进程

[英]Find original owning process of a Linux socket

在Linux和其他类UNIX操作系统,它是可能的两个(或多个)进程共享一个互联网插座。 假设进程之间没有父子关系,有没有办法告诉最初创建套接字的进程是什么?

澄清:我需要使用/proc文件系统或类似程序从“外部”进程确定。 我无法修改进程的代码。 我已经可以通过读取/proc/<pid>/fd告诉哪些进程正在共享套接字,但这并不能告诉我最初创建它们的进程。

你可以使用netstat。 您应该查看“本地地址”和“PID /程序名称”列。

xxx@xxx:~$ netstat -tulpen
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       User       Inode       PID/Program name
tcp        0      0 127.0.0.1:4005          0.0.0.0:*               LISTEN      1000       68449       7559/sbcl       
tcp        0      0 0.0.0.0:6000            0.0.0.0:*               LISTEN      0          3938        -               
tcp6       0      0 :::6000                 :::*                    LISTEN      0          3937        -               
udp        0      0 0.0.0.0:68              0.0.0.0:*                           0          4528        -               

不会'帮助'-Ua'吗?

您可以通过解析/ proc / net / tcp(以及其他协议的类似“文件”)来找到共享套接字。 有上的/ proc /净/ TCP一些文档在这里

您需要找到套接字(可能通过其IP地址/端口号?)并解析出inode编号。 获得inode之后,您可以搜索所有/proc/*/fd/* ,为每个链接调用stat并检查struct statst_ino成员,直到找到匹配项。

inode编号应该在两个进程之间匹配,所以当你经历了所有/proc/*/fd/*你应该找到它们。

如果您知道的是第一个的进程ID和套接字fd,您可能不需要通过/ proc / net / tcp,您需要做的就是统计/proc/<pid>/fd/<fd>并在/proc/*/fd/*的其余部分搜索匹配的inode。 如果你想获取ip地址/端口号,你需要/ proc / net / tcp - 如果你知道inode号就可以找到

为了创建测试用例,请考虑多个ssh-agent进程正在运行并具有打开套接字的情况。 即用户多次运行ssh-agent并丢失代理启动时给出的套接字/ PID信息:

$ find /tmp -path "*ssh*agent*" 2>/dev/null
/tmp/ssh-0XemJ4YlRtVI/agent.14405
/tmp/ssh-W1Tl4i8HiftZ/agent.21283
/tmp/ssh-w4fyViMab8wr/agent.10966

稍后,用户希望以编程方式确定特定ssh-agent套接字的PID所有者(即/tmp/ssh-W1Tl4i8HiftZ/agent.21283):

$ stat /tmp/ssh-W1Tl4i8HiftZ/agent.21283
  File: '/tmp/ssh-W1Tl4i8HiftZ/agent.21283'
  Size: 0               Blocks: 0          IO Block: 4096   socket
Device: 805h/2053d      Inode: 113         Links: 1
Access: (0600/srw-------)  Uid: ( 4000/ myname)   Gid: ( 4500/   mygrp)
Access: 2018-03-07 21:23:08.373138728 -0600
Modify: 2018-03-07 20:49:43.638291884 -0600
Change: 2018-03-07 20:49:43.638291884 -0600
Birth: -

在这种情况下,因为ssh-agent很好地命名它的套接字,因为人类旁观者可以猜测套接字属于PID 21284,因为套接字名称包含一个数字组件,该组件是用ps标识的PID的一次性:

$ ps -ef |  grep ssh-agent
myname   10967     1  0 16:54 ?        00:00:00 ssh-agent
myname   14406     1  0 20:35 ?        00:00:00 ssh-agent
myname   21284     1  0 20:49 ?        00:00:00 ssh-agent

似乎非常不明智地假设PID将如此可靠以至于总是只被一个人关闭,而且,人们可能会认为并非所有套接字创建者都会如此好地命名套接字。

@ Cypher的答案指向了识别套接字所有者的PID问题的直接解决方案,但是不完整,因为lsof实际上只能通过提升的权限来识别此PID。 如果没有提升权限,则不会有任何结果:

$ lsof /tmp/ssh-W1Tl4i8HiftZ/agent.21283
$

但是,通过提升权限,可以识别PID:

$ sudo lsof /tmp/ssh-W1Tl4i8HiftZ/agent.21283
COMMAND     PID    USER   FD   TYPE             DEVICE SIZE/OFF    NODE NAME
ssh-agent 21284 myname     3u  unix 0xffff971aba04cc00      0t0 1785049 /tmp/ssh-W1Tl4i8HiftZ/agent.21283 type=STREAM

在这种情况下,PID(myname)和套接字的所有者是进行查询的所有者,因此似乎不需要提升权限。 此外,执行查询的任务不应该能够提升权限,所以我寻找另一个答案。

这让我想到了@whoplisp的回答,提出netstat -tulpen作为OP问题的解决方案。 虽然它可能对OP有效,但命令行限制太大而无法用作通用命令,并且在这种情况下完全无效(即使具有提升的权限)。

$ sudo netstat -tulpen | grep -E -- '(agent.21283|ssh-agent)'
$

但是,如果使用不同的命令行, netstat可能会关闭:

$ netstat -ap | grep -E -- '(agent.21283)'
(Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.)
unix  2      [ ACC ]     STREAM     LISTENING     1785049  -                    /tmp/ssh-W1Tl4i8HiftZ/agent.21283

可悲的是,在这里,PID是难以捉摸的,没有提升权限:

$ sudo netstat -ap | grep -E -- '(agent.21283|ssh-agent)'
unix  2      [ ACC ]     STREAM     LISTENING     1765316  10967/ssh-agent      /tmp/ssh-w4fyViMab8wr/agent.10966
unix  2      [ ACC ]     STREAM     LISTENING     1777450  14406/ssh-agent      /tmp/ssh-0XemJ4YlRtVI/agent.14405
unix  2      [ ACC ]     STREAM     LISTENING     1785049  21284/ssh-agent      /tmp/ssh-W1Tl4i8HiftZ/agent.21283

然而,在这两种解决方案中, lsof显然在比赛中获胜:

$ time sudo netstat -ap | grep -E -- '(agent.21283|ssh-agent)' >/dev/null

real    0m5.159s
user    0m0.010s
sys     0m0.019s
$ time sudo lsof /tmp/ssh-W1Tl4i8HiftZ/agent.21283 >/dev/null

real    0m0.120s
user    0m0.038s
sys     0m0.066s

根据netstat手册页,存在另一种工具:

$ man netstat | grep -iC1 replace
NOTES
       This program is mostly obsolete.  Replacement for netstat is ss.  Replacement for netstat -r is ip route.  Replacement for netstat -i
       is ip -s link.  Replacement for netstat -g is ip maddr.

遗憾的是, ss还需要提升权限才能识别PID,但它会击败netstatlsof执行时间:

$ time sudo ss -ap | grep -E "(agent.21283|ssh-agent)"
u_str  LISTEN     0      128    /tmp/ssh-w4fyViMab8wr/agent.10966 1765316               * 0                     users:(("ssh-agent",pid=10967,fd=3))
u_str  LISTEN     0      128    /tmp/ssh-0XemJ4YlRtVI/agent.14405 1777450               * 0                     users:(("ssh-agent",pid=14406,fd=3))
u_str  LISTEN     0      128    /tmp/ssh-W1Tl4i8HiftZ/agent.21283 1785049               * 0                     users:(("ssh-agent",pid=21284,fd=3))

real    0m0.043s
user    0m0.018s
sys     0m0.021s

总之,似乎对于某些PID识别,似乎需要提升权限。

注意:并非所有操作系统都需要提升权限。 例如,SCO Openserver 5.0.7的lsof似乎工作得很好而没有提升权限。

警告:关于OP找到套接字“原始创建者”的资格,这个答案可能会失败。 在使用的示例中,毫无疑问PID 21283是套接字创建的发起者,因为此PID在套接字名称中标识。 lsofnetstat都没有将PID 21283识别为原始创建者,但显然PID 21284是当前的维护者。

我不知道使用sendmsg()将套接字从一个进程“发送”到另一个进程。

我知道如果第二个进程尝试使用相同的端口,bind()系统调用将返回EADDRINUSE。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM