Jak pasywnie przechwytywać z gniazd domeny Unix (monitorowanie gniazd AF_UNIX)?


13

Przechwytywanie TCP / IP i UDP może być wykonane przy użyciu tcpdump/ dumpcapi tworzy plik pcap / pcapng, który można przekazać do Wireshark w celu dalszej analizy. Czy istnieje podobne narzędzie dla nazwanych gniazd domeny Unix? (Ogólne rozwiązanie, które działa dla gniazd abstrakcyjnych, również byłoby fajne.)

straceponieważ-nie jest wystarczające, filtrowanie gniazd we / wy domenowych systemu Unix nie jest proste. Serwer proxy używający socatlub podobny nie jest również odpowiedni, ponieważ celem jest pasywna analiza istniejących otwartych programów.

Jak mogę uzyskać przechwytywanie pakietów, którego mogę używać w Wireshark do analizy? Przykładowe aplikacje protokołu to X11 (Xorg, moja bieżąca aplikacja) i cURL / PHP (HTTP). Widziałem CONFIG_UNIX_DIAGopcję w jądrze Linuksa, czy to się przyda?



@ StéphaneChazelas Dzięki, ale odkąd Xorg został uruchomiony z -nolisten tcp, nie ma gniazda TCP. Jeśli wszystko się nie powiedzie, prawdopodobnie powrócę do korzystania z xscope lub twojej schludnej sztuczki + sztuczki text2pcap. Nadal byłbym zainteresowany ogólnym przechwytywaniem gniazd Unix (tylko dla danych, a nie danych z kanału bocznego).
Lekensteyn,

Oprócz strace możesz także spojrzeć na audyt i systemtap.
Stéphane Chazelas,

systemtap wygląda prawie jak hack GDB, ale potem na poziomie jądra. Nie wiem o audycie, znalazłem tylko hak LSM, który sprawdził, czy wolno ci czytać / pisać. (Aktualnie przeglądam kod źródłowy jądra Linux)
Lekensteyn,

Odpowiedzi:


12

Od jądra Linux v4.2-rc5 nie jest możliwe przechwytywanie bezpośrednio przy użyciu interfejsów używanych przez libpcap. libpcap wykorzystuje domenę specyficzną dla Linuksa AF_PACKET(alias PF_PACKET), która pozwala jedynie przechwytywać dane dla danych przechodzących przez „urządzenie sieciowe ” (takie jak interfejsy Ethernet).

Nie ma interfejsu jądra do przechwytywania z AF_UNIXgniazd. Standardowe przechwyty Ethernet mają nagłówek Ethernet ze źródłem / miejscem docelowym itp. Gniazda uniksowe nie mają takiego fałszywego nagłówka, a rejestr typów nagłówków w warstwie łącza nie zawiera niczego związanego z tym.

Podstawowymi punktami wejścia dla danych są unix_stream_recvmsgi unix_stream_sendmsgdla SOCK_STREAM( SOCK_DGRAMi SOCK_SEQPACKETmają podobnie nazwane funkcje). Dane są buforowane sk->sk_receive_queuei w unix_stream_sendmsgfunkcji nie ma kodu, który ostatecznie prowadziłby do wywołania tpacket_rcvfunkcji dla przechwytywania pakietów. Zobacz tę analizę osgx na SO, aby uzyskać więcej szczegółowych informacji na temat wewnętrznych funkcji przechwytywania pakietów w ogóle.

Wracając do pierwotnego pytania dotyczącego AF_UNIXmonitorowania gniazd, jeśli interesują Cię głównie dane aplikacji, masz kilka opcji:

  • Pasywny (działa również w przypadku już uruchomionych procesów):
    • Używaj stracei przechwytuj możliwe połączenia systemowe, które wykonują operacje we / wy. Istnieje wiele z nich read, pread64, readv, preadv, recvmsgi wiele więcej ... zobacz @ Stéphane Chazelas przykład xterm. Wadą tego podejścia jest to, że najpierw musisz znaleźć deskryptor pliku, a następnie nadal możesz przegapić wywołania systemowe. Z funkcją strace możesz korzystać -e trace=filew większości z nich ( preadjest objęty -e trace=desc, ale prawdopodobnie nie jest używany w gniazdach uniksowych przez większość programów).
    • Przerwa na / modyfikować unix_stream_recvmsg, unix_stream_sendmsg(lub unix_dgram_*lub unix_seqpacket_*) w jądrze i wysyłają dane, gdzieś. Możesz użyć SystemTap do ustawienia takich punktów śledzenia, oto przykład monitorowania wiadomości wychodzących. Wymaga obsługi jądra i dostępności symboli debugowania .
  • Aktywny (działa tylko w przypadku nowych procesów):

    • Użyj proxy, który również zapisuje pliki. Możesz sam napisać szybki multiplekser lub zhakować coś takiego, który również generuje plik pcap (uważaj na ograniczenia, na przykład AF_UNIXmoże przekazać deskryptory plików, AF_INETnie może):

      # fake TCP server connects to real Unix socket
      socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CONNECT:some.sock
      # start packet capture on said port
      tcpdump -i lo -f 'tcp port 6000'
      # clients connect to this Unix socket
      socat UNIX-LISTEN:fake.sock,fork TCP-CONNECT:127.0.0.1:6000
      
    • Użyj dedykowanego serwera proxy aplikacji. Dla X11 istnieje xscope ( git , manual ).

Sugerowana CONFIG_UNIX_DIAGopcja nie jest tu niestety pomocna, można jej użyć tylko do zbierania statystyk, a nie pobierania danych w czasie rzeczywistym (patrz linux / unix_diag.h ).

Niestety w tej chwili nie ma idealnych wskaźników dla gniazd domeny Unix, które produkują pcaps (o ile mi wiadomo). Idealnie byłby format libpcap, który ma nagłówek zawierający PID źródłowy / docelowy (jeśli jest dostępny), a następnie opcjonalne dodatkowe dane (poświadczenia, deskryptory plików) i wreszcie dane. Bez tego najlepszym, co można zrobić, jest śledzenie syscall.


Dodatkowe informacje (dla zainteresowanego czytelnika), oto kilka śladów wstecznych (nabytych z łamaniem GDB unix_stream_*i rbreak packet.c:.Linux w QEMU i socat na głównym Linuksie 4.2-rc5):

# echo foo | socat - UNIX-LISTEN:/foo &
# echo bar | socat - UNIX-CONNECT:/foo
unix_stream_sendmsg at net/unix/af_unix.c:1638
sock_sendmsg_nosec at net/socket.c:610
sock_sendmsg at net/socket.c:620
sock_write_iter at net/socket.c:819
new_sync_write at fs/read_write.c:478
__vfs_write at fs/read_write.c:491
vfs_write at fs/read_write.c:538
SYSC_write at fs/read_write.c:585
SyS_write at fs/read_write.c:577
entry_SYSCALL_64_fastpath at arch/x86/entry/entry_64.S:186

unix_stream_recvmsg at net/unix/af_unix.c:2210
sock_recvmsg_nosec at net/socket.c:712
sock_recvmsg at net/socket.c:720
sock_read_iter at net/socket.c:797
new_sync_read at fs/read_write.c:422
__vfs_read at fs/read_write.c:434
vfs_read at fs/read_write.c:454
SYSC_read at fs/read_write.c:569
SyS_read at fs/read_write.c:562

# tcpdump -i lo &
# echo foo | socat - TCP-LISTEN:1337 &
# echo bar | socat - TCP-CONNECT:127.0.0.1:1337
tpacket_rcv at net/packet/af_packet.c:1962
dev_queue_xmit_nit at net/core/dev.c:1862
xmit_one at net/core/dev.c:2679
dev_hard_start_xmit at net/core/dev.c:2699
__dev_queue_xmit at net/core/dev.c:3104
dev_queue_xmit_sk at net/core/dev.c:3138
dev_queue_xmit at netdevice.h:2190
neigh_hh_output at include/net/neighbour.h:467
dst_neigh_output at include/net/dst.h:401
ip_finish_output2 at net/ipv4/ip_output.c:210
ip_finish_output at net/ipv4/ip_output.c:284
ip_output at net/ipv4/ip_output.c:356
dst_output_sk at include/net/dst.h:440
ip_local_out_sk at net/ipv4/ip_output.c:119
ip_local_out at include/net/ip.h:119
ip_queue_xmit at net/ipv4/ip_output.c:454
tcp_transmit_skb at net/ipv4/tcp_output.c:1039
tcp_write_xmit at net/ipv4/tcp_output.c:2128
__tcp_push_pending_frames at net/ipv4/tcp_output.c:2303
tcp_push at net/ipv4/tcp.c:689
tcp_sendmsg at net/ipv4/tcp.c:1276
inet_sendmsg at net/ipv4/af_inet.c:733
sock_sendmsg_nosec at net/socket.c:610
sock_sendmsg at net/socket.c:620
sock_write_iter at net/socket.c:819
new_sync_write at fs/read_write.c:478
__vfs_write at fs/read_write.c:491
vfs_write at fs/read_write.c:538
SYSC_write at fs/read_write.c:585
SyS_write at fs/read_write.c:577
entry_SYSCALL_64_fastpath at arch/x86/entry/entry_64.S:186

tpacket_rcv at net/packet/af_packet.c:1962
dev_queue_xmit_nit at net/core/dev.c:1862
xmit_one at net/core/dev.c:2679
dev_hard_start_xmit at net/core/dev.c:2699
__dev_queue_xmit at net/core/dev.c:3104
dev_queue_xmit_sk at net/core/dev.c:3138
dev_queue_xmit at netdevice.h:2190
neigh_hh_output at include/net/neighbour.h:467
dst_neigh_output at include/net/dst.h:401
ip_finish_output2 at net/ipv4/ip_output.c:210
ip_finish_output at net/ipv4/ip_output.c:284
ip_output at net/ipv4/ip_output.c:356
dst_output_sk at include/net/dst.h:440
ip_local_out_sk at net/ipv4/ip_output.c:119
ip_local_out at include/net/ip.h:119
ip_queue_xmit at net/ipv4/ip_output.c:454
tcp_transmit_skb at net/ipv4/tcp_output.c:1039
tcp_send_ack at net/ipv4/tcp_output.c:3375
__tcp_ack_snd_check at net/ipv4/tcp_input.c:4901
tcp_ack_snd_check at net/ipv4/tcp_input.c:4914
tcp_rcv_state_process at net/ipv4/tcp_input.c:5937
tcp_v4_do_rcv at net/ipv4/tcp_ipv4.c:1423
tcp_v4_rcv at net/ipv4/tcp_ipv4.c:1633
ip_local_deliver_finish at net/ipv4/ip_input.c:216
ip_local_deliver at net/ipv4/ip_input.c:256
dst_input at include/net/dst.h:450
ip_rcv_finish at net/ipv4/ip_input.c:367
ip_rcv at net/ipv4/ip_input.c:455
__netif_receive_skb_core at net/core/dev.c:3892
__netif_receive_skb at net/core/dev.c:3927
process_backlog at net/core/dev.c:4504
napi_poll at net/core/dev.c:4743
net_rx_action at net/core/dev.c:4808
__do_softirq at kernel/softirq.c:273
do_softirq_own_stack at arch/x86/entry/entry_64.S:970

Nawiasem mówiąc, jeśli przeczytałeś kristrev.github.io/2013/07/26/... i zobaczył instrukcje do oglądania za linkiem powiadomień poprzez netlink i zastanawiał się, czy diagnostyki może dostarczyć pakiet wąchania, odpowiedź jest wciąż brak . Ta diagnostyka zapewnia statystyki poprzez odpytywanie, a nie w czasie rzeczywistym.
Lekensteyn,

9

Napisałem narzędzie do przechwytywania i zrzucania ruchu na gniazdach domeny unix. Służy bpf/kprobedo sondowania funkcji jądra unix_stream_sendmsgi zrzucania ruchu do przestrzeni użytkownika.

Narzędzie zależy od bcc, więc musisz bccnajpierw zainstalować .

Przykładowy przebieg:

$ sudo ./sockdump.py /var/run/docker.sock # run "docker ps" in another terminal
>>> docker[3412] len 83
GET /_ping HTTP/1.1
Host: docker
User-Agent: Docker-Client/18.06.1-ce (linux)

>>> dockerd[370] len 215
HTTP/1.1 200 OK
Api-Version: 1.38
Docker-Experimental: false
Ostype: linux
Server: Docker/18.06.1-ce (linux)
Date: Tue, 25 Sep 2018 07:05:03 GMT
Content-Length: 2
Content-Type: text/plain; charset=utf-8

OK
...
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.