দ্রষ্টব্য : আমি এখন এখানে একটি lsof
বর্ণনাকারী রক্ষণাবেক্ষণ করেছি যা এখানে বর্ণিত উভয় পদ্ধতির সমন্বয় করে এবং লুপব্যাক টিসিপি সংযোগের পিয়ার্সের জন্য https://github.com/stephane-chazelas/misc-scriptts/blob/master/lsofc এ যোগ করি
লিনাক্স -৩.৩ এবং তারপরে।
লিনাক্স-এ, কার্নেল সংস্করণ ৩.৩ (যে UNIX_DIAG
বৈশিষ্ট্যটি কার্নেলের মধ্যে নির্মিত হয়েছে), একটি নতুন ইউনিক্স ডোমেন সকেটের (সকেটপেইস অন্তর্ভুক্ত) পিয়ারটি একটি নতুন নেট লিঙ্ক ভিত্তিক এপিআই ব্যবহার করে প্রাপ্ত করা যেতে পারে ।
lsof
সংস্করণ ৪.৯৯ যেটি এপিআই ব্যবহার করতে পারে:
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 ব্যবহার করতে পুনরুদ্ধার করতে এবং পিয়ার তথ্য সহ সিস্টেমে UNIX ডোমেইন সকেট তালিকায় তথ্য প্রদর্শন করে তোলে।
সকেটগুলি তাদের ইনোড নম্বর দ্বারা চিহ্নিত করা হয় । মনে রাখবেন এটি সকেট ফাইলের ফাইল সিস্টেম ইনোডের সাথে সম্পর্কিত নয়।
উদাহরণস্বরূপ:
$ ss -x
[...]
u_str ESTAB 0 0 @/tmp/.X11-unix/X0 3435997 * 3435996
এটিতে বলা হয়েছে যে সকেট 3435997 (এটি আবস্ট্রাক্ট সকেটের সাথে আবদ্ধ ছিল /tmp/.X11-unix/X0
) সকেটের সাথে 3435996 সংযুক্ত রয়েছে option -p
বিকল্পটি আপনাকে বলতে পারে কোন সক্রিয়তার (এস) সেই সকেটটি খোলা আছে। এটি কিছুটা readlink
চালিয়ে যাওয়ার দ্বারা এটি করে /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);
উদাহরণ স্বরূপ:
$ sudo that-lsof-wrapper -ad3 -p 29215
কম্যান্ড পিআইডি ব্যবহারকারী এফডি টাইপ ডিভাইস সাইজ / কোনও নাম বাদ নেই
xterm 29215 স্টেফেন 3 ইউ ইউনিক্স 0xffff8800a07da4c0 0t0 3435996 টাইপ = স্ট্রিম <-> 3435997 [এক্সর্গ, 3080, @ / টিএমপি / .এক্স 11-ইউনিক্স / এক্স0]
লিনাক্স -৩.৩ এর আগে
ইউনিক্স সকেট তথ্য পুনরুদ্ধার করতে পুরানো লিনাক্স এপিআই /proc/net/unix
পাঠ্য ফাইলের মাধ্যমে । এটি সমস্ত ইউনিক্স ডোমেন সকেট (সকেটপেইস সহ) তালিকাভুক্ত করে। সেখানে প্রথম ক্ষেত্রটি (যদি সিসটেলkernel.kptr_restrict
প্যারামিটারের সাথে অ- সুপারিউসারদের কাছে গোপন না থাকে ) যেমনটি @ টোটার ইতিমধ্যে ব্যাখ্যা করেছেন তাতে একটি 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
:
উদাহরণ স্বরূপ:
$ যে-lsof-wrapper -aUc এনএম-অ্যাপলেট
কম্যান্ড পিআইডি ব্যবহারকারী এফডি টাইপ ডিভাইস সাইজ / কোনও নাম বাদ নেই
NM-অ্যাপলেট 4183 Stephane 4u UNIX 0xffff8800a055eb40 0t0 36888 টাইপ = STREAM -> 0xffff8800a055e7c0 [dbus,-ডেমন, 4190, @ / tmp / 'dbus,-AiBCXOnuP6]
NM-অ্যাপলেট 4183 Stephane 7u UNIX 0xffff8800a055e440 0t0 36890 টাইপ = STREAM -> 0xffff8800a055e0c0 [উপলব্ধকারী Xorg, 3080, @ / টিএমপি / .এক্স 11-ইউনিক্স / এক্স0]
এনএম-অ্যাপলেট 4183 স্টেফেন 8 ইউ ইউনিক্স 0xffff8800a05c1040 0t0 36201 টাইপ = স্ট্রিম -> 0xffff8800a05c13c0 [ডিবিএস-ডেমন, 4118, @ / টিএমপি / ডিবিএস-এএনএক্সএনসিআরএনএম 1
এনএন 1 UNIX 0xffff8800a055d080 0t0 36219 টাইপ = STREAM -> 0xffff8800a055d400 [dbus,-ডেমন, 4118, @ / tmp / 'dbus,-yxxNr1NkYC]
NM-অ্যাপলেট 4183 12u UNIX 0xffff88022e0dfb80 0t0 36221 টাইপ = STREAM Stephane -> 0xffff88022e0df800 [dbus,-ডেমন, 2268, / Var / চালানোর / dbus, / system_bus_socket]
এনএম-অ্যাপলেট 4183 স্টেফেন 13 ইউ ইউনিক্স 0xffff88022e0f80c0 0t0 37025 টাইপ = স্ট্রিম -> 0xffff88022e29ec00 [ডিবিস-ডেমন, 2268, / ভের / রান / ডিবিস / সিস্টেম_বাস_সকেট]
লিপিটি এখানে:
#! /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);