Bagaimana cara menangkap secara pasif dari soket domain Unix (pemantauan soket AF_UNIX)?

13

Pengambilan TCP / IP dan UDP dapat dilakukan menggunakan tcpdump/ dumpcapdan menghasilkan file pcap / pcapng yang dapat diumpankan ke Wireshark untuk analisis lebih lanjut. Apakah ada alat serupa untuk soket domain bernama Unix? (Solusi umum yang berfungsi untuk soket abstrak akan lebih baik juga.)

straceapa adanya tidak cukup, tidak mudah untuk menyaring I / O soket domain Unix. Sebuah proxy menggunakan socatatau sama juga tidak cocok sebagai tujuannya adalah analisis pasif untuk program terbuka yang ada.

Bagaimana saya bisa mendapatkan tangkapan paket yang bisa saya gunakan di Wireshark untuk analisis? Contoh aplikasi protokol adalah X11 (Xorg, aplikasi saya saat ini) dan cURL / PHP (HTTP). Saya telah melihat CONFIG_UNIX_DIAGopsi di kernel Linux, apakah ini ada gunanya?

Lekensteyn
sumber
1
Lihat Menangkap lalu lintas protokol X11
Stéphane Chazelas
@ StéphaneChazelas Terima kasih, tetapi sejak Xorg dimulai -nolisten tcp, tidak ada soket TCP. Jika semua gagal, maka saya mungkin akan kembali menggunakan xscope atau trik strace + text2pcap Anda yang rapi. Saya masih akan tertarik pada penangkapan soket Unix generik (hanya data, bukan data saluran samping).
Lekensteyn
Selain strace, Anda juga dapat melihat auditd dan systemtap.
Stéphane Chazelas
systemtap hampir terlihat seperti hack GDB, tetapi kemudian pada level kernel. Tidak tahu tentang audit, saya hanya menemukan kait LSM yang memeriksa apakah Anda diizinkan untuk membaca / menulis. (Saat ini saya sedang menggali kode sumber kernel Linux)
Lekensteyn

Jawaban:

12

Pada Linux kernel v4.2-rc5 tidak mungkin untuk menangkap secara langsung menggunakan antarmuka yang digunakan oleh libpcap. libpcap menggunakan domain khusus Linux AF_PACKET(alias PF_PACKET) yang hanya memungkinkan Anda untuk mengambil data untuk data yang melalui " netdevice " (seperti antarmuka Ethernet).

Tidak ada antarmuka kernel untuk mengambil dari AF_UNIXsoket. Tangkapan Ethernet standar memiliki tajuk Ethernet dengan sumber / tujuan, dll. Soket Unix tidak memiliki tajuk palsu dan registri jenis taut-lapis tidak mencantumkan apa pun yang terkait dengan ini.

Titik masuk dasar untuk data adalah unix_stream_recvmsgdan unix_stream_sendmsguntuk SOCK_STREAM( SOCK_DGRAMdan SOCK_SEQPACKETmemiliki fungsi yang bernama sama). Data buffered sk->sk_receive_queuedan dalam unix_stream_sendmsgfungsi tersebut , tidak ada kode yang pada akhirnya mengarah ke memanggil tpacket_rcvfungsi untuk menangkap paket. Lihat analisis ini oleh osgx pada SO untuk detail lebih lanjut tentang internal capture paket secara umum.

Kembali ke pertanyaan awal tentang AF_UNIXpemantauan soket, jika Anda terutama tertarik pada data aplikasi, Anda memiliki beberapa opsi:

  • Pasif (juga berfungsi untuk proses yang sudah berjalan):
    • Gunakan stracedan tangkap kemungkinan panggilan sistem yang menjalankan I / O. Ada banyak dari mereka, read, pread64, readv, preadv, recvmsgdan masih banyak lagi ... See @ Stéphane Chazelas contoh bagi xterm. Kerugian dari pendekatan ini adalah bahwa Anda pertama-tama harus menemukan deskriptor file Anda dan kemudian masih mungkin kehilangan panggilan sistem. Dengan strace Anda dapat menggunakan -e trace=filesebagian besar dari mereka ( preadhanya ditutupi oleh -e trace=desc, tetapi mungkin tidak digunakan untuk soket Unix oleh sebagian besar program).
    • Hancurkan / modifikasi unix_stream_recvmsg, unix_stream_sendmsg(atau unix_dgram_*atau unix_seqpacket_*) di kernel dan output data, di suatu tempat. Anda dapat menggunakan SystemTap untuk mengatur titik jejak tersebut, berikut adalah contoh untuk memantau pesan keluar. Membutuhkan dukungan kernel dan ketersediaan simbol debugging .
  • Aktif (hanya berfungsi untuk proses baru):

    • Gunakan proxy yang juga menulis file. Anda dapat menulis multiplexer cepat sendiri atau meretas sesuatu seperti ini yang juga menghasilkan pcap (waspadalah terhadap keterbatasan, misalnya AF_UNIXdapat melewati deskriptor file, AF_INETtidak dapat):

      # 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
      
    • Gunakan proksi aplikasi khusus. Untuk X11, ada xscope ( git , manual ).

CONFIG_UNIX_DIAGOpsi yang disarankan sayangnya juga tidak membantu di sini, hanya dapat digunakan untuk mengumpulkan statistik, tidak memperoleh data waktu nyata saat mereka mengalir (lihat linux / unix_diag.h ).

Sayangnya tidak ada pelacak yang sempurna saat ini untuk soket domain Unix yang menghasilkan pcaps (setahu saya). Idealnya akan ada format libpcap yang memiliki header yang berisi PID sumber / dest (bila tersedia) diikuti oleh data tambahan opsional (kredensial, deskriptor file) dan akhirnya data. Karena itu, yang terbaik yang bisa dilakukan adalah penelusuran syscall.


Informasi tambahan (untuk pembaca yang tertarik), berikut adalah beberapa backtraces (diperoleh dengan GDB break on unix_stream_*dan rbreak packet.c:., Linux di QEMU dan socat pada mainline Linux 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
Lekensteyn
sumber
Ngomong-ngomong, jika Anda telah membaca kristrev.github.io/2013/07/26/… dan melihat instruksi untuk melihat notifikasi tautan melalui netlink dan bertanya-tanya apakah diagnostik dapat menyediakan paket sniffing, jawabannya masih belum . Diagnostik ini menyediakan statistik melalui polling, bukan waktu nyata.
Lekensteyn
9

Saya menulis alat untuk menangkap dan membuang lalu lintas soket domain unix. Ini digunakan bpf/kprobeuntuk menyelidiki fungsi kernel unix_stream_sendmsgdan membuang lalu lintas ke ruang pengguna.

Alat ini tergantung pada bcc, jadi Anda harus menginstal bccterlebih dahulu.

Contoh dijalankan:

$ 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
...
mechpen
sumber