Siapa yang punya ujung lain dari soket unix ini?

54

Saya ingin menentukan proses mana yang memiliki ujung soket UNIX.

Secara khusus, saya bertanya tentang yang dibuat dengan socketpair(), meskipun masalahnya sama untuk setiap soket UNIX.

Saya punya program parentyang membuat a socketpair(AF_UNIX, SOCK_STREAM, 0, fds), dan fork()s. Proses induk ditutup fds[1]dan terus fds[0]berkomunikasi. Anak melakukan yang sebaliknya close(fds[0]); s=fds[1],. Kemudian anak exec()itu program lain child1,. Keduanya dapat berkomunikasi bolak-balik melalui soketpair ini.

Sekarang, katakanlah saya tahu siapa parentitu, tetapi saya ingin mencari tahu siapa child1itu. Bagaimana saya melakukan ini?

Ada beberapa alat yang saya miliki, tetapi tidak ada yang bisa memberi tahu saya proses mana yang ada di ujung soket. Saya telah mencoba:

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

Pada dasarnya, saya dapat melihat dua soket, dan segala sesuatu tentang mereka, tetapi tidak dapat mengatakan bahwa mereka terhubung. Saya mencoba untuk menentukan FD mana dalam orangtua yang berkomunikasi dengan proses anak mana.

Jonathon Reinhart
sumber

Jawaban:

27

Sejak kernel 3.3, dimungkinkan menggunakan ssatau lsof-4.89atau di atas - lihat jawaban Stéphane Chazelas .

Dalam versi yang lebih lama, menurut penulis lsof, tidak mungkin untuk menemukan ini: kernel Linux tidak memaparkan informasi ini. Sumber: utas 2003 di comp.unix.admin .

Nomor yang ditunjukkan /proc/$pid/fd/$fdadalah nomor inode soket di sistem file soket virtual. Saat Anda membuat pasangan pipa atau soket, setiap ujung secara berturut-turut menerima nomor inode. Angka-angka tersebut dikaitkan secara berurutan, sehingga ada kemungkinan tinggi bahwa angka-angkanya berbeda dengan 1, tetapi ini tidak dijamin (baik karena soket pertama adalah N dan N +1 sudah digunakan karena pembungkus, atau karena beberapa utas lainnya adalah dijadwalkan antara kedua alokasi inode dan utas yang membuat beberapa inode juga).

Aku memeriksa definisi socketpairdi kernel 2.6.39 , dan kedua ujung soket tidak berkorelasi kecuali dengan jenis spesifik socketpairmetode . Untuk soket unix, itu unix_socketpairdinet/unix/af_unix.c .

Gilles 'SANGAT berhenti menjadi jahat'
sumber
2
Terima kasih @Gillles. Saya ingat pernah membaca sesuatu tentang itu beberapa waktu lalu, tetapi tidak dapat menemukannya lagi. Saya mungkin harus menulis patch untuk / proc / net / unix.
Jonathon Reinhart
Dan ya, saya telah membuat pengamatan dengan meningkatnya jumlah inode, dan saat ini itulah yang saya kerjakan. Namun, seperti yang Anda catat, itu tidak dijamin. Proses yang saya lihat memiliki setidaknya 40 soket unix terbuka, dan saya melihat satu contoh di mana N +1 tidak berlaku. Kekecewaan.
Jonathon Reinhart
1
@JonathonReinhart Aku memeriksa definisisocketpair , dan kedua ujung soket tidak berkorelasi kecuali dengan jenis spesifik socketpairmetode . Untuk soket unix, ada unix_socketpairdi `net / unix / af_unix.c . Akan menyenangkan untuk memiliki informasi ini untuk pipa juga.
Gilles 'SANGAT berhenti menjadi jahat'
36

Catatan : Saya sekarang mengelola lsofpembungkus yang menggabungkan kedua pendekatan yang dijelaskan di sini dan juga menambahkan informasi untuk rekan-rekan koneksi TCP loopback di https://github.com/stephane-chazelas/misc-scripts/blob/master/lsofc

Linux-3.3 dan yang lebih baru.

Di Linux, karena kernel versi 3.3 (dan asalkan UNIX_DIAGfitur dibangun di dalam kernel), rekan dari soket domain unix yang diberikan (termasuk soket pasang) dapat diperoleh dengan menggunakan API berbasis netlink baru .

lsof sejak versi 4.89 dapat menggunakan API itu:

lsof +E -aUc Xorg

Akan mencantumkan semua soket domain Unix yang memiliki proses yang namanya dimulai dengan Xorgkedua ujungnya dalam format yang mirip dengan:

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

Jika versi Anda lsofterlalu lama, ada beberapa opsi lagi.

The ssutilitas (dari iproute2) yang menggunakan yang API yang sama untuk mengambil dan menampilkan informasi dalam daftar unix domain sockets pada sistem termasuk informasi rekan.

Soket diidentifikasi oleh nomor inode mereka . Perhatikan bahwa ini tidak terkait dengan inode sistem file dari file socket.

Misalnya di:

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

dikatakan bahwa soket 3435997 (yang terikat ke soket ABSTRAK /tmp/.X11-unix/X0) terhubung dengan soket 3435996. -pOpsi ini dapat memberi tahu Anda proses mana yang membuat soket itu terbuka. Itu melakukan itu dengan melakukan beberapa readlinks /proc/$pid/fd/*, sehingga hanya bisa melakukan itu pada proses yang Anda miliki (kecuali Anda root). Misalnya di sini:

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

Untuk mengetahui proses apa yang telah 3435996, Anda dapat mencari entri sendiri di output dari ss -xp:

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

Anda juga dapat menggunakan skrip ini sebagai pembungkus lsofuntuk dengan mudah menampilkan informasi yang relevan di sana:

#! /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);

Sebagai contoh:

$ sudo that-lsof-wrapper -ad3 -p 29215
PERINTAH PID PENGGUNA UKURAN PERANGKAT FD TIPE / OFF NAMA NAMA
xterm 29215 stephane 3u unix 0xffff8800a07da4c0 0t0 3435996 type = STREAM <-> 3435997 [Xorg, 3080, @ / tmp / .X11-unix / X0]

Sebelum linux-3.3

Linux API lama untuk mengambil informasi soket unix adalah melalui /proc/net/unixfile teks. Ini mencantumkan semua soket domain Unix (termasuk soketnya). Bidang pertama di sana (jika tidak disembunyikan untuk non-pengguna super dengan kernel.kptr_restrictparameter sysctl) seperti yang sudah dijelaskan oleh @Totor berisi alamat kernel dari suatu unix_sockstruktur yang berisi peerbidang yang menunjuk ke rekan yang sesuai unix_sock. Ini juga merupakan lsofkeluaran untuk DEVICEkolom pada soket Unix.

Sekarang mendapatkan nilai peerbidang itu berarti bisa membaca memori kernel dan mengetahui offset peerbidang itu berkaitan dengan unix_sockalamat.

Beberapa gdbberbasis dan systemtapberbasis solusi telah diberikan tetapi mereka memerlukan gdb/ systemtapdan Linux kernel simbol debug untuk kernel yang berjalan yang diinstal yang umumnya tidak terjadi pada sistem produksi.

Hardcoding of the offset sebenarnya bukan pilihan karena bervariasi dengan versi kernel.

Sekarang kita dapat menggunakan pendekatan heuristik untuk menentukan offset: minta alat kita membuat dummy socketpair(lalu kita tahu alamat kedua rekan), dan cari alamat rekan di sekitar memori di ujung lainnya untuk menentukan offset.

Berikut ini adalah skrip proof-of-concept yang tidak hanya menggunakan perl(berhasil diuji dengan kernel 2.4.27 dan 2.6.32 pada i386 dan 3.13 dan 3.16 pada amd64). Seperti di atas, ini berfungsi sebagai pembungkus lsof:

Sebagai contoh:

$ that-lsof-wrapper -aUc nm-applet
PERINTAH PID PENGGUNA UKURAN PERANGKAT FD TIPE / OFF NAMA NAMA
nm-applet 4183 stephane 4u unix 0xffff8800a055eb40 0T0 36.888 type = STREAM -> 0xffff8800a055e7c0 [dbus-daemon, 4190, @ / tmp / dbus-AiBCXOnuP6] 
nm-applet 4183 stephane 7U unix 0xffff8800a055e440 0T0 36.890 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 0xffff88008228808e08e08bl0e0822880e0822880e0822880e08 type0 STREAM -> 0xffff8800a055d400 / 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]

Ini skripnya:

#! /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);
Stéphane Chazelas
sumber
1
@ mikeserv, itu tindak lanjut dari komentar itu . Tidak dapat menemukan ujung lain dari soket unix adalah sesuatu yang selalu mengganggu saya (seringkali ketika mencoba mencari klien X dan ada pertanyaan baru tentang itu ). Saya akan mencoba dan melihat apakah pendekatan yang serupa dapat digunakan untuk terminal semu dan menyarankannya kepada lsofpenulis.
Stéphane Chazelas
1
Saya masih tidak percaya ini tidak disediakan oleh kernel itu sendiri! Saya harus benar-benar mengirimkan tambalan, jika tidak ada yang lain selain untuk mengetahui mengapa itu belum ada.
Jonathon Reinhart
1
tidak sstidak melakukan hal ini? Agak di atas kepala saya, tetapi ss -pxdaftar banyak soket unix dengan informasi rekan seperti: 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* 15068dan judul kolom adalah ...State\tRecv-Q\tSend-Q\tLocal Address:Port\tPeer Address:Port
mikeserv
1
Juga, jika saya lsof -c terminologybisa, saya bisa melihat terminolo 12731\tmikeserv\t12u\tunix\t0xffff880600e82680\t0t0\t1312426\ttype=STREAMtetapi jika saya melakukannya ss -px | grep terminologysaya mendapatkan:u_str\tESTAB\t0\t0\t* 1312426\t*1315046\tusers:(("terminology",pid=12731,fd=12))
mikeserv
1
@ mikeserv, sepertinya memang benar! Sepertinya saya telah membuang banyak waktu belakangan ini ...
Stéphane Chazelas
8

Sejak kernel 3.3

Anda sekarang dapat memperoleh informasi ini dengan :ss

# ss -xp

Sekarang Anda dapat melihat PeerID di kolom (nomor inode) yang sesuai dengan ID lain di Localkolom. ID yang cocok adalah dua ujung soket.

Catatan: UNIX_DIAGOpsi ini harus diaktifkan di kernel Anda.

Sebelum kernel 3.3

Linux tidak memaparkan informasi ini ke userland.

Namun, dengan melihat ke dalam memori kernel , kita dapat mengakses informasi ini.

Catatan: Jawaban ini melakukannya dengan menggunakan gdb, namun, lihat jawaban @ StéphaneChazelas yang lebih rinci dalam hal ini.

# lsof | grep whatever
mysqld 14450 (...) unix 0xffff8801011e8280 (...) /var/run/mysqld/mysqld.sock
mysqld 14450 (...) unix 0xffff8801011e9600 (...) /var/run/mysqld/mysqld.sock

Ada 2 soket berbeda, 1 mendengarkan dan 1 didirikan. Nomor heksa adalah alamat ke unix_sockstruktur kernel yang sesuai , yang memiliki peeratribut sebagai alamat ujung soket yang lain (juga merupakan unix_sockcontoh struktur).

Sekarang kita dapat menggunakan gdbuntuk menemukan di peerdalam memori kernel:

# 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

Ini dia, ujung soket lainnya dipegang oleh mysql, PID 14815.

Kernel Anda harus dikompilasi KCORE_ELFuntuk digunakan /proc/kcore. Anda juga memerlukan versi kernel image Anda dengan simbol debugging. Pada Debian 7, apt-get install linux-image-3.2.0-4-amd64-dbgakan menyediakan file ini.

Tidak perlu untuk image kernel yang dapat di-debuggable ...

Jika Anda tidak memiliki (atau tidak ingin menyimpan) citra kernel debugging pada sistem, Anda dapat memberikan gdbmemori offset untuk mengakses peernilai "secara manual" . Nilai offset ini biasanya berbeda dengan versi kernel atau arsitektur.

Pada kernel saya, saya tahu offsetnya adalah 680 byte, yaitu 85 kali 64 bit. Jadi saya bisa melakukan:

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

Voa, hasil yang sama seperti di atas.

Jika Anda memiliki kernel yang sama berjalan di beberapa mesin, lebih mudah untuk menggunakan varian ini karena Anda tidak memerlukan gambar debug, hanya nilai offset.

Untuk (dengan mudah) menemukan nilai offset ini pada awalnya, Anda memang membutuhkan gambar debug:

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

Ini dia, 680 byte, ini adalah 85 x 64 bit, atau 170 x 32 bit.

Sebagian besar penghargaan untuk jawaban ini diberikan ke MvG .

Totor
sumber
2
Pendekatan lain untuk mengambil offset bisa dengan membuat socketpair, mengidentifikasi entri yang sesuai di / proc / net / unix berdasarkan nomor inode dari readlinks di / proc / pif / fd / *, dan memindai memori di sekitar alamat satu soket untuk alamat yang lain. Itu bisa membuat yang cukup portabel (lintas versi Linux dan arsitektur) yang dapat diimplementasikan oleh lsof sendiri. Saya akan mencoba membuat PoC.
Stéphane Chazelas
2
Saya sekarang telah menambahkan PoC yang tampaknya bekerja dengan baik pada sistem yang saya uji.
Stéphane Chazelas
5

Solusi ini, meskipun berfungsi, memiliki minat terbatas karena jika Anda memiliki systemtap yang cukup baru, kemungkinan Anda akan memiliki kernel yang cukup baru di mana Anda dapat menggunakan pendekatan ssberbasis , dan jika Anda menggunakan kernel yang lebih tua, yang lain solusi , meskipun lebih banyak peretasan lebih mungkin untuk bekerja dan tidak memerlukan perangkat lunak tambahan.

Masih bermanfaat sebagai peragaan cara menggunakan systemtapuntuk jenis tugas ini.

Jika pada sistem Linux baru-baru ini dengan tap sistem yang berfungsi (1,8 atau lebih baru), Anda dapat menggunakan skrip di bawah ini untuk memposting-proses output dari lsof:

Sebagai contoh:

$ lsof -aUc nm-applet | sudo-script itu
PERINTAH PID PENGGUNA UKURAN PERANGKAT FD TIPE / OFF NAMA NAMA
nm-applet 4183 stephane 4u unix 0xffff8800a055eb40 0T0 36.888 type = STREAM -> 0xffff8800a055e7c0 [dbus-daemon, 4190, @ / tmp / dbus-AiBCXOnuP6] 
nm-applet 4183 stephane 7U unix 0xffff8800a055e440 0T0 36.890 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 0xffff88008228808e08e08bl0e0822880e0822880e0822880e08 type0 STREAM -> 0xffff8800a055d400 / 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]

(jika Anda melihat 0x000000000000000000 di atas bukannya 0xffff ..., itu karena kernel.kptr_restrictparameter sysctl diatur pada sistem Anda yang menyebabkan pointer kernel disembunyikan dari proses yang tidak istimewa, dalam hal ini Anda harus menjalankan lsofsebagai root untuk mendapatkan hasil yang bermakna).

Script ini tidak berusaha untuk mengatasi nama file socket dengan karakter baris baru, tetapi juga tidak lsof(juga tidak lsofmengatasi kekosongan atau titik dua).

systemtapdi sini digunakan untuk membuang alamat dan alamat rekan semua unix_sockstruktur dalam unix_socket_tablehash di kernel.

Hanya diuji pada Linux 3.16 amd64 dengan systemtap 2.6, dan 3.13 dengan 2.3.

#! /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";
}
Stéphane Chazelas
sumber
parse error: unknown statistic operator @var: apakah saya melewatkan sesuatu?
Totor
@ Motor, @varditambahkan di systemtap 1.8, 2012-06-17 (terbaru 2.7)
Stéphane Chazelas
2

4,89 dari lsof mendukung menampilkan opsi titik akhir.

Dikutip dari 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.

Contoh output:

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
Masatake YAMATO
sumber
2

Karena ada kernel Linux 4.2 CONFIG_UNIX_DIAG, yang menyediakan informasi tambahan tentang soket domain UNIX, yaitu informasi Virtual File System(VFS), yang berisi informasi yang sejauh ini tidak ada untuk menghubungkan Inode dari jalur ke proses. Ini sudah bisa ditanyakan menggunakan ssalat dari iproute2 dimulai dengan versi v4.19.0 ~ 55 :

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

Nomor perangkat dan jalur Inode dapat Anda peroleh

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

ss juga mendukung pemfilteran:

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

tetapi perlu diketahui bahwa ini mungkin tidak mencantumkan soket yang tepat untuk Anda, karena proses jahat mungkin mengganti nama soket asli Anda dan menggantinya dengan yang jahat itu sendiri:

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

lsof /tmp/socket, fuser /tmp/socketdan ss --processes --unix --all --extended 'sport = /tmp/socket'semuanya akan mendaftar proses aslinya, bukan pengganti yang jahat. Alih-alih gunakan sesuatu seperti ini:

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

Atau tulis program litte Anda sendiri berdasarkan template yang terdapat di man 7 sock_diag .

pmhahn
sumber