Wie erfasst man passiv von Unix-Domain-Sockets (AF_UNIX-Socket-Überwachung)?

13

TCP / IP- und UDP-Captures können mit tcpdump/ erstellt dumpcapund eine pcap / pcapng-Datei erstellt werden, die zur weiteren Analyse an Wireshark gesendet werden kann. Gibt es ein ähnliches Tool für benannte Unix-Domain-Sockets? (Eine allgemeine Lösung, die für abstrakte Sockets funktioniert, wäre aber auch nett.)

straceIst dies nicht ausreichend, ist es nicht einfach, nach Unix-Domain-Sockets-E / A zu filtern. Ein Proxy unter Verwendung socatoder ähnlichem ist ebenfalls nicht geeignet, da das Ziel eine passive Analyse für vorhandene offene Programme ist.

Wie kann ich eine Paketerfassung erhalten, die ich in Wireshark zur Analyse verwenden kann? Beispielprotokollanwendungen sind X11 (Xorg, meine aktuelle Anwendung) und cURL / PHP (HTTP). Ich habe eine CONFIG_UNIX_DIAGOption im Linux-Kernel gesehen. Ist dies von Nutzen?

Lekensteyn
quelle
1
Siehe Erfassen des Datenverkehrs des X11-Protokolls
Stéphane Chazelas,
@ StéphaneChazelas Danke, aber da Xorg mit gestartet wurde -nolisten tcp, gibt es keinen TCP-Socket. Wenn alles fehlschlägt, werde ich wahrscheinlich wieder auf xscope oder Ihren ordentlichen Trick mit strace + text2pcap zurückgreifen. Ich würde mich trotzdem für ein generisches Unix-Socket-Capture interessieren (nur für Daten, nicht für Seitenkanaldaten).
Lekensteyn
Neben strace können Sie auch auditd und systemtap betrachten.
Stéphane Chazelas
systemtap sieht fast aus wie ein GDB-Hack, aber dann auf Kernel-Ebene. Keine Ahnung von Audit. Ich habe nur einen LSM-Hook gefunden, der überprüft hat, ob Sie lesen / schreiben dürfen. (Ich grabe gerade im Linux-Kernel-Quellcode)
Lekensteyn

Antworten:

12

Ab Linux-Kernel v4.2-rc5 ist es nicht möglich, direkt über die von libpcap verwendeten Schnittstellen zu erfassen. libpcap verwendet die Linux-spezifische AF_PACKET(Alias- PF_PACKET) Domäne, mit der Sie nur Daten für Daten erfassen können, die über ein " Netzgerät " (z. B. Ethernet-Schnittstellen) übertragen werden.

Es gibt keine Kernel-Schnittstelle zum Aufzeichnen von AF_UNIXSockets. Standard-Ethernet-Captures haben einen Ethernet-Header mit Quelle / Ziel usw. Unix-Sockets haben keinen solchen gefälschten Header, und in der Registrierung für Link-Layer-Headertypen sind keine diesbezüglichen Informationen aufgeführt.

Die grundlegenden Einstiegspunkte für Daten sind unix_stream_recvmsgund unix_stream_sendmsgfür SOCK_STREAM( SOCK_DGRAMund SOCK_SEQPACKEThaben ähnlich benannte Funktionen). Daten werden in sk->sk_receive_queueund in der unix_stream_sendmsgFunktion zwischengespeichert , es gibt keinen Code, der letztendlich zum Aufrufen der tpacket_rcvFunktion für Paketerfassungen führt. In dieser Analyse von osgx zu SO finden Sie weitere Informationen zu den Interna der Paketerfassung im Allgemeinen.

Zurück zur ursprünglichen Frage zur AF_UNIXSocket-Überwachung: Wenn Sie hauptsächlich an Anwendungsdaten interessiert sind, haben Sie einige Möglichkeiten:

  • Passiv (funktioniert auch bei bereits laufenden Prozessen):
    • Verwenden straceund erfassen Sie mögliche Systemaufrufe, die E / A-Vorgänge ausführen. Es gibt viele von ihnen, read, pread64, readv, preadv, recvmsgund vieles mehr ... Siehe @ Stéphane Chazelas Beispiel für xterm. Nachteil dieses Ansatzes ist, dass Sie zuerst Ihren Dateideskriptor finden müssen und dann möglicherweise immer noch Systemaufrufe verpassen. Mit strace können Sie -e trace=filefür die meisten von ihnen ( preadwird nur von -e trace=desc, aber wahrscheinlich nicht von den meisten Programmen für Unix-Sockets verwendet).
    • Break on / ändern unix_stream_recvmsg, unix_stream_sendmsg(oder unix_dgram_*oder unix_seqpacket_*) im Kernel und gibt die Daten, irgendwo. Sie können SystemTap zum Festlegen solcher Tracepunkte verwenden. Hier ist ein Beispiel zum Überwachen von ausgehenden Nachrichten. Erfordert Kernel-Unterstützung und Verfügbarkeit von Debugging-Symbolen .
  • Aktiv (funktioniert nur bei neuen Prozessen):

    • Verwenden Sie einen Proxy, der auch Dateien schreibt. Sie könnten selbst einen schnellen Multiplexer schreiben oder so etwas hacken, das auch einen pcap ausgibt (achten Sie auf die Einschränkungen, z. B. AF_UNIXkönnen Sie Dateideskriptoren übergeben, AF_INETkönnen Sie nicht):

      # 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
      
    • Verwenden Sie einen dedizierten Anwendungs-Proxy. Für X11 gibt es xscope ( git , manual ).

Die vorgeschlagene CONFIG_UNIX_DIAGOption ist hier leider auch nicht hilfreich, sie kann nur zum Sammeln von Statistiken und nicht zum Erfassen von Echtzeitdaten im Fluss verwendet werden (siehe linux / unix_diag.h ).

Leider gibt es im Moment keine perfekten Tracer für Unix-Domain-Sockets, die nach meinem besten Wissen pcaps produzieren. Im Idealfall gibt es ein libpcap-Format mit einem Header, der die Quell- / Ziel-PID (sofern verfügbar), gefolgt von optionalen zusätzlichen Daten (Anmeldeinformationen, Dateideskriptoren) und schließlich die Daten enthält. Ist dies nicht der Fall, ist das beste, was getan werden kann, das Syscall-Tracing.


Zusätzliche Informationen (für den interessierten Leser), hier einige Backtraces (erworben mit GDB unix_stream_*und rbreak packet.c:.Linux in QEMU und socat on 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
quelle
Übrigens, wenn Sie kristrev.github.io/2013/07/26/… gelesen und Anweisungen zum Überprüfen von Verbindungsbenachrichtigungen über Netlink gesehen haben und sich gefragt haben, ob die Diagnose Paket-Sniffing ermöglichen kann, lautet die Antwort immer noch Nein . Diese Diagnosen liefern Statistiken nicht in Echtzeit, sondern über Abfragen.
Lekensteyn
9

Ich habe ein Tool geschrieben , um Unix-Domain-Socket-Verkehr zu erfassen und zu sichern. Es wird verwendet bpf/kprobe, um die Kernelfunktion zu testen unix_stream_sendmsgund den Datenverkehr in den Benutzerbereich zu verschieben.

Das Tool ist abhängig von bcc, daher müssen Sie es bcczuerst installieren .

Ein Beispiellauf:

$ 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
quelle