¿Quién tiene el otro extremo de este par de enchufes Unix?

54

Quiero determinar qué proceso tiene el otro extremo de un socket UNIX.

Específicamente, estoy preguntando acerca de uno que fue creado con socketpair(), aunque el problema es el mismo para cualquier socket UNIX.

Tengo un programa parentque crea un socketpair(AF_UNIX, SOCK_STREAM, 0, fds), y fork()s. El proceso principal se cierra fds[1]y se mantiene fds[0]para comunicarse. El niño hace lo contrario, close(fds[0]); s=fds[1]. Entonces el niño exec()es otro programa child1,. Los dos pueden comunicarse de ida y vuelta a través de este socketpair.

Ahora, digamos que sé quién parentes, pero quiero averiguar quién child1es. ¿Cómo hago esto?

Hay varias herramientas a mi disposición, pero ninguna puede decirme qué proceso está en el otro extremo del zócalo. Yo he tratado:

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

Básicamente, puedo ver los dos enchufes, y todo sobre ellos, pero no puedo decir que están conectados. Estoy tratando de determinar qué FD en el padre se está comunicando con qué proceso hijo.

Jonathon Reinhart
fuente

Respuestas:

27

Desde kernel 3.3, es posible utilizar sso lsof-4.89o superior - véase la respuesta de Stéphane Chazelas .

En versiones anteriores, según el autor de lsof, era imposible descubrir esto: el kernel de Linux no expone esta información. Fuente: hilo 2003 en comp.unix.admin .

El número que se muestra /proc/$pid/fd/$fdes el número de inodo del socket en el sistema de archivos del socket virtual. Cuando crea un par de tubos o enchufes, cada extremo recibe sucesivamente un número de inodo. Los números se atribuyen secuencialmente, por lo que existe una alta probabilidad de que los números difieran en 1, pero esto no está garantizado (ya sea porque el primer zócalo era N y N +1 ya estaba en uso debido a la envoltura, o porque algún otro hilo estaba programado entre las dos asignaciones de inodo y ese hilo también creó algunos inodes).

Verifiqué la definición de socketpairen el kernel 2.6.39 , y los dos extremos del socket no están correlacionados, excepto por el socketpairmétodo de tipo específico . Para tomas unix, eso está unix_socketpairennet/unix/af_unix.c .

Gilles 'SO- deja de ser malvado'
fuente
2
Gracias @Gillles. Recuerdo haber leído algo sobre eso hace un tiempo, pero no pude encontrarlo nuevamente. Es posible que deba escribir un parche para / proc / net / unix.
Jonathon Reinhart
Y sí, había hecho esa observación con el creciente número de inodos, y actualmente eso es con lo que estoy trabajando. Sin embargo, como notó, no está garantizado. El proceso que estoy viendo tiene al menos 40 zócalos Unix abiertos, y vi una instancia donde el N + 1 no era cierto. Gorrón.
Jonathon Reinhart
1
@JonathonReinhart Verifiqué la definición desocketpair , y los dos extremos del zócalo no están correlacionados, excepto por el socketpairmétodo específico del tipo . Para los sockets de Unix, está unix_socketpairen `net / unix / af_unix.c . Sería bueno tener esta información también para las tuberías.
Gilles 'SO- deja de ser malvado'
36

Nota : ahora mantengo un lsofcontenedor que combina los dos enfoques descritos aquí y también agrega información para pares de conexiones TCP de bucle invertido en https://github.com/stephane-chazelas/misc-scripts/blob/master/lsofc

Linux-3.3 y superior.

En Linux, desde la versión 3.3 del kernel (y siempre que la UNIX_DIAGcaracterística esté integrada en el kernel), el par de un socket de dominio unix dado (incluye pares de socket) se puede obtener utilizando una nueva API basada en netlink .

lsof desde la versión 4.89 puede hacer uso de esa API:

lsof +E -aUc Xorg

Enumerará todos los sockets de dominio de Unix que tienen un proceso cuyo nombre comienza Xorgen cada extremo en un formato similar a:

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

Si su versión de lsofes demasiado antigua, hay algunas opciones más.

La ssutilidad (from iproute2) utiliza esa misma API para recuperar y mostrar información en la lista de sockets de dominio Unix en el sistema, incluida la información de pares.

Los enchufes se identifican por su número de inodo . Tenga en cuenta que no está relacionado con el inodo del sistema de archivos del archivo socket.

Por ejemplo en:

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

dice que el zócalo 3435997 (que estaba vinculado al zócalo ABSTRACT /tmp/.X11-unix/X0) está conectado con el zócalo 3435996. La -popción puede decirle qué proceso (s) tiene ese zócalo abierto. Lo hace haciendo algunos readlinks on /proc/$pid/fd/*, por lo que solo puede hacerlo en los procesos que posee (a menos que sea root). Por ejemplo aquí:

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

Para averiguar qué proceso (s) tiene 3435996, puede buscar su propia entrada en la salida de ss -xp:

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

También puede usar este script como envoltorio lsofpara mostrar fácilmente la información relevante allí:

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

Por ejemplo:

$ sudo that-lsof-wrapper -ad3 -p 29215
COMANDO PID USUARIO FD TIPO DISPOSITIVO TAMAÑO / APAGADO NODO NOMBRE
xterm 29215 stephane 3u unix 0xffff8800a07da4c0 0t0 3435996 type = STREAM <-> 3435997 [Xorg, 3080, @ / tmp / .X11-unix / X0]

Antes de linux-3.3

La antigua API de Linux para recuperar información de socket de Unix es a través del /proc/net/unixarchivo de texto. Enumera todos los sockets de dominio de Unix (incluidos los pares de sockets). El primer campo allí (si no está oculto para los no superusuarios con el kernel.kptr_restrictparámetro sysctl) como ya lo explicó @Totor contiene la dirección del núcleo de una unix_sockestructura que contiene un peercampo que apunta al par correspondiente unix_sock. También es lo que lsofgenera la DEVICEcolumna en un socket Unix.

Ahora obtener el valor de ese peercampo significa poder leer la memoria del kernel y conocer el desplazamiento de ese peercampo con respecto a la unix_sockdirección.

Ya se han dado varias soluciones gdbbasadas y systemtapbasadas , pero requieren gdb/ systemtapy símbolos de depuración del kernel de Linux para la instalación del kernel en ejecución, lo que generalmente no es el caso en los sistemas de producción.

Codificar el desplazamiento no es realmente una opción, ya que varía con la versión del kernel.

Ahora podemos usar un enfoque heurístico para determinar el desplazamiento: haga que nuestra herramienta cree un maniquí socketpair(entonces conocemos la dirección de ambos pares) y busque la dirección del par alrededor de la memoria en el otro extremo para determinar el desplazamiento.

Aquí hay un script de prueba de concepto que hace exactamente eso usando perl(probado con éxito con el kernel 2.4.27 y 2.6.32 en i386 y 3.13 y 3.16 en amd64). Al igual que arriba, funciona como un envoltorio alrededor de lsof:

Por ejemplo:

$ that-lsof-wrapper -aUc nm-applet
COMANDO PID USUARIO FD TIPO DISPOSITIVO TAMAÑO / APAGADO NODO NOMBRE
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 36,201 type = STREAM -> 0xffff8800a05c13c0 [dbus-daemon, 4118, @ / tmp / dbus-yxxNr1NkYC] 
nm-applet 4183 stephane 11u UNIX 0xffff8800a055d080 0T0 36,219 type = STREAM -> 0xffff8800a055d400 [dbus-daemon, 4118, @ / tmp / dbus-yxxNr1NkYC] 
nm-applet 4183 stephane 12u UNIX 0xffff88022e0dfb80 0T0 36,221 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]

Aquí está el guión:

#! /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
fuente
1
@mikeserv, eso es un seguimiento de ese comentario . No poder encontrar el otro extremo de los sockets de Unix es algo que siempre me ha molestado (a menudo cuando trato de encontrar clientes X y había una pregunta reciente al respecto ). Trataré de ver si se puede usar un enfoque similar para pseudo terminales y sugeriré eso al lsofautor.
Stéphane Chazelas
1
¡Todavía no puedo creer que esto no sea proporcionado por el núcleo mismo! Realmente debería enviar un parche, para nada más que descubrir por qué aún no existe.
Jonathon Reinhart
1
no ssno hacer esto? Es un poco por encima de mi cabeza, pero ss -pxlas listas de una gran cantidad de conectores Unix con la información de pares como: 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* 15068y los títulos de las columnas son ...State\tRecv-Q\tSend-Q\tLocal Address:Port\tPeer Address:Port
mikeserv
1
Además, si lo hago lsof -c terminology, puedo ver, terminolo 12731\tmikeserv\t12u\tunix\t0xffff880600e82680\t0t0\t1312426\ttype=STREAMpero si lo hago ss -px | grep terminology, obtengo:u_str\tESTAB\t0\t0\t* 1312426\t*1315046\tusers:(("terminology",pid=12731,fd=12))
mikeserv
1
@mikeserv, ¡parece que sí! Parece que he estado perdiendo mucho tiempo últimamente ...
Stéphane Chazelas
8

Desde el kernel 3.3

Usted puede ahora obtener esta información con ss:

# ss -xp

Ahora puede ver en la Peercolumna una ID (número de inodo) que corresponde a otra ID en la Localcolumna. Las ID coincidentes son los dos extremos de un zócalo.

Nota: La UNIX_DIAGopción debe estar habilitada en su kernel.

Antes del kernel 3.3

Linux no expuso esta información a la tierra de usuarios.

Sin embargo, al examinar la memoria del núcleo , podemos acceder a esta información.

Nota: Esta respuesta lo hace utilizando gdb, sin embargo, consulte la respuesta de @ StéphaneChazelas, que es más elaborada a este respecto.

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

Hay 2 enchufes diferentes, 1 escucha y 1 establecido. El número hexa es la dirección de la unix_sockestructura del núcleo correspondiente , con un peeratributo que es la dirección del otro extremo del socket (también una unix_sockinstancia de estructura).

Ahora podemos usar gdbpara encontrar la peermemoria interna del 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

Aquí tienes, el otro extremo del zócalo está sujeto mysql, PID 14815.

Su núcleo debe estar compilado KCORE_ELFpara poder usarlo /proc/kcore. Además, necesita una versión de su imagen del núcleo con símbolos de depuración. En Debian 7, apt-get install linux-image-3.2.0-4-amd64-dbgproporcionará este archivo.

No se necesita la imagen del núcleo depurable ...

Si no tiene (o no desea conservar) la imagen del núcleo de depuración en el sistema, puede asignar gdbel desplazamiento de memoria para acceder "manualmente" al peervalor. Este valor de compensación generalmente difiere con la versión o arquitectura del kernel.

En mi kernel, sé que el desplazamiento es de 680 bytes, es decir, 85 veces 64 bits. Entonces puedo hacer:

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

Voilà, mismo resultado que el anterior.

Si tiene el mismo núcleo ejecutándose en varias máquinas, es más fácil usar esta variante porque no necesita la imagen de depuración, solo el valor de compensación.

Para descubrir (fácilmente) este valor de compensación al principio, necesita la imagen de depuración:

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

Aquí tienes, 680 bytes, esto es 85 x 64 bits, o 170 x 32 bits.

La mayor parte del crédito por esta respuesta va a MvG .

Totor
fuente
2
Otro enfoque para recuperar el desplazamiento podría ser crear un par de socket, identificar las entradas correspondientes en / proc / net / unix en función de los números de inodo de los enlaces de lectura en / proc / pif / fd / *, y escanear la memoria alrededor de la dirección de un socket para La dirección del otro. Eso podría ser razonablemente portátil (entre versiones y arquitecturas de Linux) que podría implementarse por sí mismo. Trataré de llegar a un PoC.
Stéphane Chazelas
2
Ahora he agregado un PoC que parece funcionar bien en los sistemas que he probado.
Stéphane Chazelas
5

Esta solución, aunque funciona, es de interés limitado, ya que si tiene una información sobre el sistema lo suficientemente reciente, es probable que tenga un kernel lo suficientemente reciente donde pueda usar enfoques ssbasados , y si está en un kernel más antiguo, ese otro solución , aunque es más probable que funcione más hacky y no requiere software adicional.

Sigue siendo útil como demostración de cómo usarlo systemtappara este tipo de tarea.

Si se encuentra en un sistema Linux reciente con una pestaña de sistema en funcionamiento (1.8 o más reciente), puede usar el siguiente script para procesar la salida de lsof:

Por ejemplo:

$ lsof -aUc nm-applet | sudo that-script
COMANDO PID USUARIO FD TIPO DISPOSITIVO TAMAÑO / APAGADO NODO NOMBRE
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 36,201 type = STREAM -> 0xffff8800a05c13c0 [dbus-daemon, 4118, @ / tmp / dbus-yxxNr1NkYC] 
nm-applet 4183 stephane 11u UNIX 0xffff8800a055d080 0T0 36,219 type = STREAM -> 0xffff8800a055d400 [dbus-daemon, 4118, @ / tmp / dbus-yxxNr1NkYC] 
nm-applet 4183 stephane 12u UNIX 0xffff88022e0dfb80 0T0 36,221 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]

(si ve 0x0000000000000000 arriba en lugar de 0xffff ..., es porque el kernel.kptr_restrictparámetro sysctl está configurado en su sistema lo que hace que los punteros del kernel se oculten de los procesos no privilegiados, en cuyo caso deberá ejecutar lsofcomo root para obtener un resultado significativo).

Este script no intenta hacer frente a los nombres de archivos de socket con caracteres de nueva línea, pero tampoco lo hace lsof(ni hace lsoffrente a espacios en blanco o dos puntos).

systemtapaquí se usa para volcar la dirección y la dirección de igual de todas las unix_sockestructuras en el unix_socket_tablehash en el kernel.

Solo probado en Linux 3.16 amd64 con systemtap 2.6 y 3.13 con 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
fuente
parse error: unknown statistic operator @var: ¿Me estoy perdiendo de algo?
Totor
@Totor, @varse agregó en systemtap 1.8, 2012-06-17 (la última es 2.7)
Stéphane Chazelas
2

4.89 de lsof admite la visualización de opciones de punto final.

Citado de 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.

Ejemplo de salida:

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
fuente
2

Desde Linux kernel 4.2 existe CONFIG_UNIX_DIAG, que proporciona información adicional sobre los sockets de dominio UNIX, es decir, la información Virtual File System(VFS), que contiene la información que falta hasta ahora para vincular el Inode desde la ruta al proceso. Ya se puede consultar con la ssherramienta de iproute2 a partir de la versión 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:

El número de dispositivo y la ruta Inode que puede obtener de

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

ss También es compatible con el filtrado:

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

pero tenga en cuenta que esto podría no enumerar el zócalo adecuado para usted, ya que un proceso malvado podría cambiar el nombre de su zócalo original y reemplazarlo por el propio malvado:

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

lsof /tmp/socket, fuser /tmp/sockety ss --processes --unix --all --extended 'sport = /tmp/socket'todos enumerarán el proceso original, no el malvado reemplazo. En cambio, use algo como esto:

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

O escriba su propio pequeño programa basado en la plantilla contenida en man 7 sock_diag .

pmhahn
fuente