Not : Şimdi lsof
burada açıklanan her iki yaklaşımı birleştiren ve aynı zamanda https://github.com/stephane-chazelas/misc-scripts/blob/master/lsofc
Linux-3.3 ve üzeri.
Linux'ta, çekirdek sürüm 3.3'ten (ve UNIX_DIAG
özellik çekirdeğe yerleştirildiği sürece ), belirli bir unix alan soketinin eşi (soket çiftlerini içerir) yeni bir netlink tabanlı API kullanarak elde edilebilir .
lsof
4.89 sürümünden beri bu API’yı kullanabilir:
lsof +E -aUc Xorg
Adı Xorg
iki başından başlayan bir işlem olan tüm Unix alan soketlerine benzer bir formatta listelenir :
Xorg 2777 root 56u unix 0xffff8802419a7c00 0t0 34036 @/tmp/.X11-unix/X0 type=STREAM ->INO=33273 4120,xterm,3u
Sürümünüz lsof
çok eskiyse, birkaç seçenek daha vardır.
Yardımcı ss
program (from iproute2
), eş bilgiler de dahil olmak üzere sistemdeki unix alan soketleri listesinde bilgi almak ve görüntülemek için aynı API'yi kullanır.
Soketler inode numaralarıyla tanımlanır . Bunun soket dosyasının dosya sistemi inode ile ilgili olmadığını unutmayın.
Örneğin:
$ ss -x
[...]
u_str ESTAB 0 0 @/tmp/.X11-unix/X0 3435997 * 3435996
3435997 soketinin (ÖZET soketine /tmp/.X11-unix/X0
bağlı) 3435996 soketine bağlı olduğunu söylüyor. -p
Seçenek, hangi işlemlerin bu soketin açık olduğunu size söyleyebilir. Bunu, bazılarını readlink
açık yaparak yapar /proc/$pid/fd/*
, böylece yalnızca sahip olduğunuz işlemlerde (siz olmadıkça root
) yapabilir. Mesela burada:
$ 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]
Hangi işlem (ler) in 3435996 olduğunu bulmak için, aşağıdaki adreste kendi girdisine bakabilirsiniz ss -xp
:
$ ss -xp | awk '$6 == 3435996'
u_str ESTAB 0 0 * 3435996 * 3435997 users:(("xterm",pid=29215,fd=3))
Bu komut dosyasını lsof
, ilgili bilgileri burada kolayca göstermek için etrafındaki bir sarmalayıcı olarak da kullanabilirsiniz :
#! /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);
Örneğin:
$ sudo that-lsof-sarıcı -ad3 -p 29215
COMMAND PID KULLANICI FD TİP CİHAZ CİHAZ BOYUTU / KAPALI NODE ADI
xterm 29215 stephane 3u unix 0xffff8800a07da4c0 0t0 3435996 türü = STREAM <-> 3435997 [Xorg, 3080, @ / tmp / .X11-unix / X0]
Linux-3.3'ten önce
Unix soket bilgisini alan eski Linux API'si /proc/net/unix
metin dosyasıdır. Tüm Unix alan soketlerini listeler (soket çiftleri dahil). Buradaki ilk alan ( kernel.kptr_restrict
sysctl parametresiyle süper olmayan kullanıcılara gizlenmemişse ) @Totor tarafından açıklandığı gibi , ilgili eşe işaret eden unix_sock
bir peer
alanı içeren bir yapının çekirdek adresini içerir . Aynı zamanda bir Unix soketindeki sütun için çıktılar . unix_sock
lsof
DEVICE
Şimdi o peer
alanın değerini almak, çekirdek belleğini okuyabilmek ve o peer
alanın unix_sock
adrese göre ofsetini bilmek anlamına gelir .
Çeşitli gdb
tabanlı ve systemtap
merkezli çözümler zaten verilmiş ancak gerektirir gdb
/ systemtap
ve çekirdek için Linux çekirdeği ayıklama sembolleri üretim sistemlerinde durum genellikle olmadığı yüklenen.
Ofsetin kodlanması gerçekten, çekirdek sürümüne göre değişen bir seçenek değildir.
Şimdi ofsetin belirlenmesinde sezgisel bir yaklaşım kullanabiliriz: aracımızın bir kukla oluşturmasını sağlayın socketpair
(daha sonra her iki eşin adresini de biliyoruz) ve ofseti belirlemek için diğer uçtaki eşin adresini aranır.
İşte sadece bunu kullanan bir kavram kanıtı betiği perl
(i386 ve 3.13 ve 3.16 amd64'te çekirdek 2.4.27 ve 2.6.32 ile başarıyla test edilmiştir). Yukarıdaki gibi, etrafında bir sarmalayıcı olarak çalışır lsof
:
Örneğin:
$ that-lsof-sarıcı -AUc nm-applet
COMMAND PID KULLANICI FD TİP CİHAZ CİHAZ BOYUTU / KAPALI NODE ADI
mil-uygulama 4183 stephane 4u unix 0xffff8800a055eb40 0T0 36.888 türü = STREAM -> 0xffff8800a055e7c0 [dbus-cini 4190, @ / tmp / dbus-AiBCXOnuP6]
nm uygulama 4183 stephane 7U unix 0xffff8800a055e440 0T0 36890 türü = STREAM -> 0xffff8800a055e0c0 [Xorg, 3080, @ / tmp / .X11-unix / X0]
nm uygulama 4183 stephane 8U unix 0xffff8800a05c1040 0T0 36201 türü = STREAM -> 0xffff8800a05c13c0 [dbus-cini 4118 @ / tmp / dbus-yxxNr1NkYC]
nm uygulama 4183 stephane 11u unix 0xffff8800a055d080 0T0 36.219 türü = STREAM -> 0xffff8800a055d400 [dbus-cini 4118 @ / tmp / dbus-yxxNr1NkYC]
nm uygulama 4183 unix 0xffff88022e0dfb80 0T0 36221 türü = STREAM 12U stephane -> 0xffff88022e0df800 [dbus-cini 2268 / var / çalıştırmak / dbus / system_bus_socket]
nm-applet 4183 stephane 13u unix 0xffff88022e0f80c0 0t0 37025 türü = STREAM -> 0xffff88022e29ec00 [dbus-daemon, 2268, / var / run / dbus / system_bus_socket]
İşte senaryo:
#! /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);