Qui a l'autre extrémité de ce socketpair unix?

54

Je veux déterminer quel processus a l'autre extrémité d'un socket UNIX.

Plus précisément, je pose une question sur celle qui a été créée avec socketpair(), bien que le problème soit le même pour toutes les sockets UNIX.

J'ai un programme parentqui crée un socketpair(AF_UNIX, SOCK_STREAM, 0, fds), et l' fork()art. Le processus parent se ferme fds[1]et continue fds[0]à communiquer. L'enfant fait le contraire, close(fds[0]); s=fds[1]. Ensuite, l’enfant exec()est un autre programme child1,. Les deux peuvent communiquer en arrière via ce socketpair.

Maintenant, disons que je sais qui parentest, mais je veux savoir qui child1est. Comment puis-je faire cela?

Plusieurs outils sont à ma disposition, mais aucun ne peut me dire quel processus se trouve à l’autre bout du socket. J'ai essayé:

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

En gros, je peux voir les deux sockets et tout ce qui les concerne, mais je ne peux pas dire qu'ils sont connectés. J'essaie de déterminer quelle FD dans le parent communique avec quel processus enfant.

Jonathon Reinhart
la source

Réponses:

27

Depuis le noyau 3.3, il est possible en utilisant ssou lsof-4.89ou au- dessus - voir la réponse de Stéphane Chazelas .

Dans les versions antérieures, selon l'auteur de lsof, il était impossible de le savoir: le noyau Linux n'expose pas ces informations. Source: Fil 2003 sur comp.unix.admin .

Le numéro indiqué /proc/$pid/fd/$fdest le numéro d'inode du socket dans le système de fichiers du socket virtuel. Lorsque vous créez une paire de tubes ou de sockets, chaque extrémité reçoit successivement un numéro d'inode. Les nombres sont attribués de manière séquentielle, il y a donc une forte probabilité que les nombres diffèrent de 1, mais cela n’est pas garanti (soit parce que le premier socket était N et que N +1 était déjà utilisé en raison du wrapping, ou parce qu’un autre fil était programmé entre les deux affectations d’inodes et ce thread a également créé des inodes).

J'ai vérifié la définition de socketpairdans le noyau 2.6.39 et les deux extrémités du socket ne sont pas corrélées, sauf par la socketpairméthode spécifique au type . Pour les sockets unix, c'est unix_socketpairdansnet/unix/af_unix.c .

Gilles, arrête de faire le mal
la source
2
Merci @Gillles. Je me souviens d’avoir lu quelque chose à ce sujet il ya quelque temps, mais j’ai été incapable de le retrouver. Je vais peut-être devoir écrire un correctif pour / proc / net / unix.
Jonathon Reinhart
Et oui, j'avais fait cette observation avec l'augmentation du nombre d'inodes, et c'est actuellement ce sur quoi je travaille. Cependant, comme vous l'avez noté, ce n'est pas garanti. Le processus que je suis en train d’examiner comporte au moins 40 sockets Unix ouvertes et j’ai vu un cas où le N + 1 n’était pas vrai. Bummer.
Jonathon Reinhart
1
@JonathonReinhart J'ai vérifié la définition desocketpair , et les deux extrémités du socket ne sont pas corrélées, sauf par la socketpairméthode spécifique au type . Pour les sockets unix, cela se trouve unix_socketpairdans `net / unix / af_unix.c . Ce serait bien d'avoir cette information pour les pipes aussi.
Gilles 'SO- arrête d'être méchant'
36

Remarque : Je gère maintenant un lsofwrapper qui combine les deux approches décrites ici et ajoute également des informations pour les homologues de connexions TCP en boucle à l' adresse https://github.com/stephane-chazelas/misc-scripts/blob/master/lsofc.

Linux-3.3 et supérieur.

Sous Linux, à partir de la version 3.3 du noyau (et à condition que la UNIX_DIAGfonctionnalité soit intégrée au noyau), l'homologue d'un socket de domaine unix donné (y compris socketpairs) peut être obtenu à l'aide d'une nouvelle API basée sur netlink .

lsof depuis la version 4.89, on peut utiliser cette API:

lsof +E -aUc Xorg

Répertoriera tous les sockets de domaine Unix ayant un processus dont le nom commence par un des Xorgdeux bouts dans un format semblable à celui-ci:

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

Si votre version de lsofest trop ancienne, il existe quelques options supplémentaires.

L' ssutilitaire (depuis iproute2) utilise cette même API pour extraire et afficher des informations sur la liste des sockets de domaine Unix sur le système, y compris des informations d'homologue.

Les sockets sont identifiés par leur numéro d'inode . Notez que cela n'est pas lié à l'inode du système de fichiers du fichier de socket.

Par exemple dans:

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

il indique que le socket 3435997 (qui était lié au socket ABSTRACT /tmp/.X11-unix/X0) est connecté au socket 3435996. L' -poption peut vous indiquer le ou les processus pour lesquels cette socket est ouverte. Il le fait en faisant quelques readlinks sur /proc/$pid/fd/*, il ne peut le faire que sur les processus que vous possédez (sauf si vous êtes root). Par exemple ici:

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

Pour savoir quel processus a 3435996, vous pouvez rechercher sa propre entrée dans le résultat de ss -xp:

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

Vous pouvez également utiliser ce script comme enveloppe lsofpour y afficher facilement les informations pertinentes:

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

Par exemple:

$ sud that-lsof-wrapper -ad3 -p 29215
COMMAND PID UTILISATEUR TYPE FD TAILLE DU DISPOSITIF / NOM DE NŒUDS
xterm 29215 stephane 3u unix 0xffff8800a07da4c0 0t0 3435996 type = STREAM <-> 3435997 [Xorg, 3080, @ / tmp / .X11-unix / X0]

Avant linux-3.3

L'ancienne API Linux permettant de récupérer les informations de socket Unix se fait via le /proc/net/unixfichier texte. Il répertorie tous les sockets du domaine Unix (y compris socketpairs). Le premier champ qu'il contient (s'il n'est pas masqué par les non-utilisateurs avec le kernel.kptr_restrictparamètre sysctl), comme expliqué par @Totor, contient l'adresse du noyau d'une unix_sockstructure contenant un peerchamp pointant sur l' homologue correspondant unix_sock. C'est aussi ce qui lsofsort pour la DEVICEcolonne sur un socket Unix.

Désormais, obtenir la valeur de ce peerchamp signifie pouvoir lire la mémoire du noyau et connaître le décalage de ce peerchamp par rapport à l' unix_sockadresse.

Plusieurs à gdbbase et à systemtapbase de solutions ont déjà été données , mais ils ont besoin gdb/ systemtapet les symboles de débogage de Linux pour le noyau en cours d' exécution en cours d' installation qui est généralement pas le cas sur les systèmes de production.

Le codage en dur de l'offset n'est pas vraiment une option car cela varie avec la version du noyau.

Maintenant , nous pouvons utiliser une approche heuristique de déterminer l'offset: avoir notre outil créer un mannequin socketpair(nous savons l'adresse des deux pairs), et rechercher l'adresse du poste autour de la mémoire à l'autre extrémité pour déterminer le décalage.

Voici un script de perlvalidation de principe qui utilise précisément (testé avec succès avec les noyaux 2.4.27 et 2.6.32 sur i386 et 3.13 et 3.16 sur amd64). Comme ci-dessus, cela fonctionne comme un wrapper autour de lsof:

Par exemple:

$ that-lsof-wrapper -aUc nm-applet
COMMAND PID UTILISATEUR TYPE FD TAILLE DU DISPOSITIF / NOM DE NŒUDS
nm-applet 4183 stephane 4u unix 0xffff8800a055eb40 0T0 de type 36888 = STREAM -> 0xffff8800a055e7c0 [dbus-daemon, 4190, @ / tmp / dbus-AiBCXOnuP6] 
nm-applet 4183 stephane 7u unix 0xffff8800a055e440 0T0 36890 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- 
yxxNr unix 0xffff8800a055d080 0T0 de type 36219 = STREAM -> 0xffff8800a055d400 [dbus-daemon, 4118, @ / tmp / dbus-yxxNr1NkYC] 
nm-applet unix 12u 4183 stephane 0xffff88022e0dfb80 0T0 36221 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]

Voici le script:

#! /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
la source
1
@mikeserv, c'est un suivi de ce commentaire . Ne pas être capable de trouver l'autre extrémité des sockets unix est quelque chose qui m'a toujours agacé (souvent lorsque j'essayais de trouver des clients X et qu'il y avait une question récente à ce sujet ). Je vais essayer de voir si une approche similaire peut être utilisée pour les pseudo-terminaux et les suggérer à l' lsofauteur.
Stéphane Chazelas
1
Je n'arrive toujours pas à croire que ce n'est pas fourni par le noyau lui-même! Je devrais vraiment soumettre un patch, ne serait-ce que pour découvrir pourquoi il n'existe pas déjà.
Jonathon Reinhart
1
ne fait sspas ça? C'est un peu au-dessus de ma tête, mais ss -pxrépertorie un grand nombre de sockets Unix avec des informations sur les pairs du type: 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* 15068et les en-têtes de colonne sont ...State\tRecv-Q\tSend-Q\tLocal Address:Port\tPeer Address:Port
mikeserv
1
Aussi, si je le fais lsof -c terminologyje peux voir terminolo 12731\tmikeserv\t12u\tunix\t0xffff880600e82680\t0t0\t1312426\ttype=STREAMmais si je le fais ss -px | grep terminologyje reçois:u_str\tESTAB\t0\t0\t* 1312426\t*1315046\tusers:(("terminology",pid=12731,fd=12))
mikeserv
1
@ mikeserv, on dirait que c'est le cas! Il semble que j'ai perdu beaucoup de temps ces derniers temps ...
Stéphane Chazelas
9

Erkki Seppala a en fait un outil qui récupère ces informations du noyau Linux avec gdb .. Il est disponible ici .

Caleb
la source
2
Information très utile! Même si l’outil n’a pas fonctionné immédiatement (cela a causé un problème de noyau), l’idée m’a aidé à identifier l’autre extrémité. J'ai décrit ma solution sur Stack Overflow.
MvG
8

Depuis le noyau 3.3

Vous pouvez maintenant obtenir cette information avec ss:

# ss -xp

Vous pouvez maintenant voir dans la Peercolonne un identifiant (numéro d'inode) qui correspond à un autre identifiant dans la Localcolonne. Les ID correspondants sont les deux extrémités d'un socket.

Remarque: L' UNIX_DIAGoption doit être activée dans votre noyau.

Avant le noyau 3.3

Linux n'a pas exposé cette information à l'utilisateur.

Cependant, en regardant dans la mémoire du noyau , nous pouvons accéder à ces informations.

Remarque: cette réponse le fait en utilisant gdb, cependant, veuillez consulter la réponse de @ StéphaneChazelas qui est plus élaborée à cet égard.

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

Il y a 2 prises différentes, 1 à l'écoute et 1 établie. Le nombre hexa est l'adresse de la unix_sockstructure de noyau correspondante , l' peerattribut étant l'adresse de l'autre extrémité du socket (également une unix_sockinstance de structure).

Maintenant, nous pouvons utiliser gdbpour trouver la peermémoire dans le noyau:

# 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

Voilà, l’autre extrémité de la prise est tenue par mysql, le PID 14815.

Votre noyau doit être compilé avec KCORE_ELFpour pouvoir être utilisé /proc/kcore. De plus, vous avez besoin d’une version de l’image de votre noyau avec des symboles de débogage. Sur Debian 7, apt-get install linux-image-3.2.0-4-amd64-dbgfournira ce fichier.

Pas besoin de l'image du noyau débogable ...

Si vous ne possédez pas (ou ne souhaitez pas conserver) l'image de noyau de débogage sur le système, vous pouvez attribuer à gdbl'offset de mémoire un accès "manuel" à la peervaleur. Cette valeur de décalage diffère généralement avec la version du noyau ou l'architecture.

Sur mon noyau, je sais que le décalage est de 680 octets, soit 85 fois 64 bits. Donc je peux faire:

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

Voilà, même résultat que ci-dessus.

Si vous avez le même noyau s'exécutant sur plusieurs machines, il est plus facile d'utiliser cette variante car vous n'avez pas besoin de l'image de débogage, seulement de la valeur de décalage.

Pour découvrir (facilement) cette valeur de décalage dans un premier temps, vous avez besoin de l'image de débogage:

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

Voilà, 680 octets, 85 x 64 bits, ou 170 x 32 bits.

La majeure partie du crédit de cette réponse revient à MvG .

Totor
la source
2
Une autre approche pour récupérer le décalage pourrait consister à créer un socketpair, à identifier les entrées correspondantes dans / proc / net / unix en se basant sur les numéros d’inode à partir de readlinks sur / proc / pif / fd / * et à balayer la mémoire autour de l’adresse d’un socket. l'adresse de l'autre. Cela pourrait constituer une solution relativement portable (à travers les versions et architectures Linux) pouvant être implémentée par lsof elle-même. Je vais essayer de trouver un PoC.
Stéphane Chazelas
2
J'ai maintenant ajouté un tel PoC qui semble bien fonctionner sur les systèmes que j'ai testés.
Stéphane Chazelas
5

Cette solution, bien que travail, est d' un intérêt limité car si vous avez une systemtap récente assez, les chances sont que vous aurez un noyau récente assez où vous pouvez utiliser en ssfonction des approches , et si vous êtes sur un noyau plus ancien, cet autre solution , bien que plus de hacky est plus susceptible de fonctionner et ne nécessite pas de logiciel supplémentaire.

Encore utile comme démonstration de l’utilisation systemtapde ce type de tâche.

Si vous travaillez sur un système Linux récent avec un systemtap opérationnel (1.8 ou plus récent), vous pouvez utiliser le script ci-dessous pour post-traiter la sortie de lsof:

Par exemple:

$ lsof -aUc nm-applet | sudo that-script
COMMAND PID UTILISATEUR TYPE FD TAILLE DU DISPOSITIF / NOM DE NŒUDS
nm-applet 4183 stephane 4u unix 0xffff8800a055eb40 0T0 de type 36888 = STREAM -> 0xffff8800a055e7c0 [dbus-daemon, 4190, @ / tmp / dbus-AiBCXOnuP6] 
nm-applet 4183 stephane 7u unix 0xffff8800a055e440 0T0 36890 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- 
yxxNr unix 0xffff8800a055d080 0T0 de type 36219 = STREAM -> 0xffff8800a055d400 [dbus-daemon, 4118, @ / tmp / dbus-yxxNr1NkYC] 
nm-applet unix 12u 4183 stephane 0xffff88022e0dfb80 0T0 36221 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 vous voyez 0x0000000000000000 ci-dessus au lieu de 0xffff ..., c'est parce que le kernel.kptr_restrictparamètre sysctl est défini sur votre système, ce qui a pour effet de masquer les pointeurs du noyau aux processus non privilégiés. Dans ce cas, vous devrez vous lancer en lsoftant que root pour obtenir un résultat significatif).

Ce script ne tente pas de gérer les noms de fichier de socket avec des caractères de nouvelle ligne, mais ne le fait pas non plus lsof(ni les lsofblancs ni les deux points).

systemtapici est utilisé pour vider l’adresse et l’adresse de l’homologue de toutes les unix_sockstructures du unix_socket_tablehachage du noyau.

Testé uniquement sur Linux 3.16 amd64 avec systemtap 2.6 et 3.13 avec 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
la source
parse error: unknown statistic operator @var: est-ce que je manque quelque chose?
Totor
@Totor, a @varété ajouté à systemtap 1.8, 2012-06-17 (la dernière est 2.7)
Stéphane Chazelas
2

4.89 de lsof prend en charge l’affichage des options de points de terminaison.

Cité 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.

Exemple de sortie:

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
la source
2

Depuis le noyau Linux 4.2, il existe CONFIG_UNIX_DIAGdes informations supplémentaires sur les sockets de domaine UNIX, à savoir les informations Virtual File System(VFS), qui contiennent les informations manquantes jusqu'à présent pour relier l'inode du chemin d'accès au processus. Il peut déjà être interrogé à l'aide de l' ssoutil de iproute2 à partir de la version 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:

Le numéro de périphérique et le chemin Inode que vous pouvez obtenir

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

ss prend également en charge le filtrage:

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

mais sachez que ceci pourrait ne pas lister le bon socket pour vous, car un processus pervers pourrait renommer votre socket original et le remplacer par son propre mauvais:

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

lsof /tmp/socket, fuser /tmp/socketet ss --processes --unix --all --extended 'sport = /tmp/socket'tous énuméreront le processus original, pas le remplaçant diabolique. Utilisez plutôt quelque chose comme ceci:

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

Ou écrivez votre propre petit programme basé sur le modèle contenu dans man 7 sock_diag .

pmhahn
la source