नोट : मैं अब एक lsof
रैपर रखता हूं जो यहां वर्णित दोनों दृष्टिकोणों को जोड़ता है और साथ ही https://github.com/stephane-chazelas/misc-scripts/blob/master/lsofc पर लूपबैक टीसीपी कनेक्शन के साथियों के लिए जानकारी जोड़ता है।
Linux-3.3 और ऊपर।
लिनक्स पर, चूंकि कर्नेल संस्करण 3.3 (और यह UNIX_DIAG
सुविधा प्रदान करता है कि कर्नेल में बनाया गया है), एक दिए गए यूनिक्स डोमेन सॉकेट (सॉकेटकेस सहित) का पीयर एक नए नेटलिंक आधारित एपीआई का उपयोग करके प्राप्त किया जा सकता है।
lsof
4.89 संस्करण के बाद से उस एपीआई का उपयोग कर सकते हैं:
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 के उपयोग को पुनः प्राप्त और साथियों के बारे में जानकारी सहित सिस्टम पर यूनिक्स डोमेन सॉकेट की सूची के बारे में जानकारी प्रदर्शित करने के लिए बनाता है।
सॉकेट्स की पहचान उनके आईनोड नंबर से की जाती है । ध्यान दें कि यह सॉकेट फ़ाइल के फाइल सिस्टम इनोड से संबंधित नहीं है।
उदाहरण के लिए:
$ ss -x
[...]
u_str ESTAB 0 0 @/tmp/.X11-unix/X0 3435997 * 3435996
यह कहता है कि सॉकेट 3435997 (जो ABSTRACT सॉकेट /tmp/.X11-unix/X0
से जुड़ा हुआ था) सॉकेट 3435996 से जुड़ा है। -p
विकल्प आपको बता सकता है कि किस प्रक्रिया (तों) में वह सॉकेट खुला है। यह ऐसा कुछ readlink
s पर करता है /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);
उदाहरण के लिए:
$ सूडो कि- lsof-आवरण -ad3 -p 29215
COMMID PID USER FD TYPE DEVICE SIZE / OFF NODE NAME
xterm 29215 स्टीफन 3u यूनिक्स 0xffff8800a07da4c0 0t0 3435996 प्रकार = STREAM <-> 3435997 [Xorg, 3080, @ / tmp / .X11-unix / X0]।
Linux-3.3 से पहले
/proc/net/unix
पाठ लाइन फ़ाइल के माध्यम से यूनिक्स सॉकेट जानकारी प्राप्त करने के लिए पुराना लिनक्स एपीआई है । यह सभी यूनिक्स डोमेन सॉकेट (सॉकेटपेयर सहित) को सूचीबद्ध करता है। वहाँ में पहले क्षेत्र (यदि साथ गैर superusers को छिपा नहीं kernel.kptr_restrict
sysctl पैरामीटर) के रूप में पहले से ही @Totor से समझाया एक की गिरी पता शामिल unix_sock
संरचना है कि एक में शामिल peer
क्षेत्र इसी की ओर इशारा करते सहकर्मी unix_sock
। यह भी क्या एक यूनिक्स सॉकेट पर कॉलम के lsof
लिए आउटपुट है DEVICE
।
अब उस peer
फ़ील्ड का मान प्राप्त करने का अर्थ है कि कर्नेल मेमोरी को पढ़ने में सक्षम होना और पते के peer
संबंध में उस फ़ील्ड की ऑफसेट को जानना unix_sock
।
कई- gdb
आधारित और systemtap
आधारित समाधान पहले ही दिए जा चुके हैं, लेकिन उन्हें चल रहे कर्नेल के लिए gdb
/ systemtap
और लिनक्स कर्नेल डिबग प्रतीकों की आवश्यकता होती है, जो आमतौर पर उत्पादन प्रणालियों पर नहीं होता है।
ऑफसेट को हार्डकोड करना वास्तव में एक विकल्प नहीं है क्योंकि यह कर्नेल संस्करण के साथ बदलता रहता है।
अब हम ऑफसेट को निर्धारित करने में एक अनुमानी दृष्टिकोण का उपयोग कर सकते हैं: क्या हमारे उपकरण ने एक डमी बनाई है socketpair
(फिर हम दोनों साथियों का पता जानते हैं), और ऑफसेट को निर्धारित करने के लिए दूसरे छोर पर मेमोरी के आसपास सहकर्मी के पते की खोज करें ।
यहां एक प्रूफ-ऑफ-कॉन्सेप्ट स्क्रिप्ट है जो सिर्फ इतना ही करती है perl
(i386 पर कर्नेल 2.4.27 और 2.6.32 के साथ सफलतापूर्वक परीक्षण किया गया और amd64 पर 3.13 और 3.16)। ऊपर की तरह, यह एक आवरण के रूप में काम करता है lsof
:
उदाहरण के लिए:
$ वह-लसोफ़-रैपर -aUc nm-applet
COMMID PID USER FD TYPE DEVICE SIZE / OFF NODE NAME
एनएम-एप्लेट 4183 स्टीफ़न 4U यूनिक्स 0xffff8800a055eb40 0t0 36,888 प्रकार = धारा -> 0xffff8800a055e7c0 [dbus-डेमॉन, 4190, @ / tmp / dbus-AiBCXOnuP6]
एनएम-एप्लेट 4183 स्टीफ़न 7U यूनिक्स 0xffff8800a055e440 0t0 36,890 प्रकार = धारा -> 0xffff8800a055e0c0 [Xorg, 3080, @ / tmp / .X11 यूनिक्स / X 0]
एनएम-एप्लेट 4183 स्टीफ़न 8u यूनिक्स 0xffff8800a05c1040 0t0 36201 प्रकार = धारा -> 0xffff8800a05c13c0 [dbus-डेमॉन, 4118, @ / tmp / dbus-yxxNr1NkYC]
एनएम-एप्लेट 4183 स्टीफ़न 11u यूनिक्स 0xffff8800a055d080 0t0 36,219 प्रकार = धारा -> 0xffff8800a055d400 [dbus-डेमॉन, 4118, @ / tmp / dbus-yxxNr1NkYC]
एनएम-एप्लेट 4183 12U यूनिक्स 0xffff88022e0dfb80 0t0 36,221 प्रकार = धारा स्टीफ़न -> 0xffff88022e0df800 [dbus-डेमॉन, 2268, / var / चलाने / dbus / system_bus_socket]
एनएम-एप्लेट 4183 स्टीफन 13u यूनिक्स 0xffff88022e0f80c0 0t0 37025 प्रकार = 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);