이 유닉스 소켓 페어의 다른 쪽 끝은 누구입니까?


54

UNIX 소켓의 다른 쪽 끝에 어떤 프로세스가 있는지 확인하고 싶습니다.

특히, socketpair()문제는 모든 UNIX 소켓에서 동일하지만 로 작성된 것을 묻습니다 .

, 및 s 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가 어떤 자식 프로세스와 통신하는지 확인하려고합니다.

답변:


27

커널 3.3 있기 때문에, 사용 가능 ss또는 lsof-4.89참조 - 이상 스테판 Chazelas가의 답변을 .

의 저자에 따르면, 이전 버전에서는 lsof이를 찾을 수 없었습니다. Linux 커널은이 정보를 공개하지 않습니다. 출처 : comp.unix.admin 2003 스레드 .

표시된 숫자 /proc/$pid/fd/$fd는 가상 소켓 파일 시스템에서 소켓의 inode 번호입니다. 파이프 또는 소켓 쌍을 작성할 때 각 끝은 inode 번호를 연속적으로받습니다. 숫자는 순차적으로 계산되므로 숫자가 1 씩 다를 가능성이 높지만 보장되지 않습니다 (첫 번째 소켓은 N 이고 N +1은 랩핑으로 인해 이미 사용 중이거나 다른 스레드가 있었기 때문에) 두 inode 할당 사이에 예약되어 있으며 해당 스레드가 일부 inode를 생성했습니다).

커널 2.6.39에서 정의를socketpair 확인했으며 소켓의 두 끝은 유형별 socketpair방법을 제외하고는 상관되지 않습니다 . 유닉스 소켓의 경우 unix_socketpairnet/unix/af_unix.c 있습니다.


2
감사합니다 @Gillles. 나는 그것에 대해 얼마전에 읽은 것을 기억하지만 다시 찾을 수 없었습니다. / proc / net / unix에 대한 패치를 작성해야 할 수도 있습니다.
Jonathon Reinhart

그리고 네, 증가하는 inode 수로 그 관찰을 해왔으며 현재는 제가 작업하고 있습니다. 그러나 언급했듯이 보장되지는 않습니다. 내가보고있는 프로세스에는 최소 40 개의 열린 유닉스 소켓이 있으며 N + 1이 적용되지 않은 인스턴스를 보았습니다. 버머.
Jonathon Reinhart

1
@JonathonReinhart 의 정의를socketpair 확인 했으며 소켓의 두 끝은 유형별 socketpair메소드를 제외하고는 상관되지 않습니다 . 유닉스 소켓의 경우 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기능이 커널에 내장되어있는 경우)이므로 새로운 netlink 기반 API를 사용하여 지정된 유닉스 도메인 소켓 (소켓 쌍 포함)의 피어를 얻을 수 있습니다 .

lsof 버전 4.89가 해당 API를 사용할 수 있기 때문에 :

lsof +E -aUc Xorg

프로세스의 이름이 Xorg양쪽 끝에서 시작하는 프로세스가있는 모든 유닉스 도메인 소켓 을 다음과 유사한 형식으로 나열합니다 .

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

버전 lsof이 너무 오래된 경우 몇 가지 옵션이 더 있습니다.

ss(에서 유틸리티 iproute2) 검색하고 피어 정보를 포함하여 시스템에 유닉스 도메인 소켓의 목록에 정보를 표시하는 동일한 API를 사용합니다.

소켓은 inode 번호 로 식별됩니다 . 소켓 파일의 파일 시스템 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 스테판 3u 유닉스 0xffff8800a07da4c0 0t0 3435996 type = STREAM <-> 3435997 [Xorg, 3080, @ / tmp / .X11-unix / X0]

리눅스 3.3 이전

유닉스 소켓 정보를 검색하는 이전 Linux API는 /proc/net/unix텍스트 파일을 통해 이루어 집니다. 모든 Unix 도메인 소켓 (소켓 쌍 포함)을 나열합니다. @Totor의해 이미 설명 된kernel.kptr_restrict 것처럼 거기에있는 첫 번째 필드 ( sysctl 매개 변수를 사용하여 비 수퍼 유저에게 숨겨져 있지 않은 경우 ) 에는 해당 피어를 가리키는 필드 를 포함하는 구조 의 커널 주소 가 포함 됩니다. 또한 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- 애플릿
명령 PID 사용자 FD 유형 장치 크기 / 꺼짐 노드 이름
NM-애플릿 4183 스테판의 4U UNIX 0xffff8800a055eb40 0t0 36,888 TYPE = STREAM -> 0xffff8800a055e7c0 [DBUS 데몬, 4190 @ / TMP / DBUS-AiBCXOnuP6] 
nm의 애플릿 4183 스테판의 7U UNIX 0xffff8800a055e440 0t0 36,890 TYPE = STREAM -> 0xffff8800a055e0c0 [이 xorg 3080, @ / tmp / .X11-unix / X0] 
nm-applet 4183 스테판 8u 유닉스 0xffff8800a05c1040 0t0 36201 type = STREAM-> 0xffff8800a05c13c0 [dbus-daemon, 4118, @ / tmp / dbus-yxxNr1NkYC] 
nm-applet 4183 UNIX 0xffff8800a055d080 0t0 36,219 TYPE = STREAM -> 0xffff8800a055d400 [DBUS 데몬, 4118 @ / TMP / DBUS-yxxNr1NkYC] 
nm의 애플릿 4183 UNIX 0xffff88022e0dfb80 0t0 36,221 TYPE = STREAM 12U 스테판 -> 0xffff88022e0df800 [DBUS 데몬, 2,268 / VAR / run / dbus / system_bus_socket]
nm-applet 4183 스테판 13u 유닉스 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, 그 의견 에 대한 후속 조치 입니다. 유닉스 소켓의 다른 끝을 찾을 수 없다는 것은 항상 나를 괴롭힌 것입니다 (종종 X 클라이언트를 찾으려고 할 때 최근에 대한 질문 이있었습니다 ). 유사 터미널이 유사 터미널에 사용될 수 있는지 확인 하고 lsof저자 에게 제안 할 것 입니다.
Stéphane Chazelas

1
나는 아직도 이것이 커널 자체에 의해 제공되지 않는다고 믿을 수 없다! 패치가 존재하지 않는 이유를 알아 내기 위해 패치를 제출해야합니다.
Jonathon Reinhart

1
않습니다 ss이 작업을 수행하지? 내 머리 위에는 있지만 ss -px피어 정보를 가진 많은 유닉스 소켓을 나열합니다 users: ("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* 15068. 열 제목은 ...State\tRecv-Q\tSend-Q\tLocal Address:Port\tPeer Address:Port
mikeserv

1
또한, 내가 lsof -c terminology볼 수 terminolo 12731\tmikeserv\t12u\tunix\t0xffff880600e82680\t0t0\t1312426\ttype=STREAM있지만 내가 볼 경우 ss -px | grep terminology:u_str\tESTAB\t0\t0\t* 1312426\t*1315046\tusers:(("terminology",pid=12731,fd=12))
mikeserv

1
@ mikeserv, 그것은 실제로하는 것처럼 보입니다! 최근에 많은 시간을 낭비한 것 같습니다 ...
Stéphane Chazelas


8

커널 3.3부터

이제 다음 을 사용하여이 정보를 얻을 수 있습니다 .ss

# ss -xp

이제 Peer열의 다른 ID에 해당하는 ID (inode 번호)를 열 에서 볼 수 있습니다 Local. 일치하는 ID는 소켓의 두 끝입니다.

참고 : UNIX_DIAG커널에서이 옵션을 활성화해야합니다.

커널 3.3 이전

리눅스는이 정보를 사용자 영역에 노출시키지 않았다.

그러나 커널 메모리살펴보면 이 정보에 액세스 할 수 있습니다.

참고 :이 답변은을 사용하여 그렇게 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 개의 소켓이 있습니다. 16 진수는 해당 커널 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. 또한 디버깅 기호가있는 커널 이미지 버전이 필요합니다. 데비안 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

Voilà, 위와 동일한 결과.

여러 머신에서 동일한 커널을 실행하는 경우 디버그 이미지가 필요없고 오프셋 값만 필요하므로이 변형을 사용하는 것이 더 쉽습니다.

이 오프셋 값을 처음에 (쉽게) 발견하려면 디버그 이미지가 필요합니다.

$ 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를 생각해 보겠습니다.
Stéphane Chazelas

2
이제 테스트 한 시스템에서 제대로 작동하는 것처럼 보이는 PoC 를 추가했습니다 .
Stéphane Chazelas

5

이 솔루션은 작동하지만 최근에 충분한 시스템 탭이 있다면 ss기반 접근법을 사용할 수있는 최근의 커널을 가질 가능성이 높으며 이전 커널을 사용 하는 경우 다른 방법을 사용할 수 있기 때문에 관심이 적습니다. 솔루션은 ,하지만 더 해키 일 가능성이 높습니다 및 추가 소프트웨어가 필요하지 않습니다.

systemtap이런 종류의 작업 에 사용하는 방법을 보여주는 데 여전히 유용합니다 .

작동중인 시스템 탭 (1.8 이상)이있는 최근 Linux 시스템에서 아래 스크립트를 사용하여 출력을 후 처리 할 수 ​​있습니다 lsof.

예를 들면 다음과 같습니다.

$ lsof -aUc nm- 애플릿 | 그 스크립트를 sudo
명령 PID 사용자 FD 유형 장치 크기 / 꺼짐 노드 이름
NM-애플릿 4183 스테판의 4U UNIX 0xffff8800a055eb40 0t0 36,888 TYPE = STREAM -> 0xffff8800a055e7c0 [DBUS 데몬, 4190 @ / TMP / DBUS-AiBCXOnuP6] 
nm의 애플릿 4183 스테판의 7U UNIX 0xffff8800a055e440 0t0 36,890 TYPE = STREAM -> 0xffff8800a055e0c0 [이 xorg 3080, @ / tmp / .X11-unix / X0] 
nm-applet 4183 스테판 8u 유닉스 0xffff8800a05c1040 0t0 36201 type = STREAM-> 0xffff8800a05c13c0 [dbus-daemon, 4118, @ / tmp / dbus-yxxNr1NkYC] 
nm-applet 4183 UNIX 0xffff8800a055d080 0t0 36,219 TYPE = STREAM -> 0xffff8800a055d400 [DBUS 데몬, 4118 @ / TMP / DBUS-yxxNr1NkYC] 
nm의 애플릿 4183 UNIX 0xffff88022e0dfb80 0t0 36,221 TYPE = STREAM 12U 스테판 -> 0xffff88022e0df800 [DBUS 데몬, 2,268 / VAR / run / dbus / system_bus_socket]
nm-applet 4183 스테판 13u 유닉스 0xffff88022e0f80c0 0t0 37025 type = STREAM-> 0xffff88022e29ec00 [dbus-daemon, 2268, / var / run / dbus / system_bus_socket]

(0xffff 대신 위의 0x0000000000000000이 표시되면 kernel.kptr_restrict시스템에 sysctl 매개 변수가 설정되어 권한이없는 프로세스에서 커널 포인터가 숨겨지기 때문입니다.이 경우 lsof루트로 실행 하여 루트로 실행해야합니다 . 의미있는 결과).

이 스크립트는 줄 바꿈 문자로 소켓 파일 이름을 처리하려고 시도하지 않지만 공백이나 콜론에 대처 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는 systemtap 1.8, 2012-06-17에 추가되었습니다 (최신은 2.7입니다)
Stéphane 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_DIAGUNIX 도메인 소켓에 대한 추가 정보를 제공하는, 즉 Virtual File System(VFS) 정보가 있습니다. 여기에는 Inode를 경로에서 프로세스로 연결하기위한 정보가 누락되어 있습니다. 버전 v4.19.0 ~ 55ss 부터 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:

얻을 수있는 장치 번호 및 경로

$ 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/socket, fuser /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에 포함 된 템플릿을 기반으로 자신 만의 litte 프로그램을 작성하십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.