谁有这个unix套接字对的另一端?


54

我想确定哪个进程具有UNIX套接字的另一端。

具体来说,我要问的是使用创建的一个socketpair(),尽管问题对于任何UNIX套接字都是相同的。

我有一个程序parent创建一个socketpair(AF_UNIX, SOCK_STREAM, 0, fds)fork()。父进程关闭fds[1]并保持fds[0]通信。孩子做相反的事情close(fds[0]); s=fds[1]。然后孩子exec()的另一个程序child1。两者可以通过此套接字对来回通信。

现在,假设我知道谁parent是谁,但我想弄清楚谁child1是谁。我该怎么做呢?

我可以使用几种工具,但是没有一个可以告诉我哪个过程在套接字的另一端。我努力了:

  • lsof -c progname
  • lsof -c parent -c child1
  • ls -l /proc/$(pidof server)/fd
  • cat /proc/net/unix

基本上,我可以看到两个插座以及有关它们的所有内容,但无法确定它们已连接。我正在尝试确定父级中的哪个FD与哪个子进程进行通信。

Answers:


27

由于内核3.3,可以使用sslsof-4.89以上-见斯特凡Chazelas的答案

根据的作者所述,在较旧的版本中,lsof不可能发现这一点:Linux内核不会公开此信息。来源:comp.unix.admin上的2003线程

显示/proc/$pid/fd/$fd的数字是虚拟套接字文件系统中套接字的索引节点号。创建管道或插座对时,每个端接连收到一个索引节点号。数字是按顺序分配的,因此数字相差1的可能性很高,但这不能保证(这是因为第一个套接字为N,并且由于换行而已使用了N +1,或者是因为存在其他线程)安排在两个inode分配之间,并且该线程也创建了一些inode)。

我检查了内核2.6.39中定义socketpair,并且套接字的两端除了通过特定于类型的socketpair方法之外没有关联。对于unix套接字,它unix_socketpair在中net/unix/af_unix.c


2
谢谢@吉尔斯。我确实记得有一段时间读过一些关于它的内容,但无法再次找到它。我可能只需要为/ proc / net / unix编写一个补丁。
Jonathon Reinhart

是的,我已经通过增加inode数量进行了观察,目前这就是我正在使用的。但是,正如您指出的那样,不能保证。我正在查看的进程至少有40个开放的unix套接字,并且我看到一个实例,其中N + 1并不成立。笨蛋
乔纳森·莱因哈特

1
@JonathonReinhart我检查了的定义socketpair,并且套接字的两端不相关,除非使用特定于类型的socketpair方法。对于unix套接字,unix_socketpair位于`net / unix / af_unix.c中。拥有管道的此信息也将是一件好事。
吉尔(Gilles)“所以,别再邪恶了”,

36

注意:我现在维护一个lsof包装器,该包装器结合了这里描述的两种方法,并且还在https://github.com/stephane-chazelas/misc-scripts/blob/master/lsofc添加了回送TCP连接对等方的信息

Linux-3.3及更高版本。

在Linux中,因为内核版本3.3(和提供的UNIX_DIAG功能内置在内核),可以利用一个新的来获得给定的UNIX域套接字的对等体(包括socketpairs)的netlink基于API。

lsof 因为版本4.89可以使用该API:

lsof +E -aUc Xorg

将以Xorg类似于以下格式列出所有进程名称都以结尾开头的所有Unix域套接字:

Xorg       2777       root   56u  unix 0xffff8802419a7c00      0t0   34036 @/tmp/.X11-unix/X0 type=STREAM ->INO=33273 4120,xterm,3u

如果您的版本lsof太旧,则还有更多选择。

ss(从实用程序iproute2)利用同一API的检索和UNIX域套接字的系统,其包括对等体的信息的一览表上显示的信息。

套接字由它们的inode号标识。请注意,它与套接字文件的文件系统索引节点无关。

例如在:

$ ss -x
[...]
u_str  ESTAB    0    0   @/tmp/.X11-unix/X0 3435997     * 3435996

它说套接字3435997(绑定到ABSTRACT套接字/tmp/.X11-unix/X0)与套接字3435996连接。该-p选项可以告诉您哪个进程打开了该套接字。它通过在readlink上执行一些操作来做到这一点/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]

要找出哪个进程具有3435996,可以在输出中查找其自己的条目ss -xp

$ ss -xp | awk '$6 == 3435996'
u_str  ESTAB  0  0  * 3435996  * 3435997 users:(("xterm",pid=29215,fd=3))

您还可以将此脚本用作包装器,lsof以在其中轻松显示相关信息:

#! /usr/bin/perl
# lsof wrapper to add peer information for unix domain socket.
# Needs Linux 3.3 or above and CONFIG_UNIX_DIAG enabled.

# retrieve peer and direction information from ss
my (%peer, %dir);
open SS, '-|', 'ss', '-nexa';
while (<SS>) {
  if (/\s(\d+)\s+\*\s+(\d+) ([<-]-[->])$/) {
    $peer{$1} = $2;
    $dir{$1} = $3;
  }
}
close SS;

# Now get info about processes tied to sockets using lsof
my (%fields, %proc);
open LSOF, '-|', 'lsof', '-nPUFpcfin';
while (<LSOF>) {
  if (/(.)(.*)/) {
    $fields{$1} = $2;
    if ($1 eq 'n') {
      $proc{$fields{i}}->{"$fields{c},$fields{p}" .
      ($fields{n} =~ m{^([@/].*?)( type=\w+)?$} ? ",$1" : "")} = "";
    }
  }
}
close LSOF;

# and finally process the lsof output
open LSOF, '-|', 'lsof', @ARGV;
while (<LSOF>) {
  chomp;
  if (/\sunix\s+\S+\s+\S+\s+(\d+)\s/) {
    my $peer = $peer{$1};
    if (defined($peer)) {
      $_ .= $peer ?
            " ${dir{$1}} $peer\[" . (join("|", keys%{$proc{$peer}})||"?") . "]" :
            "[LISTENING]";
    }
  }
  print "$_\n";
}
close LSOF or exit(1);

例如:

$ 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]

在linux-3.3之前

用于检索unix套接字信息的旧Linux API是通过/proc/net/unix文本文件获取的。它列出了所有Unix域套接字(包括套接字对)。@Totor已在其中说明了其中的第一个字段(如果没有使用kernel.kptr_restrictsysctl参数隐藏给非超级用户),则该字段包含结构的内核地址,该结构的内核地址包含指向相应对等方的字段。这也是Unix套接字上列的输出。unix_sockpeer unix_socklsofDEVICE

现在获取该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 type = STREAM-> 0xffff8800a055d400 [dbus-daemon,4118,@ / tmp / dbus-yxxNr1NkYC] 
nm-applet 4183 stephane 12u unix 0xffff88022e0dfb80 0t0 36221 type = daREAM-268 / 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]

这是脚本:

#! /usr/bin/perl
# wrapper around lsof to add peer information for Unix
# domain sockets. needs lsof, and superuser privileges.
# Copyright Stephane Chazelas 2015, public domain.
# example: sudo this-lsof-wrapper -aUc Xorg
use Socket;

open K, "<", "/proc/kcore" or die "open kcore: $!";
read K, $h, 8192 # should be more than enough
 or die "read kcore: $!";

# parse ELF header
my ($t,$o,$n) = unpack("x4Cx[C19L!]L!x[L!C8]S", $h);
$t = $t == 1 ? "L3x4Lx12" : "Lx4QQx8Qx16"; # program header ELF32 or ELF64
my @headers = unpack("x$o($t)$n",$h);

# read data from kcore at given address (obtaining file offset from ELF
# @headers)
sub readaddr {
  my @h = @headers;
  my ($addr, $length) = @_;
  my $offset;
  while (my ($t, $o, $v, $s) = splice @h, 0, 4) {
    if ($addr >= $v && $addr < $v + $s) {
      $offset = $o + $addr - $v;
      if ($addr + $length - $v > $s) {
        $length = $s - ($addr - $v);
      }
      last;
    }
  }
  return undef unless defined($offset);
  seek K, $offset, 0 or die "seek kcore: $!";
  my $ret;
  read K, $ret, $length or die "read($length) kcore \@$offset: $!";
  return $ret;
}

# create a dummy socketpair to try find the offset in the
# kernel structure
socketpair(Rdr, Wtr, AF_UNIX, SOCK_STREAM, PF_UNSPEC)
 or die "socketpair: $!";
$r = readlink("/proc/self/fd/" . fileno(Rdr)) or die "readlink Rdr: $!";
$r =~ /\[(\d+)/; $r = $1;
$w = readlink("/proc/self/fd/" . fileno(Wtr)) or die "readlink Wtr: $!";
$w =~ /\[(\d+)/; $w = $1;
# now $r and $w contain the socket inodes of both ends of the socketpair
die "Can't determine peer offset" unless $r && $w;

# get the inode->address mapping
open U, "<", "/proc/net/unix" or die "open unix: $!";
while (<U>) {
  if (/^([0-9a-f]+):(?:\s+\S+){5}\s+(\d+)/) {
    $addr{$2} = hex $1;
  }
}
close U;

die "Can't determine peer offset" unless $addr{$r} && $addr{$w};

# read 2048 bytes starting at the address of Rdr and hope to find
# the address of Wtr referenced somewhere in there.
$around = readaddr $addr{$r}, 2048;
my $offset = 0;
my $ptr_size = length(pack("L!",0));
my $found;
for (unpack("L!*", $around)) {
  if ($_ == $addr{$w}) {
    $found = 1;
    last;
  }
  $offset += $ptr_size;
}
die "Can't determine peer offset" unless $found;

my %peer;
# now retrieve peer for each socket
for my $inode (keys %addr) {
  $peer{$addr{$inode}} = unpack("L!", readaddr($addr{$inode}+$offset,$ptr_size));
}
close K;

# Now get info about processes tied to sockets using lsof
my (%fields, %proc);
open LSOF, '-|', 'lsof', '-nPUFpcfdn';
while (<LSOF>) {
  if (/(.)(.*)/) {
    $fields{$1} = $2;
    if ($1 eq 'n') {
      $proc{hex($fields{d})}->{"$fields{c},$fields{p}" .
      ($fields{n} =~ m{^([@/].*?)( type=\w+)?$} ? ",$1" : "")} = "";
    }
  }
}
close LSOF;

# and finally process the lsof output
open LSOF, '-|', 'lsof', @ARGV;
while (<LSOF>) {
  chomp;
  for my $addr (/0x[0-9a-f]+/g) {
    $addr = hex $addr;
    my $peer = $peer{$addr};
    if (defined($peer)) {
      $_ .= $peer ?
            sprintf(" -> 0x%x[", $peer) . join("|", keys%{$proc{$peer}}) . "]" :
            "[LISTENING]";
      last;
    }
  }
  print "$_\n";
}
close LSOF or exit(1);

1
@mikeserv,这是该评论的后续内容。找不到unix套接字的另一端一直使我很烦恼(通常是在尝试查找X客户端时,最近一个关于此的问题)。我将尝试看看是否可以将类似方法用于伪终端,并向lsof作者提出建议。
斯特凡Chazelas

1
我仍然不敢相信内核本身并没有提供!我真的应该提交一个补丁,如果无非就是发现它为什么不存在的原因。
乔纳森·莱因哈特

1
ss这样做吗?这有点ss -pxusers: ("nacl_helper",pid=18992,fd=6),("chrome",pid=18987,fd=6),("chrome",pid=18975,fd=5)) u_str ESTAB\t0\t0\t/run/dbus/system_bus_socket 8760\t\t* 15068State\tRecv-Q\tSend-Q\tLocal Address:Port\tPeer Address:Port
麻烦

1
此外,如果lsof -c terminology可以,我可以看到,terminolo 12731\tmikeserv\t12u\tunix\t0xffff880600e82680\t0t0\t1312426\ttype=STREAM但可以看到ss -px | grep terminologyu_str\tESTAB\t0\t0\t* 1312426\t*1315046\tusers:(("terminology",pid=12731,fd=12))
mikeserv 2015年

1
@mikeserv,看起来确实如此!看来我最近一直在浪费了大量的时间...
斯特凡Chazelas


8

从内核3.3开始

可以 现在获得这些信息ss

# ss -xp

现在,您可以在Peer列中看到一个ID(索引节点编号),它对应于该Local列中的另一个ID 。匹配的ID是套接字的两端。

注意:UNIX_DIAG必须在内核中启用该选项。

在内核3.3之前

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

有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

在这里,插座的另一端由mysqlPID 14815保持。

你的内核必须编译KCORE_ELF使用/proc/kcore。另外,您需要一个带有调试符号的内核映像版本。在Debian 7上,apt-get install linux-image-3.2.0-4-amd64-dbg将提供此文件。

不需要可调试的内核映像...

如果您没有(或不想保留)系统上的调试内核映像,则可以给gdb内存偏移量以“手动”访问该peer值。此偏移值通常随内核版本或体系结构而不同。

在我的内核上,我知道偏移量是680个字节,即64位的85倍。所以我可以做:

# gdb /boot/vmlinux-3.2.0-4-amd64 /proc/kcore
(gdb) print ((void**)0xffff8801011e9600)[85]
$1 = (void *) 0xffff880171f078c0

瞧,和上面的结果一样。

如果您在多台计算机上运行相同的内核,则使用此变体会更容易,因为您不需要调试映像,而只需要偏移值。

首先要(轻松)发现此偏移值,您确实需要调试映像:

$ pahole -C unix_sock /usr/lib/debug/boot/vmlinux-3.2.0-4-amd64
struct unix_sock {
  (...)
  struct sock *              peer;                 /*   680     8 */
  (...)
}

680个字节,这是85 x 64位或170 x 32位。

此答案的大部分功劳归功于MvG


2
检索偏移量的另一种方法可能是创建一个套接字对,基于/ proc / pif / fd / *上的读取链接的inode编号在/ proc / net / unix中标识相应的条目,并在一个套接字的地址周围扫描内存以查找对方的地址。这可以使lsof本身可以实现合理的可移植性(跨Linux版本和体系结构)。我将尝试提出PoC。
斯特凡Chazelas

2
我现在添加了这样的PoC,它似乎在我测试过的系统上运行良好。
斯特凡Chazelas

5

该解决方案虽然有效,但是兴趣有限,因为如果您使用了最近足够的系统,则很可能会使用一个最近足够的内核,可以在其中使用ss基于 方法,如果您使用的是较旧的内核,则可以使用其他方法。解决方案,尽管更多的黑客行为更有可能起作用,并且不需要其他软件。

仍然作为演示如何systemtap用于此类任务的演示很有用。

如果在最新的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 type = STREAM-> 0xffff8800a055d400 [dbus-daemon,4118,@ / tmp / dbus-yxxNr1NkYC] 
nm-applet 4183 stephane 12u unix 0xffff88022e0dfb80 0t0 36221 type = daREAM-268 / 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上进行了测试。

#! /usr/bin/perl
# meant to process lsof output to try and find the peer of a given
# unix domain socket. Needs a working systemtap, lsof, and superuser
# privileges. Copyright Stephane Chazelas 2015, public domain.
# Example: lsof -aUc X | sudo this-script
open STAP, '-|', 'stap', '-e', q{
  probe begin {
    offset = &@cast(0, "struct sock")->__sk_common->skc_node;
    for (i = 0; i < 512; i++) 
      for (p = @var("unix_socket_table@net/unix/af_unix.c")[i]->first;
           p;
           p=@cast(p, "struct hlist_node")->next
          ) {
        sock = p - offset;
        printf("%p %p\n", sock, @cast(sock, "struct unix_sock")->peer);
    }
    exit()
  }
};  
my %peer;
while (<STAP>) {
  chomp;
  my ($a, $b) = split;
  $peer{$a} = $b;
}
close STAP;

my %f, %addr;
open LSOF, '-|', 'lsof', '-nPUFpcfdn';
while (<LSOF>) {
  if (/(.)(.*)/) {
    $f{$1} = $2;
    if ($1 eq 'n') {
      $addr{$f{d}}->{"$f{c},$f{p}" . ($f{n} =~ m{^([@/].*?)( type=\w+)?$} ? ",$1" : "")} = "";
    }
  }
}
close LSOF;

while (<>) {
  chomp;
  for my $addr (/0x[0-9a-f]+/g) {
    my $peer = $peer{$addr};
    if (defined($peer)) {
      $_ .= $peer eq '0x0' ?
            "[LISTENING]" :
            " -> $peer\[" . join("|", keys%{$addr{$peer}}) . "]";
      last;
    }
  }
  print "$_\n";
}

parse error: unknown statistic operator @var:我想念什么吗?
Totor

@Totor,@var在1.8的SystemTap,2012-06-17加入(最新的是2.7)
斯特凡Chazelas

2

lsof的4.89支持显示端点选项。

引用lsof.8:

+|-E +E specifies that process intercommunication channels should be
     displayed with endpoint information and the channels
     of the endpoints should also be displayed.  Currently
     only pipe on Linux is implemented.

     Endpoint information is displayed in the NAME column
     in the form "PID,cmd,FDmode".  PID is the endpoint
     process ID; cmd is the endpoint process command; FD is
     the endpoint file's descriptor; and mode is the
     endpoint file's access mode.  Multiple occurrences of
     this information can appear in a file's NAME column.

     -E specfies that Linux pipe files should only be
     displayed with endpoint information.

输出示例:

mozStorag 21535 22254  yamato    6u     unix 0xf...       0t0     348924 type=STREAM pino=351122 4249,dbus-daem,55u
mozStorag 21535 22254  yamato   10u     unix 0xf...       0t0     356193 type=STREAM pino=356194 21535,gdbus,11u
mozStorag 21535 22254  yamato   11u     unix 0xf...       0t0     356194 type=STREAM pino=356193 21535,gdbus,10u
mozStorag 21535 22254  yamato   21u     unix 0xf...       0t0     355141 type=STREAM pino=357544 4249,dbus-daem,60u
mozStorag 21535 22254  yamato   26u     unix 0xf...       0t0     351134 type=STREAM pino=355142 5015,gdbus,17u
mozStorag 21535 22254  yamato   69u     unix 0xf...       0t0     469354 type=STREAM pino=468160 4545,alsa-sink,21u
mozStorag 21535 22254  yamato   82u     unix 0xf...       0t0     449383 type=STREAM pino=449384 12257,Chrome_Ch,3u
mozStorag 21535 22254  yamato   86u     unix 0xf...       0t0     355174 type=SEQPACKET pino=355175 21535,gdbus,95u
mozStorag 21535 22254  yamato   95u     unix 0xf...       0t0     355175 type=SEQPACKET pino=355174 21535,gdbus,86u 12257,Chrome_Ch,4u
mozStorag 21535 22254  yamato  100u     unix 0xf...       0t0     449389 type=STREAM pino=456453 3614,Xorg,38u
mozStorag 21535 22254  yamato  105u     unix 0xf...       0t0     582613 type=STREAM pino=586261
obexd     22163        yamato    1u     unix 0xf...       0t0     361859 type=STREAM pino=365931
obexd     22163        yamato    2u     unix 0xf...       0t0     361860 type=STREAM pino=365934
obexd     22163        yamato    3u     unix 0xf...       0t0     361241 type=DGRAM pino=10028
obexd     22163        yamato    6u     unix 0xf...       0t0     361242 type=STREAM pino=361864 4249,dbus-daem,70u

2

从Linux内核4.2开始,存在CONFIG_UNIX_DIAG,它提供了有关UNIX域套接字的额外信息,即Virtual File System(VFS)信息,该信息包含迄今为止缺少的信息,以将Inode从路径链接到进程。ss从版本v4.19.0〜55开始,已经可以使用iproute2中的工具进行查询:

$ ss --processes --unix --all --extened
...
Netid  State   Recv-Q  Send-Q  Local Address:Port      Peer Address:Port
u_str  LISTEN  0       5         /tmp/socket 13381347             * 0     users:(("nc",pid=12550,fd=3)) <-> ino:1569897 dev:0/65025 peers:

您可以从中获得的设备编号和路径Inode

$ stat -c 'ino:%i dev:0/%d' /tmp/socket
ino:1569946 dev:0/65025

ss 还支持过滤:

 ss --processes --unix --all --extended 'sport = /tmp/socket'

但是请注意,这可能无法为您列出正确的套接字,因为一个邪恶的进程可能会重命名您原来的套接字,并用它自己的邪恶套接字替换它:

mv /tmp/socket /tmp/socket.orig
nc -U -l /tmp/socket.evil &
mv /tmp/socket.evil /tmp/socket

lsof /tmp/socketfuser /tmp/socket并将ss --processes --unix --all --extended 'sport = /tmp/socket'列出所有原始流程,而不是邪恶的替换。而是使用类似以下的内容:

id=$(stat -c 'ino:%i dev:0/%d' /tmp/socket)
ss --processes --unix --all --extended | grep -F "$id"

或者根据man 7 sock_diag中包含的模板编写自己的litt程序

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.