Chcę ustalić, który proces ma drugi koniec gniazda UNIX.
W szczególności pytam o jeden, który został stworzony socketpair()
, chociaż problem jest taki sam dla każdego gniazda UNIX.
Mam program, parent
który tworzy socketpair(AF_UNIX, SOCK_STREAM, 0, fds)
i fork()
. Proces nadrzędny zamyka się fds[1]
i kontynuuje fds[0]
komunikację. Dziecko robi coś przeciwnego, close(fds[0]); s=fds[1]
. Wtedy dziecko exec()
s inny program child1
. Obie mogą komunikować się tam iz powrotem za pośrednictwem tej pary gniazd.
Powiedzmy, że wiem, kto parent
jest, ale chcę dowiedzieć się, kto child1
jest. Jak mam to zrobic?
Do dyspozycji mam kilka narzędzi, ale żadne nie może mi powiedzieć, który proces jest na drugim końcu gniazda. Próbowałem:
lsof -c progname
lsof -c parent -c child1
ls -l /proc/$(pidof server)/fd
cat /proc/net/unix
Zasadniczo widzę dwa gniazda i wszystko na ich temat, ale nie mogę powiedzieć, że są ze sobą połączone. Próbuję ustalić, która FD u rodzica komunikuje się z którym procesem potomnym.
źródło
socketpair
, a dwa końce gniazda nie są skorelowane inaczej niż za pomocąsocketpair
metody specyficznej dla typu . Dla gniazd unixowych znajduje sięunix_socketpair
w `net / unix / af_unix.c . Byłoby miło mieć tę informację również dla rur.Linux-3.3 i nowsze wersje.
W systemie Linux, ponieważ jądro w wersji 3.3 (i pod warunkiem, że
UNIX_DIAG
funkcja jest wbudowana w jądro), element równorzędny danego gniazda domeny unix (obejmuje pary gniazd) można uzyskać za pomocą nowego interfejsu API opartego na netlink .lsof
ponieważ wersja 4.89 może korzystać z tego interfejsu API:Wyświetli listę wszystkich gniazd domeny Unix, które mają proces, którego nazwa zaczyna się
Xorg
na dowolnym końcu, w formacie podobnym do:Jeśli Twoja wersja
lsof
jest za stara, istnieje kilka innych opcji.ss
Gospodarczy (ziproute2
) sprawia, że korzystanie z tego samego API do pobierania i wyświetlania informacji na liście gniazd domeny UNIX w systemie, w tym informacji o partnerze.Gniazda są identyfikowane przez ich numer i-węzła . Zauważ, że nie jest to związane z i-węzłem systemu plików pliku gniazda.
Na przykład w:
mówi, że gniazdo 3435997 (które było powiązane z gniazdem ABSTRACT
/tmp/.X11-unix/X0
) jest połączone z gniazdem 3435996. Ta-p
opcja pozwala określić, które procesy mają otwarte to gniazdo. Robi to, wykonując kilkareadlink
s/proc/$pid/fd/*
, więc może to zrobić tylko w procesach, które posiadasz (chyba że jesteśroot
). Na przykład tutaj:Aby dowiedzieć się, jaki proces (y) ma 3435996, możesz poszukać własnego wpisu w wynikach
ss -xp
:Możesz również użyć tego skryptu jako opakowania,
lsof
aby łatwo pokazać odpowiednie informacje:Na przykład:
Przed linux-3.3
Stary Linux API do pobierania informacji o gniazdach unixowych jest za pośrednictwem
/proc/net/unix
pliku tekstowego. Zawiera listę wszystkich gniazd domeny uniksowej (w tym par gniazd). Pierwsze pole tam (jeśli nie jest ukryte dla nieurządzających zkernel.kptr_restrict
parametrem sysctl), jak już wyjaśniono przez @Totor, zawiera adres jądraunix_sock
struktury zawierającejpeer
pole wskazujące odpowiedni element równorzędnyunix_sock
. To także danelsof
wyjściowe dlaDEVICE
kolumny w gnieździe Uniksa.Teraz uzyskanie wartości tego
peer
pola oznacza możliwość odczytu pamięci jądra i znania przesunięcia tegopeer
pola względemunix_sock
adresu.Podano już kilka rozwiązań
gdb
opartych na isystemtap
opartych na nich, ale wymagają onegdb
/systemtap
i symboli debugowania jądra Linuksa dla zainstalowanego jądra, co na ogół nie ma miejsca w systemach produkcyjnych.Przesunięcie na stałe przesunięcia nie jest tak naprawdę opcją, ponieważ różni się w zależności od wersji jądra.
Teraz możemy użyć heurystycznego podejścia do określania przesunięcia: pozwól naszemu narzędziu utworzyć manekina
socketpair
(wtedy znamy adres obu peerów) i wyszukaj adres peera wokół pamięci na drugim końcu, aby ustalić przesunięcie.Oto skrypt
perl
sprawdzający koncepcję, który właśnie to robi (pomyślnie przetestowany z jądrem 2.4.27 i 2.6.32 na i386 oraz 3.13 i 3.16 na amd64). Podobnie jak powyżej, działa jak opakowanielsof
:Na przykład:
Oto skrypt:
źródło
lsof
autorowi.ss
nie to zrobić? To coś w rodzaju mojej głowy, aless -px
wymienia wiele gniazd unixowych z równorzędnymi informacjami, takimi jak: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
a nagłówki kolumn są ...State\tRecv-Q\tSend-Q\tLocal Address:Port\tPeer Address:Port
lsof -c terminology
, zobaczę,terminolo 12731\tmikeserv\t12u\tunix\t0xffff880600e82680\t0t0\t1312426\ttype=STREAM
ale jeśli to zrobięss -px | grep terminology
, otrzymam:u_str\tESTAB\t0\t0\t* 1312426\t*1315046\tusers:(("terminology",pid=12731,fd=12))
Erkki Seppala posiada narzędzie, które pobiera te informacje z jądra Linuksa za pomocą gdb. Jest ono dostępne tutaj .
źródło
Od jądra 3.3
Państwo może teraz uzyskać te informacje
ss
:Teraz możesz zobaczyć w
Peer
kolumnie identyfikator (numer i-węzła), który odpowiada innemu identyfikatorowi wLocal
kolumnie. Identyfikatory pasujące to dwa końce gniazda.Uwaga:
UNIX_DIAG
Opcja musi być włączona w twoim jądrze.Przed jądrem 3.3
Linux nie ujawnił tych informacji użytkownikom.
Jednak patrząc na pamięć jądra , możemy uzyskać dostęp do tych informacji.
Uwaga: Ta odpowiedź jest dostępna przy użyciu
gdb
, jednak proszę zobaczyć odpowiedź @ StéphaneChazelas, która jest bardziej rozwinięta w tym zakresie.Istnieją 2 różne gniazda, 1 słuchanie i 1 ustanowione. Liczba szesnastkowa jest adresem odpowiedniej
unix_sock
struktury jądra , którejpeer
atrybut jest adresem drugiego końca gniazda (równieżunix_sock
instancji struktury).Teraz możemy użyć
gdb
do znalezieniapeer
wewnętrznej pamięci jądra:Proszę bardzo, drugi koniec gniazda trzyma
mysql
PID 14815.Twoje jądro musi zostać skompilowane,
KCORE_ELF
aby móc z niego korzystać/proc/kcore
. Potrzebujesz także wersji obrazu jądra z symbolami debugowania. Na Debianie 7apt-get install linux-image-3.2.0-4-amd64-dbg
udostępni ten plik.Nie ma potrzeby debugowania obrazu jądra ...
Jeśli nie masz (lub nie chcesz zachować) obrazu jądra debugowania w systemie, możesz
gdb
ustawić przesunięcie pamięci, aby „ręcznie” uzyskać dostęp dopeer
wartości. Ta wartość przesunięcia zwykle różni się w zależności od wersji lub architektury jądra.W moim jądrze wiem, że przesunięcie wynosi 680 bajtów, czyli 85 razy 64 bitów. Więc mogę zrobić:
Voilà, taki sam wynik jak powyżej.
Jeśli masz to samo jądro uruchomione na kilku komputerach, łatwiej jest użyć tego wariantu, ponieważ nie potrzebujesz obrazu debugowania, tylko wartość przesunięcia.
Aby (łatwo) odkryć tę wartość przesunięcia na początku, potrzebujesz obrazu debugowania:
Proszę, 680 bajtów, to 85 x 64 bitów lub 170 x 32 bitów.
Większość zasług za tę odpowiedź należy do MvG .
źródło
Jeśli na najnowszym systemie Linux z działającym paskiem systemowym (1.8 lub nowszym), możesz użyć poniższego skryptu, aby przetworzyć dane wyjściowe
lsof
:Na przykład:
(jeśli widzisz 0x0000000000000000 powyżej zamiast 0xffff ..., to dlatego, że
kernel.kptr_restrict
parametr sysctl jest ustawiony w twoim systemie, co powoduje, że wskaźniki jądra są ukryte przed procesami nieuprzywilejowanymi, w takim przypadku musisz uruchomićlsof
jako root, aby uzyskać znaczący wynik).Ten skrypt nie próbuje poradzić sobie z nazwami plików gniazd ze znakami nowej linii, ale nie robi tego
lsof
(nielsof
radzi sobie z pustymi znakami lub dwukropkami).systemtap
tutaj służy do zrzucenia adresu i adresu równorzędnego wszystkichunix_sock
struktur wunix_socket_table
haszu w jądrze.Testowane tylko w systemie Linux 3.16 amd64 z systemtap 2.6 i 3.13 z 2.3.
źródło
parse error: unknown statistic operator @var
: czy coś mi brakuje?@var
dodano w systemtap 1.8, 2012-06-17 (najnowszy jest 2.7)4.89 z lsof obsługuje wyświetlanie opcji punktów końcowych.
Cytat z lsof.8:
Przykład wyniku:
źródło
Od jądra Linuksa 4.2 istnieje
CONFIG_UNIX_DIAG
dodatkowe informacje o gniazdach domeny UNIX, a mianowicie informacjeVirtual File System
(VFS), które zawierają dotychczas brakujące informacje pozwalające połączyć i-węzeł ze ścieżką do procesu. Można go już zapytać za pomocąss
narzędzia z iproute2, począwszy od wersji v4.19.0 ~ 55 :Numer urządzenia i ścieżka i-węzła, które można uzyskać
ss
obsługuje również filtrowanie:ale pamiętaj, że może to nie zawierać odpowiedniego gniazda, ponieważ zły proces może zmienić nazwę oryginalnego gniazda i zastąpić go własnym złym:
lsof /tmp/socket
,fuser /tmp/socket
Iss --processes --unix --all --extended 'sport = /tmp/socket'
będzie wszystko notować oryginalny proces, a nie zło wymiany. Zamiast tego użyj czegoś takiego:Lub napisz własny program litte na podstawie szablonu zawartego w man 7 sock_diag .
źródło