इस यूनिक्स सॉकेटपेयर का दूसरा छोर किसे मिला है?


54

मैं यह निर्धारित करना चाहता हूं कि किस प्रक्रिया में UNIX सॉकेट का दूसरा छोर है।

विशेष रूप से, मैं उस एक के बारे में पूछ रहा हूं जिसके साथ बनाया गया था socketpair(), हालांकि समस्या किसी भी यूनिक्स सॉकेट के लिए समान है।

मेरे पास एक कार्यक्रम है 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

असल में, मैं दो सॉकेट और उनके बारे में सब कुछ देख सकता हूं, लेकिन यह नहीं बता सकता कि वे जुड़े हुए हैं। मैं यह निर्धारित करने की कोशिश कर रहा हूं कि माता-पिता में कौन सी एफडी किस बच्चे की प्रक्रिया के साथ संचार कर रही है।

जवाबों:


27

कर्नेल 3.3 के बाद से, इसे का उपयोग संभव है ssया lsof-4.89देखते हैं - या इसके बाद स्टीफन Chazelas का जवाब

पुराने संस्करणों में, लेखक के अनुसार lsof, यह पता लगाना असंभव था: लिनक्स कर्नेल इस जानकारी को उजागर नहीं करता है। स्रोत: 2003 धागा comp.unix.admin पर

/proc/$pid/fd/$fdवर्चुअल सॉकेट फ़ाइल सिस्टम में सॉकेट का इनोड नंबर दिखाया गया है। जब आप एक पाइप या सॉकेट जोड़ी बनाते हैं, तो प्रत्येक छोर क्रमिक रूप से एक इनोड नंबर प्राप्त करता है। संख्याओं को क्रमिक रूप से जिम्मेदार ठहराया जाता है, इसलिए एक उच्च संभावना है कि संख्या 1 से भिन्न होती है, लेकिन यह गारंटी नहीं है (या तो क्योंकि पहला सॉकेट एन था और एन 1 पहले से ही लपेटने के कारण उपयोग में था, या क्योंकि कुछ अन्य धागा था दो इनोड आवंटन के बीच अनुसूचित और उस थ्रेड ने कुछ इनोड भी बनाए)।

मैंने कर्नेल 2.6.39 की परिभाषा कीsocketpair जाँच की , और सॉकेट के दो छोर टाइप-विशिष्ट socketpairविधि को छोड़कर सहसंबद्ध नहीं हैं । यूनिक्स सॉकेट्स के लिए, यह unix_socketpairअंदर हैnet/unix/af_unix.c


2
धन्यवाद @ गिल्स मुझे याद है कि कुछ समय पहले के बारे में कुछ पढ़ रहा था, लेकिन इसे फिर से नहीं पाया। मुझे बस / proc / net / unix के लिए एक पैच लिखना पड़ सकता है।
जोनाथन रेनहार्ट

और हाँ, मैंने बढ़ते हुए इनोड नंबरों के साथ उस अवलोकन को बनाया है, और वर्तमान में मैं इसके साथ काम कर रहा हूं। हालांकि, जैसा कि आपने उल्लेख किया है, इसकी गारंटी नहीं है। मैं जिस प्रक्रिया को देख रहा हूं उसमें कम से कम 40 खुले यूनिक्स सॉकेट हैं, और मैंने एक उदाहरण देखा जहां एन + 1 सच नहीं था। ओह।
जोनाथन रेनहार्ट

1
@JonathonReinhart मैंने की परिभाषा कीsocketpair जाँच की , और सॉकेट के दो छोरों को टाइप-विशिष्ट socketpairविधि के अलावा सहसंबद्ध नहीं किया गया है । यूनिक्स सॉकेट के लिए, यह unix_socketpair`नेट / यूनिक्स / af_unix.c में है । पाइपों के लिए भी यह जानकारी होना अच्छा होगा।
गिलेस एसओ- बुराई को रोकना '

36

नोट : मैं अब एक 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विकल्प आपको बता सकता है कि किस प्रक्रिया (तों) में वह सॉकेट खुला है। यह ऐसा कुछ readlinks पर करता है /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_restrictsysctl पैरामीटर) के रूप में पहले से ही @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);

1
@ mikeserv, कि टिप्पणी पर एक अनुवर्ती है । यूनिक्स सॉकेट्स के दूसरे छोर को खोजने में सक्षम नहीं होना एक ऐसी चीज है जिसने मुझे हमेशा परेशान किया है (अक्सर जब एक्स क्लाइंट खोजने की कोशिश की जाती है और उस बारे में हाल ही में सवाल था )। मैं कोशिश करता हूं और देखता हूं कि क्या छद्म टर्मिनलों के लिए एक समान दृष्टिकोण का उपयोग किया जा सकता है और lsofलेखक को सुझाव दे सकते हैं ।
स्टीफन चेजलस

1
मैं अभी भी विश्वास नहीं कर सकता यह कर्नेल द्वारा प्रदान नहीं किया गया है! मुझे वास्तव में एक पैच जमा करना चाहिए, अगर कुछ और के लिए नहीं बल्कि यह पता लगाने के लिए कि यह पहले से मौजूद क्यों नहीं है।
जोनाथन रेनहार्ट

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, ऐसा लगता है कि यह वास्तव में करता है! ऐसा लगता है कि मैं हाल ही में बहुत समय बर्बाद कर रहा हूं ...
स्टीफन चेजालस

9

Erkki Seppala में वास्तव में एक उपकरण है जो लिनक्स कर्नेल से gdb के साथ इस जानकारी को पुनर्प्राप्त करता है .. यह यहां उपलब्ध है


2
बहुत उपयोगी जानकारी! यहां तक ​​कि अगर उपकरण मेरे लिए बॉक्स से बाहर काम नहीं करता था (यह कर्नेल ऊप्स का कारण बनता है), तो विचार ने मुझे दूसरे छोर की पहचान करने में मदद की। मैंने स्टैक ओवरफ्लो पर अपने समाधान का वर्णन किया
MvG

8

कर्नेल के बाद से 3.3

आप कर सकते हैं अब के साथ इस जानकारी को प्राप्त ss:

# ss -xp

अब आप Peerकॉलम में एक आईडी (इनोड नंबर) देख सकते हैं, जो कॉलम में किसी अन्य आईडी से मेल खाती है Local। मैचिंग आईडी एक सॉकेट के दो छोर हैं।

नोट: 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 स्थापित है। हेक्सा संख्या संबंधित कर्नेल 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

यहां आप जाते हैं, सॉकेट के दूसरे छोर को mysqlपीआईडी ​​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 / * से इनकोड संख्याओं के आधार पर / proc / net / unix में संबंधित प्रविष्टियों की पहचान करें, और एक सॉकेट के पते के आसपास मेमोरी स्कैन करें दूसरे का पता। यह एक यथोचित पोर्टेबल (लिनक्स लिनक्स संस्करण और आर्किटेक्चर) के लिए बना सकता है जिसे lsof द्वारा ही कार्यान्वित किया जा सकता है। मैं एक PoC के साथ आने की कोशिश करूँगा।
स्टीफन चेज़लस

2
मैंने अब एक ऐसा PoC जोड़ा है जो मेरे द्वारा परीक्षण किए गए सिस्टम पर अच्छा काम करता है।
स्टीफन चेजलस

5

यह समाधान, हालांकि काम कर रहा है, सीमित रुचि का है क्योंकि यदि आपके पास हाल ही में पर्याप्त सिस्टमटैप है, तो संभावना है कि आपके पास हाल ही में पर्याप्त कर्नेल होगा जहां आप ssआधारित दृष्टिकोण का उपयोग कर सकते हैं , और यदि आप एक पुराने कर्नेल पर हैं, तो अन्य समाधान , हालांकि अधिक हैकी काम करने की अधिक संभावना है और इसके लिए अतिरिक्त सॉफ़्टवेयर की आवश्यकता नहीं है।

systemtapइस तरह के कार्य के लिए उपयोग करने के प्रदर्शन के रूप में अभी भी उपयोगी है ।

यदि हाल ही में काम कर रहे सिस्टमटैप (1.8 या नए) के साथ लिनक्स सिस्टम पर, आप निम्न स्क्रिप्ट का उपयोग कर सकते हैं lsof:

उदाहरण के लिए:

$ lsof -aUc एनएम-एप्लेट | सूद कि लिपि
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]

(यदि आपको 0xffff के बजाय 0x0000000000000000 ऊपर दिखाई देता है ..., यह इसलिए है क्योंकि kernel.kptr_restrictsysctl पैरामीटर आपके सिस्टम पर सेट है, जो कर्नेल पॉइंटर्स को गैर-विशेषाधिकार प्राप्त प्रक्रियाओं से छिपा देता है, जिस स्थिति में आपको 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, @varsystemtap 1.8, 2012-06-17 में जोड़ा गया था (नवीनतम 2.7 है)
स्टीफन चेज़लस

2

4.89 के lsof एंडपॉइंट विकल्पों को प्रदर्शित करने का समर्थन करता है।

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

चूंकि लिनक्स कर्नेल 4.2 मौजूद है CONFIG_UNIX_DIAG, जो UNIX डोमेन सॉकेट के बारे में अतिरिक्त जानकारी प्रदान करता है, अर्थात Virtual File System(VFS) जानकारी, जिसमें इनोड को पथ से प्रक्रिया में लिंक करने के लिए अब तक लापता जानकारी है। यह पहले ssसे ही संस्करण v4.19.0 ~ 55 के साथ शुरू होने वाले 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"

या आदमी 7 sock_diag में शामिल टेम्प्लेट के आधार पर अपना खुद का लिट्टी प्रोग्राम लिखें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.