rtoax | 57a86aa | 2021-09-12 13:33:37 +0800 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | # @lint-avoid-python-3-compatibility-imports |
| 3 | # |
| 4 | # undump Dump UNIX socket packets. |
| 5 | # For Linux, uses BCC, eBPF. Embedded C. |
| 6 | # USAGE: undump [-h] [-t] [-p PID] |
| 7 | # |
| 8 | # This uses dynamic tracing of kernel functions, and will need to be updated |
| 9 | # to match kernel changes. |
| 10 | # |
| 11 | # Copyright (c) 2021 Rong Tao. |
| 12 | # Licensed under the GPL License, Version 2.0 |
| 13 | # |
| 14 | # 27-Aug-2021 Rong Tao Created this. |
rtoax | 4615a3f | 2021-09-17 18:38:24 +0800 | [diff] [blame] | 15 | # 17-Sep-2021 Rong Tao Simplify according to chenhengqi's suggestion |
| 16 | # https://github.com/iovisor/bcc/pull/3615 |
rtoax | 57a86aa | 2021-09-12 13:33:37 +0800 | [diff] [blame] | 17 | # |
| 18 | from __future__ import print_function |
| 19 | from bcc import BPF |
| 20 | from bcc.containers import filter_by_containers |
| 21 | from bcc.utils import printb |
| 22 | import argparse |
| 23 | from socket import inet_ntop, ntohs, AF_INET, AF_INET6 |
| 24 | from struct import pack |
| 25 | from time import sleep |
| 26 | from datetime import datetime |
| 27 | import sys |
| 28 | |
| 29 | # arguments |
| 30 | examples = """examples: |
| 31 | ./undump # trace/dump all UNIX packets |
rtoax | 57a86aa | 2021-09-12 13:33:37 +0800 | [diff] [blame] | 32 | ./undump -p 181 # only trace/dump PID 181 |
| 33 | """ |
| 34 | parser = argparse.ArgumentParser( |
| 35 | description="Dump UNIX socket packets", |
| 36 | formatter_class=argparse.RawDescriptionHelpFormatter, |
| 37 | epilog=examples) |
| 38 | |
rtoax | 57a86aa | 2021-09-12 13:33:37 +0800 | [diff] [blame] | 39 | parser.add_argument("-p", "--pid", |
| 40 | help="trace this PID only") |
| 41 | args = parser.parse_args() |
| 42 | |
| 43 | # define BPF program |
| 44 | bpf_text = """ |
| 45 | #include <uapi/linux/ptrace.h> |
| 46 | #include <net/sock.h> |
| 47 | #include <bcc/proto.h> |
| 48 | #include <linux/aio.h> |
| 49 | #include <linux/socket.h> |
| 50 | #include <linux/net.h> |
| 51 | #include <linux/fs.h> |
| 52 | #include <linux/mount.h> |
| 53 | #include <linux/module.h> |
| 54 | #include <net/sock.h> |
| 55 | #include <net/af_unix.h> |
| 56 | |
rtoax | 57a86aa | 2021-09-12 13:33:37 +0800 | [diff] [blame] | 57 | #define MAX_PKT 512 |
| 58 | struct recv_data_t { |
| 59 | u32 recv_len; |
| 60 | u8 pkt[MAX_PKT]; |
| 61 | }; |
| 62 | |
| 63 | // single element per-cpu array to hold the current event off the stack |
rtoax | 4615a3f | 2021-09-17 18:38:24 +0800 | [diff] [blame] | 64 | BPF_PERCPU_ARRAY(unix_data, struct recv_data_t, 1); |
rtoax | 57a86aa | 2021-09-12 13:33:37 +0800 | [diff] [blame] | 65 | |
| 66 | BPF_PERF_OUTPUT(unix_recv_events); |
| 67 | |
rtoax | 57a86aa | 2021-09-12 13:33:37 +0800 | [diff] [blame] | 68 | int trace_unix_stream_read_actor(struct pt_regs *ctx) |
| 69 | { |
| 70 | u32 zero = 0; |
| 71 | int ret = PT_REGS_RC(ctx); |
| 72 | u64 pid_tgid = bpf_get_current_pid_tgid(); |
| 73 | u32 pid = pid_tgid >> 32; |
| 74 | u32 tid = pid_tgid; |
| 75 | |
| 76 | FILTER_PID |
| 77 | |
| 78 | struct sk_buff *skb = (struct sk_buff *)PT_REGS_PARM1(ctx); |
| 79 | |
| 80 | struct recv_data_t *data = unix_data.lookup(&zero); |
| 81 | if (!data) |
| 82 | return 0; |
| 83 | |
| 84 | unsigned int data_len = skb->len; |
| 85 | if(data_len > MAX_PKT) |
| 86 | return 0; |
| 87 | |
| 88 | void *iodata = (void *)skb->data; |
| 89 | data->recv_len = data_len; |
| 90 | |
| 91 | bpf_probe_read(data->pkt, data_len, iodata); |
| 92 | unix_recv_events.perf_submit(ctx, data, data_len+sizeof(u32)); |
| 93 | |
| 94 | return 0; |
| 95 | } |
| 96 | """ |
| 97 | |
| 98 | if args.pid: |
| 99 | bpf_text = bpf_text.replace('FILTER_PID', |
| 100 | 'if (pid != %s) { return 0; }' % args.pid) |
| 101 | |
| 102 | bpf_text = bpf_text.replace('FILTER_PID', '') |
| 103 | |
| 104 | # process event |
rtoax | 57a86aa | 2021-09-12 13:33:37 +0800 | [diff] [blame] | 105 | def print_recv_pkg(cpu, data, size): |
| 106 | event = b["unix_recv_events"].event(data) |
rtoax | 4615a3f | 2021-09-17 18:38:24 +0800 | [diff] [blame] | 107 | if args.pid: |
| 108 | print("PID \033[1;31m%s\033[m " % args.pid, end="") |
| 109 | print("Recv \033[1;31m%d\033[m bytes" % event.recv_len) |
| 110 | |
| 111 | print(" ", end="") |
rtoax | 57a86aa | 2021-09-12 13:33:37 +0800 | [diff] [blame] | 112 | for i in range(0, event.recv_len): |
| 113 | print("%02x " % event.pkt[i], end="") |
| 114 | sys.stdout.flush() |
| 115 | if (i+1)%16 == 0: |
| 116 | print("") |
rtoax | 4615a3f | 2021-09-17 18:38:24 +0800 | [diff] [blame] | 117 | print(" ", end="") |
| 118 | print("") |
| 119 | |
rtoax | 57a86aa | 2021-09-12 13:33:37 +0800 | [diff] [blame] | 120 | # initialize BPF |
| 121 | b = BPF(text=bpf_text) |
rtoax | 57a86aa | 2021-09-12 13:33:37 +0800 | [diff] [blame] | 122 | b.attach_kprobe(event="unix_stream_read_actor", fn_name="trace_unix_stream_read_actor") |
| 123 | |
rtoax | 4615a3f | 2021-09-17 18:38:24 +0800 | [diff] [blame] | 124 | if args.pid: |
| 125 | print("Tracing \033[1;31mPID=%s\033[m UNIX socket packets ... Hit Ctrl-C to end" % args.pid) |
| 126 | else: |
| 127 | print("Tracing UNIX socket packets ... Hit Ctrl-C to end") |
rtoax | 57a86aa | 2021-09-12 13:33:37 +0800 | [diff] [blame] | 128 | |
rtoax | 57a86aa | 2021-09-12 13:33:37 +0800 | [diff] [blame] | 129 | start_ts = 0 |
| 130 | |
| 131 | # read events |
rtoax | 57a86aa | 2021-09-12 13:33:37 +0800 | [diff] [blame] | 132 | b["unix_recv_events"].open_perf_buffer(print_recv_pkg) |
| 133 | |
| 134 | while True: |
| 135 | try: |
| 136 | b.perf_buffer_poll() |
| 137 | except KeyboardInterrupt: |
| 138 | exit() |