xref: /aosp_15_r20/external/bcc/tools/tcpstates.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python
2*387f9dfdSAndroid Build Coastguard Worker# -*- coding: utf-8 -*-
3*387f9dfdSAndroid Build Coastguard Worker# @lint-avoid-python-3-compatibility-imports
4*387f9dfdSAndroid Build Coastguard Worker#
5*387f9dfdSAndroid Build Coastguard Worker# tcpstates   Trace the TCP session state changes with durations.
6*387f9dfdSAndroid Build Coastguard Worker#             For Linux, uses BCC, BPF. Embedded C.
7*387f9dfdSAndroid Build Coastguard Worker#
8*387f9dfdSAndroid Build Coastguard Worker# USAGE: tcpstates [-h] [-C] [-S] [interval [count]] [-4 | -6]
9*387f9dfdSAndroid Build Coastguard Worker#
10*387f9dfdSAndroid Build Coastguard Worker# This uses the sock:inet_sock_set_state tracepoint, added to Linux 4.16.
11*387f9dfdSAndroid Build Coastguard Worker# Linux 4.16 also adds more state transitions so that they can be traced.
12*387f9dfdSAndroid Build Coastguard Worker#
13*387f9dfdSAndroid Build Coastguard Worker# Copyright 2018 Netflix, Inc.
14*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
15*387f9dfdSAndroid Build Coastguard Worker#
16*387f9dfdSAndroid Build Coastguard Worker# 20-Mar-2018   Brendan Gregg   Created this.
17*387f9dfdSAndroid Build Coastguard Worker
18*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
19*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
20*387f9dfdSAndroid Build Coastguard Workerimport argparse
21*387f9dfdSAndroid Build Coastguard Workerfrom socket import inet_ntop, AF_INET, AF_INET6
22*387f9dfdSAndroid Build Coastguard Workerfrom time import strftime, time
23*387f9dfdSAndroid Build Coastguard Workerfrom os import getuid
24*387f9dfdSAndroid Build Coastguard Worker
25*387f9dfdSAndroid Build Coastguard Worker# arguments
26*387f9dfdSAndroid Build Coastguard Workerexamples = """examples:
27*387f9dfdSAndroid Build Coastguard Worker    ./tcpstates           # trace all TCP state changes
28*387f9dfdSAndroid Build Coastguard Worker    ./tcpstates -t        # include timestamp column
29*387f9dfdSAndroid Build Coastguard Worker    ./tcpstates -T        # include time column (HH:MM:SS)
30*387f9dfdSAndroid Build Coastguard Worker    ./tcpstates -w        # wider columns (fit IPv6)
31*387f9dfdSAndroid Build Coastguard Worker    ./tcpstates -stT      # csv output, with times & timestamps
32*387f9dfdSAndroid Build Coastguard Worker    ./tcpstates -Y        # log events to the systemd journal
33*387f9dfdSAndroid Build Coastguard Worker    ./tcpstates -L 80     # only trace local port 80
34*387f9dfdSAndroid Build Coastguard Worker    ./tcpstates -L 80,81  # only trace local ports 80 and 81
35*387f9dfdSAndroid Build Coastguard Worker    ./tcpstates -D 80     # only trace remote port 80
36*387f9dfdSAndroid Build Coastguard Worker    ./tcpstates -4        # trace IPv4 family only
37*387f9dfdSAndroid Build Coastguard Worker    ./tcpstates -6        # trace IPv6 family only
38*387f9dfdSAndroid Build Coastguard Worker"""
39*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(
40*387f9dfdSAndroid Build Coastguard Worker    description="Trace TCP session state changes and durations",
41*387f9dfdSAndroid Build Coastguard Worker    formatter_class=argparse.RawDescriptionHelpFormatter,
42*387f9dfdSAndroid Build Coastguard Worker    epilog=examples)
43*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-T", "--time", action="store_true",
44*387f9dfdSAndroid Build Coastguard Worker    help="include time column on output (HH:MM:SS)")
45*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-t", "--timestamp", action="store_true",
46*387f9dfdSAndroid Build Coastguard Worker    help="include timestamp on output (seconds)")
47*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-w", "--wide", action="store_true",
48*387f9dfdSAndroid Build Coastguard Worker    help="wide column output (fits IPv6 addresses)")
49*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-s", "--csv", action="store_true",
50*387f9dfdSAndroid Build Coastguard Worker    help="comma separated values output")
51*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-L", "--localport",
52*387f9dfdSAndroid Build Coastguard Worker    help="comma-separated list of local ports to trace.")
53*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-D", "--remoteport",
54*387f9dfdSAndroid Build Coastguard Worker    help="comma-separated list of remote ports to trace.")
55*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true",
56*387f9dfdSAndroid Build Coastguard Worker    help=argparse.SUPPRESS)
57*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-Y", "--journal", action="store_true",
58*387f9dfdSAndroid Build Coastguard Worker    help="log session state changes to the systemd journal")
59*387f9dfdSAndroid Build Coastguard Workergroup = parser.add_mutually_exclusive_group()
60*387f9dfdSAndroid Build Coastguard Workergroup.add_argument("-4", "--ipv4", action="store_true",
61*387f9dfdSAndroid Build Coastguard Worker    help="trace IPv4 family only")
62*387f9dfdSAndroid Build Coastguard Workergroup.add_argument("-6", "--ipv6", action="store_true",
63*387f9dfdSAndroid Build Coastguard Worker    help="trace IPv6 family only")
64*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args()
65*387f9dfdSAndroid Build Coastguard Workerdebug = 0
66*387f9dfdSAndroid Build Coastguard Worker
67*387f9dfdSAndroid Build Coastguard Worker# define BPF program
68*387f9dfdSAndroid Build Coastguard Workerbpf_header = """
69*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
70*387f9dfdSAndroid Build Coastguard Worker#include <linux/tcp.h>
71*387f9dfdSAndroid Build Coastguard Worker#include <net/sock.h>
72*387f9dfdSAndroid Build Coastguard Worker#include <bcc/proto.h>
73*387f9dfdSAndroid Build Coastguard Worker
74*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(last, struct sock *, u64);
75*387f9dfdSAndroid Build Coastguard Worker
76*387f9dfdSAndroid Build Coastguard Worker// separate data structs for ipv4 and ipv6
77*387f9dfdSAndroid Build Coastguard Workerstruct ipv4_data_t {
78*387f9dfdSAndroid Build Coastguard Worker    u64 ts_us;
79*387f9dfdSAndroid Build Coastguard Worker    u64 skaddr;
80*387f9dfdSAndroid Build Coastguard Worker    u32 saddr[1];
81*387f9dfdSAndroid Build Coastguard Worker    u32 daddr[1];
82*387f9dfdSAndroid Build Coastguard Worker    u64 span_us;
83*387f9dfdSAndroid Build Coastguard Worker    u32 pid;
84*387f9dfdSAndroid Build Coastguard Worker    u16 lport;
85*387f9dfdSAndroid Build Coastguard Worker    u16 dport;
86*387f9dfdSAndroid Build Coastguard Worker    int oldstate;
87*387f9dfdSAndroid Build Coastguard Worker    int newstate;
88*387f9dfdSAndroid Build Coastguard Worker    char task[TASK_COMM_LEN];
89*387f9dfdSAndroid Build Coastguard Worker};
90*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(ipv4_events);
91*387f9dfdSAndroid Build Coastguard Worker
92*387f9dfdSAndroid Build Coastguard Workerstruct ipv6_data_t {
93*387f9dfdSAndroid Build Coastguard Worker    u64 ts_us;
94*387f9dfdSAndroid Build Coastguard Worker    u64 skaddr;
95*387f9dfdSAndroid Build Coastguard Worker    u32 saddr[4];
96*387f9dfdSAndroid Build Coastguard Worker    u32 daddr[4];
97*387f9dfdSAndroid Build Coastguard Worker    u64 span_us;
98*387f9dfdSAndroid Build Coastguard Worker    u32 pid;
99*387f9dfdSAndroid Build Coastguard Worker    u16 lport;
100*387f9dfdSAndroid Build Coastguard Worker    u16 dport;
101*387f9dfdSAndroid Build Coastguard Worker    int oldstate;
102*387f9dfdSAndroid Build Coastguard Worker    int newstate;
103*387f9dfdSAndroid Build Coastguard Worker    char task[TASK_COMM_LEN];
104*387f9dfdSAndroid Build Coastguard Worker};
105*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(ipv6_events);
106*387f9dfdSAndroid Build Coastguard Worker"""
107*387f9dfdSAndroid Build Coastguard Worker
108*387f9dfdSAndroid Build Coastguard Workerbpf_text_tracepoint = """
109*387f9dfdSAndroid Build Coastguard WorkerTRACEPOINT_PROBE(sock, inet_sock_set_state)
110*387f9dfdSAndroid Build Coastguard Worker{
111*387f9dfdSAndroid Build Coastguard Worker    if (args->protocol != IPPROTO_TCP)
112*387f9dfdSAndroid Build Coastguard Worker        return 0;
113*387f9dfdSAndroid Build Coastguard Worker
114*387f9dfdSAndroid Build Coastguard Worker    u32 pid = bpf_get_current_pid_tgid() >> 32;
115*387f9dfdSAndroid Build Coastguard Worker    // sk is used as a UUID
116*387f9dfdSAndroid Build Coastguard Worker    struct sock *sk = (struct sock *)args->skaddr;
117*387f9dfdSAndroid Build Coastguard Worker
118*387f9dfdSAndroid Build Coastguard Worker    // lport is either used in a filter here, or later
119*387f9dfdSAndroid Build Coastguard Worker    u16 lport = args->sport;
120*387f9dfdSAndroid Build Coastguard Worker    FILTER_LPORT
121*387f9dfdSAndroid Build Coastguard Worker
122*387f9dfdSAndroid Build Coastguard Worker    // dport is either used in a filter here, or later
123*387f9dfdSAndroid Build Coastguard Worker    u16 dport = args->dport;
124*387f9dfdSAndroid Build Coastguard Worker    FILTER_DPORT
125*387f9dfdSAndroid Build Coastguard Worker
126*387f9dfdSAndroid Build Coastguard Worker    // calculate delta
127*387f9dfdSAndroid Build Coastguard Worker    u64 *tsp, delta_us;
128*387f9dfdSAndroid Build Coastguard Worker    tsp = last.lookup(&sk);
129*387f9dfdSAndroid Build Coastguard Worker    if (tsp == 0)
130*387f9dfdSAndroid Build Coastguard Worker        delta_us = 0;
131*387f9dfdSAndroid Build Coastguard Worker    else
132*387f9dfdSAndroid Build Coastguard Worker        delta_us = (bpf_ktime_get_ns() - *tsp) / 1000;
133*387f9dfdSAndroid Build Coastguard Worker    u16 family = args->family;
134*387f9dfdSAndroid Build Coastguard Worker    FILTER_FAMILY
135*387f9dfdSAndroid Build Coastguard Worker
136*387f9dfdSAndroid Build Coastguard Worker    // workaround to avoid llvm optimization which will cause context ptr args modified
137*387f9dfdSAndroid Build Coastguard Worker    int tcp_newstate = args->newstate;
138*387f9dfdSAndroid Build Coastguard Worker
139*387f9dfdSAndroid Build Coastguard Worker    if (args->family == AF_INET) {
140*387f9dfdSAndroid Build Coastguard Worker        struct ipv4_data_t data4 = {
141*387f9dfdSAndroid Build Coastguard Worker            .span_us = delta_us,
142*387f9dfdSAndroid Build Coastguard Worker            .oldstate = args->oldstate,
143*387f9dfdSAndroid Build Coastguard Worker            .newstate = args->newstate };
144*387f9dfdSAndroid Build Coastguard Worker        data4.skaddr = (u64)args->skaddr;
145*387f9dfdSAndroid Build Coastguard Worker        data4.ts_us = bpf_ktime_get_ns() / 1000;
146*387f9dfdSAndroid Build Coastguard Worker        __builtin_memcpy(&data4.saddr, args->saddr, sizeof(data4.saddr));
147*387f9dfdSAndroid Build Coastguard Worker        __builtin_memcpy(&data4.daddr, args->daddr, sizeof(data4.daddr));
148*387f9dfdSAndroid Build Coastguard Worker        data4.lport = lport;
149*387f9dfdSAndroid Build Coastguard Worker        data4.dport = dport;
150*387f9dfdSAndroid Build Coastguard Worker        data4.pid = pid;
151*387f9dfdSAndroid Build Coastguard Worker
152*387f9dfdSAndroid Build Coastguard Worker        bpf_get_current_comm(&data4.task, sizeof(data4.task));
153*387f9dfdSAndroid Build Coastguard Worker        ipv4_events.perf_submit(args, &data4, sizeof(data4));
154*387f9dfdSAndroid Build Coastguard Worker
155*387f9dfdSAndroid Build Coastguard Worker    } else /* 6 */ {
156*387f9dfdSAndroid Build Coastguard Worker        struct ipv6_data_t data6 = {
157*387f9dfdSAndroid Build Coastguard Worker            .span_us = delta_us,
158*387f9dfdSAndroid Build Coastguard Worker            .oldstate = args->oldstate,
159*387f9dfdSAndroid Build Coastguard Worker            .newstate = args->newstate };
160*387f9dfdSAndroid Build Coastguard Worker        data6.skaddr = (u64)args->skaddr;
161*387f9dfdSAndroid Build Coastguard Worker        data6.ts_us = bpf_ktime_get_ns() / 1000;
162*387f9dfdSAndroid Build Coastguard Worker        __builtin_memcpy(&data6.saddr, args->saddr_v6, sizeof(data6.saddr));
163*387f9dfdSAndroid Build Coastguard Worker        __builtin_memcpy(&data6.daddr, args->daddr_v6, sizeof(data6.daddr));
164*387f9dfdSAndroid Build Coastguard Worker        data6.lport = lport;
165*387f9dfdSAndroid Build Coastguard Worker        data6.dport = dport;
166*387f9dfdSAndroid Build Coastguard Worker        data6.pid = pid;
167*387f9dfdSAndroid Build Coastguard Worker        bpf_get_current_comm(&data6.task, sizeof(data6.task));
168*387f9dfdSAndroid Build Coastguard Worker        ipv6_events.perf_submit(args, &data6, sizeof(data6));
169*387f9dfdSAndroid Build Coastguard Worker    }
170*387f9dfdSAndroid Build Coastguard Worker
171*387f9dfdSAndroid Build Coastguard Worker    if (tcp_newstate == TCP_CLOSE) {
172*387f9dfdSAndroid Build Coastguard Worker        last.delete(&sk);
173*387f9dfdSAndroid Build Coastguard Worker    } else {
174*387f9dfdSAndroid Build Coastguard Worker        u64 ts = bpf_ktime_get_ns();
175*387f9dfdSAndroid Build Coastguard Worker        last.update(&sk, &ts);
176*387f9dfdSAndroid Build Coastguard Worker    }
177*387f9dfdSAndroid Build Coastguard Worker
178*387f9dfdSAndroid Build Coastguard Worker    return 0;
179*387f9dfdSAndroid Build Coastguard Worker}
180*387f9dfdSAndroid Build Coastguard Worker"""
181*387f9dfdSAndroid Build Coastguard Worker
182*387f9dfdSAndroid Build Coastguard Workerbpf_text_kprobe = """
183*387f9dfdSAndroid Build Coastguard Workerint kprobe__tcp_set_state(struct pt_regs *ctx, struct sock *sk, int state)
184*387f9dfdSAndroid Build Coastguard Worker{
185*387f9dfdSAndroid Build Coastguard Worker    u32 pid = bpf_get_current_pid_tgid() >> 32;
186*387f9dfdSAndroid Build Coastguard Worker    // sk is used as a UUID
187*387f9dfdSAndroid Build Coastguard Worker
188*387f9dfdSAndroid Build Coastguard Worker    // lport is either used in a filter here, or later
189*387f9dfdSAndroid Build Coastguard Worker    u16 lport = sk->__sk_common.skc_num;
190*387f9dfdSAndroid Build Coastguard Worker    FILTER_LPORT
191*387f9dfdSAndroid Build Coastguard Worker
192*387f9dfdSAndroid Build Coastguard Worker    // dport is either used in a filter here, or later
193*387f9dfdSAndroid Build Coastguard Worker    u16 dport = sk->__sk_common.skc_dport;
194*387f9dfdSAndroid Build Coastguard Worker    dport = ntohs(dport);
195*387f9dfdSAndroid Build Coastguard Worker    FILTER_DPORT
196*387f9dfdSAndroid Build Coastguard Worker
197*387f9dfdSAndroid Build Coastguard Worker    // calculate delta
198*387f9dfdSAndroid Build Coastguard Worker    u64 *tsp, delta_us;
199*387f9dfdSAndroid Build Coastguard Worker    tsp = last.lookup(&sk);
200*387f9dfdSAndroid Build Coastguard Worker    if (tsp == 0)
201*387f9dfdSAndroid Build Coastguard Worker        delta_us = 0;
202*387f9dfdSAndroid Build Coastguard Worker    else
203*387f9dfdSAndroid Build Coastguard Worker        delta_us = (bpf_ktime_get_ns() - *tsp) / 1000;
204*387f9dfdSAndroid Build Coastguard Worker
205*387f9dfdSAndroid Build Coastguard Worker    u16 family = sk->__sk_common.skc_family;
206*387f9dfdSAndroid Build Coastguard Worker    FILTER_FAMILY
207*387f9dfdSAndroid Build Coastguard Worker
208*387f9dfdSAndroid Build Coastguard Worker    if (family == AF_INET) {
209*387f9dfdSAndroid Build Coastguard Worker        struct ipv4_data_t data4 = {
210*387f9dfdSAndroid Build Coastguard Worker            .span_us = delta_us,
211*387f9dfdSAndroid Build Coastguard Worker            .oldstate = sk->__sk_common.skc_state,
212*387f9dfdSAndroid Build Coastguard Worker            .newstate = state };
213*387f9dfdSAndroid Build Coastguard Worker        data4.skaddr = (u64)sk;
214*387f9dfdSAndroid Build Coastguard Worker        data4.ts_us = bpf_ktime_get_ns() / 1000;
215*387f9dfdSAndroid Build Coastguard Worker        data4.saddr = sk->__sk_common.skc_rcv_saddr;
216*387f9dfdSAndroid Build Coastguard Worker        data4.daddr = sk->__sk_common.skc_daddr;
217*387f9dfdSAndroid Build Coastguard Worker        data4.lport = lport;
218*387f9dfdSAndroid Build Coastguard Worker        data4.dport = dport;
219*387f9dfdSAndroid Build Coastguard Worker        data4.pid = pid;
220*387f9dfdSAndroid Build Coastguard Worker
221*387f9dfdSAndroid Build Coastguard Worker        bpf_get_current_comm(&data4.task, sizeof(data4.task));
222*387f9dfdSAndroid Build Coastguard Worker        ipv4_events.perf_submit(ctx, &data4, sizeof(data4));
223*387f9dfdSAndroid Build Coastguard Worker
224*387f9dfdSAndroid Build Coastguard Worker    } else /* 6 */ {
225*387f9dfdSAndroid Build Coastguard Worker        struct ipv6_data_t data6 = {
226*387f9dfdSAndroid Build Coastguard Worker            .span_us = delta_us,
227*387f9dfdSAndroid Build Coastguard Worker            .oldstate = sk->__sk_common.skc_state,
228*387f9dfdSAndroid Build Coastguard Worker            .newstate = state };
229*387f9dfdSAndroid Build Coastguard Worker        data6.skaddr = (u64)sk;
230*387f9dfdSAndroid Build Coastguard Worker        data6.ts_us = bpf_ktime_get_ns() / 1000;
231*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&data6.saddr, sizeof(data6.saddr),
232*387f9dfdSAndroid Build Coastguard Worker            sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
233*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&data6.daddr, sizeof(data6.daddr),
234*387f9dfdSAndroid Build Coastguard Worker            sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32);
235*387f9dfdSAndroid Build Coastguard Worker        data6.lport = lport;
236*387f9dfdSAndroid Build Coastguard Worker        data6.dport = dport;
237*387f9dfdSAndroid Build Coastguard Worker        data6.pid = pid;
238*387f9dfdSAndroid Build Coastguard Worker        bpf_get_current_comm(&data6.task, sizeof(data6.task));
239*387f9dfdSAndroid Build Coastguard Worker        ipv6_events.perf_submit(ctx, &data6, sizeof(data6));
240*387f9dfdSAndroid Build Coastguard Worker    }
241*387f9dfdSAndroid Build Coastguard Worker
242*387f9dfdSAndroid Build Coastguard Worker    if (state == TCP_CLOSE) {
243*387f9dfdSAndroid Build Coastguard Worker        last.delete(&sk);
244*387f9dfdSAndroid Build Coastguard Worker    } else {
245*387f9dfdSAndroid Build Coastguard Worker        u64 ts = bpf_ktime_get_ns();
246*387f9dfdSAndroid Build Coastguard Worker        last.update(&sk, &ts);
247*387f9dfdSAndroid Build Coastguard Worker    }
248*387f9dfdSAndroid Build Coastguard Worker
249*387f9dfdSAndroid Build Coastguard Worker    return 0;
250*387f9dfdSAndroid Build Coastguard Worker
251*387f9dfdSAndroid Build Coastguard Worker};
252*387f9dfdSAndroid Build Coastguard Worker"""
253*387f9dfdSAndroid Build Coastguard Worker
254*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_header
255*387f9dfdSAndroid Build Coastguard Workerif BPF.tracepoint_exists("sock", "inet_sock_set_state"):
256*387f9dfdSAndroid Build Coastguard Worker    bpf_text += bpf_text_tracepoint
257*387f9dfdSAndroid Build Coastguard Workerelse:
258*387f9dfdSAndroid Build Coastguard Worker    bpf_text += bpf_text_kprobe
259*387f9dfdSAndroid Build Coastguard Worker
260*387f9dfdSAndroid Build Coastguard Worker# code substitutions
261*387f9dfdSAndroid Build Coastguard Workerif args.remoteport:
262*387f9dfdSAndroid Build Coastguard Worker    dports = [int(dport) for dport in args.remoteport.split(',')]
263*387f9dfdSAndroid Build Coastguard Worker    dports_if = ' && '.join(['dport != %d' % dport for dport in dports])
264*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER_DPORT',
265*387f9dfdSAndroid Build Coastguard Worker        'if (%s) { last.delete(&sk); return 0; }' % dports_if)
266*387f9dfdSAndroid Build Coastguard Workerif args.localport:
267*387f9dfdSAndroid Build Coastguard Worker    lports = [int(lport) for lport in args.localport.split(',')]
268*387f9dfdSAndroid Build Coastguard Worker    lports_if = ' && '.join(['lport != %d' % lport for lport in lports])
269*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER_LPORT',
270*387f9dfdSAndroid Build Coastguard Worker        'if (%s) { last.delete(&sk); return 0; }' % lports_if)
271*387f9dfdSAndroid Build Coastguard Workerif args.ipv4:
272*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER_FAMILY',
273*387f9dfdSAndroid Build Coastguard Worker        'if (family != AF_INET) { return 0; }')
274*387f9dfdSAndroid Build Coastguard Workerelif args.ipv6:
275*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER_FAMILY',
276*387f9dfdSAndroid Build Coastguard Worker        'if (family != AF_INET6) { return 0; }')
277*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('FILTER_FAMILY', '')
278*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('FILTER_DPORT', '')
279*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('FILTER_LPORT', '')
280*387f9dfdSAndroid Build Coastguard Worker
281*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf:
282*387f9dfdSAndroid Build Coastguard Worker    print(bpf_text)
283*387f9dfdSAndroid Build Coastguard Worker    if args.ebpf:
284*387f9dfdSAndroid Build Coastguard Worker        exit()
285*387f9dfdSAndroid Build Coastguard Worker
286*387f9dfdSAndroid Build Coastguard Worker#
287*387f9dfdSAndroid Build Coastguard Worker# Setup output formats
288*387f9dfdSAndroid Build Coastguard Worker#
289*387f9dfdSAndroid Build Coastguard Worker# Don't change the default output (next 2 lines): this fits in 80 chars. I
290*387f9dfdSAndroid Build Coastguard Worker# know it doesn't have NS or UIDs etc. I know. If you really, really, really
291*387f9dfdSAndroid Build Coastguard Worker# need to add columns, columns that solve real actual problems, I'd start by
292*387f9dfdSAndroid Build Coastguard Worker# adding an extended mode (-x) to included those columns.
293*387f9dfdSAndroid Build Coastguard Worker#
294*387f9dfdSAndroid Build Coastguard Workerheader_string = "%-16s %-5s %-10.10s %s%-15s %-5s %-15s %-5s %-11s -> %-11s %s"
295*387f9dfdSAndroid Build Coastguard Workerformat_string = ("%-16x %-5d %-10.10s %s%-15s %-5d %-15s %-5d %-11s " +
296*387f9dfdSAndroid Build Coastguard Worker    "-> %-11s %.3f")
297*387f9dfdSAndroid Build Coastguard Workerif args.wide:
298*387f9dfdSAndroid Build Coastguard Worker    header_string = ("%-16s %-5s %-16.16s %-2s %-39s %-5s %-39s %-5s %-11s " +
299*387f9dfdSAndroid Build Coastguard Worker        "-> %-11s %s")
300*387f9dfdSAndroid Build Coastguard Worker    format_string = ("%-16x %-5d %-16.16s %-2s %-39s %-5s %-39s %-5d %-11s " +
301*387f9dfdSAndroid Build Coastguard Worker        "-> %-11s %.3f")
302*387f9dfdSAndroid Build Coastguard Workerif args.csv:
303*387f9dfdSAndroid Build Coastguard Worker    header_string = "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s"
304*387f9dfdSAndroid Build Coastguard Worker    format_string = "%x,%d,%s,%s,%s,%s,%s,%d,%s,%s,%.3f"
305*387f9dfdSAndroid Build Coastguard Worker
306*387f9dfdSAndroid Build Coastguard Workerif args.journal:
307*387f9dfdSAndroid Build Coastguard Worker    try:
308*387f9dfdSAndroid Build Coastguard Worker        from systemd import journal
309*387f9dfdSAndroid Build Coastguard Worker    except ImportError:
310*387f9dfdSAndroid Build Coastguard Worker        print("ERROR: Journal logging requires the systemd.journal module")
311*387f9dfdSAndroid Build Coastguard Worker        exit(1)
312*387f9dfdSAndroid Build Coastguard Worker
313*387f9dfdSAndroid Build Coastguard Worker
314*387f9dfdSAndroid Build Coastguard Workerdef tcpstate2str(state):
315*387f9dfdSAndroid Build Coastguard Worker    # from include/net/tcp_states.h:
316*387f9dfdSAndroid Build Coastguard Worker    tcpstate = {
317*387f9dfdSAndroid Build Coastguard Worker        1: "ESTABLISHED",
318*387f9dfdSAndroid Build Coastguard Worker        2: "SYN_SENT",
319*387f9dfdSAndroid Build Coastguard Worker        3: "SYN_RECV",
320*387f9dfdSAndroid Build Coastguard Worker        4: "FIN_WAIT1",
321*387f9dfdSAndroid Build Coastguard Worker        5: "FIN_WAIT2",
322*387f9dfdSAndroid Build Coastguard Worker        6: "TIME_WAIT",
323*387f9dfdSAndroid Build Coastguard Worker        7: "CLOSE",
324*387f9dfdSAndroid Build Coastguard Worker        8: "CLOSE_WAIT",
325*387f9dfdSAndroid Build Coastguard Worker        9: "LAST_ACK",
326*387f9dfdSAndroid Build Coastguard Worker        10: "LISTEN",
327*387f9dfdSAndroid Build Coastguard Worker        11: "CLOSING",
328*387f9dfdSAndroid Build Coastguard Worker        12: "NEW_SYN_RECV",
329*387f9dfdSAndroid Build Coastguard Worker    }
330*387f9dfdSAndroid Build Coastguard Worker
331*387f9dfdSAndroid Build Coastguard Worker    if state in tcpstate:
332*387f9dfdSAndroid Build Coastguard Worker        return tcpstate[state]
333*387f9dfdSAndroid Build Coastguard Worker    else:
334*387f9dfdSAndroid Build Coastguard Worker        return str(state)
335*387f9dfdSAndroid Build Coastguard Worker
336*387f9dfdSAndroid Build Coastguard Workerdef journal_fields(event, addr_family):
337*387f9dfdSAndroid Build Coastguard Worker    addr_pfx = 'IPV4'
338*387f9dfdSAndroid Build Coastguard Worker    if addr_family == AF_INET6:
339*387f9dfdSAndroid Build Coastguard Worker        addr_pfx = 'IPV6'
340*387f9dfdSAndroid Build Coastguard Worker
341*387f9dfdSAndroid Build Coastguard Worker    fields = {
342*387f9dfdSAndroid Build Coastguard Worker        # Standard fields described in systemd.journal-fields(7). journal.send
343*387f9dfdSAndroid Build Coastguard Worker        # will fill in CODE_LINE, CODE_FILE, and CODE_FUNC for us. If we're
344*387f9dfdSAndroid Build Coastguard Worker        # root and specify OBJECT_PID, systemd-journald will add other OBJECT_*
345*387f9dfdSAndroid Build Coastguard Worker        # fields for us.
346*387f9dfdSAndroid Build Coastguard Worker        'SYSLOG_IDENTIFIER': 'tcpstates',
347*387f9dfdSAndroid Build Coastguard Worker        'PRIORITY': 5,
348*387f9dfdSAndroid Build Coastguard Worker        '_SOURCE_REALTIME_TIMESTAMP': time() * 1000000,
349*387f9dfdSAndroid Build Coastguard Worker        'OBJECT_PID': str(event.pid),
350*387f9dfdSAndroid Build Coastguard Worker        'OBJECT_COMM': event.task.decode('utf-8', 'replace'),
351*387f9dfdSAndroid Build Coastguard Worker        # Custom fields, aka "stuff we sort of made up".
352*387f9dfdSAndroid Build Coastguard Worker        'OBJECT_' + addr_pfx + '_SOURCE_ADDRESS': inet_ntop(addr_family, event.saddr),
353*387f9dfdSAndroid Build Coastguard Worker        'OBJECT_TCP_SOURCE_PORT': str(event.lport),
354*387f9dfdSAndroid Build Coastguard Worker        'OBJECT_' + addr_pfx + '_DESTINATION_ADDRESS': inet_ntop(addr_family, event.daddr),
355*387f9dfdSAndroid Build Coastguard Worker        'OBJECT_TCP_DESTINATION_PORT': str(event.dport),
356*387f9dfdSAndroid Build Coastguard Worker        'OBJECT_TCP_OLD_STATE': tcpstate2str(event.oldstate),
357*387f9dfdSAndroid Build Coastguard Worker        'OBJECT_TCP_NEW_STATE': tcpstate2str(event.newstate),
358*387f9dfdSAndroid Build Coastguard Worker        'OBJECT_TCP_SPAN_TIME': str(event.span_us)
359*387f9dfdSAndroid Build Coastguard Worker        }
360*387f9dfdSAndroid Build Coastguard Worker
361*387f9dfdSAndroid Build Coastguard Worker    msg_format_string = (u"%(OBJECT_COMM)s " +
362*387f9dfdSAndroid Build Coastguard Worker        u"%(OBJECT_" + addr_pfx + "_SOURCE_ADDRESS)s " +
363*387f9dfdSAndroid Build Coastguard Worker        u"%(OBJECT_TCP_SOURCE_PORT)s → " +
364*387f9dfdSAndroid Build Coastguard Worker        u"%(OBJECT_" + addr_pfx + "_DESTINATION_ADDRESS)s " +
365*387f9dfdSAndroid Build Coastguard Worker        u"%(OBJECT_TCP_DESTINATION_PORT)s " +
366*387f9dfdSAndroid Build Coastguard Worker        u"%(OBJECT_TCP_OLD_STATE)s → %(OBJECT_TCP_NEW_STATE)s")
367*387f9dfdSAndroid Build Coastguard Worker    fields['MESSAGE'] = msg_format_string % (fields)
368*387f9dfdSAndroid Build Coastguard Worker
369*387f9dfdSAndroid Build Coastguard Worker    if getuid() == 0:
370*387f9dfdSAndroid Build Coastguard Worker        del fields['OBJECT_COMM'] # Handled by systemd-journald
371*387f9dfdSAndroid Build Coastguard Worker
372*387f9dfdSAndroid Build Coastguard Worker    return fields
373*387f9dfdSAndroid Build Coastguard Worker
374*387f9dfdSAndroid Build Coastguard Worker# process event
375*387f9dfdSAndroid Build Coastguard Workerdef print_event(event, addr_family):
376*387f9dfdSAndroid Build Coastguard Worker    global start_ts
377*387f9dfdSAndroid Build Coastguard Worker    if args.time:
378*387f9dfdSAndroid Build Coastguard Worker        if args.csv:
379*387f9dfdSAndroid Build Coastguard Worker            print("%s," % strftime("%H:%M:%S"), end="")
380*387f9dfdSAndroid Build Coastguard Worker        else:
381*387f9dfdSAndroid Build Coastguard Worker            print("%-8s " % strftime("%H:%M:%S"), end="")
382*387f9dfdSAndroid Build Coastguard Worker    if args.timestamp:
383*387f9dfdSAndroid Build Coastguard Worker        if start_ts == 0:
384*387f9dfdSAndroid Build Coastguard Worker            start_ts = event.ts_us
385*387f9dfdSAndroid Build Coastguard Worker        delta_s = (float(event.ts_us) - start_ts) / 1000000
386*387f9dfdSAndroid Build Coastguard Worker        if args.csv:
387*387f9dfdSAndroid Build Coastguard Worker            print("%.6f," % delta_s, end="")
388*387f9dfdSAndroid Build Coastguard Worker        else:
389*387f9dfdSAndroid Build Coastguard Worker            print("%-9.6f " % delta_s, end="")
390*387f9dfdSAndroid Build Coastguard Worker    if addr_family == AF_INET:
391*387f9dfdSAndroid Build Coastguard Worker        version = "4"
392*387f9dfdSAndroid Build Coastguard Worker    else:
393*387f9dfdSAndroid Build Coastguard Worker        version = "6"
394*387f9dfdSAndroid Build Coastguard Worker    print(format_string % (event.skaddr, event.pid, event.task.decode('utf-8', 'replace'),
395*387f9dfdSAndroid Build Coastguard Worker        version if args.wide or args.csv else "",
396*387f9dfdSAndroid Build Coastguard Worker        inet_ntop(addr_family, event.saddr), event.lport,
397*387f9dfdSAndroid Build Coastguard Worker        inet_ntop(addr_family, event.daddr), event.dport,
398*387f9dfdSAndroid Build Coastguard Worker        tcpstate2str(event.oldstate), tcpstate2str(event.newstate),
399*387f9dfdSAndroid Build Coastguard Worker        float(event.span_us) / 1000))
400*387f9dfdSAndroid Build Coastguard Worker    if args.journal:
401*387f9dfdSAndroid Build Coastguard Worker        journal.send(**journal_fields(event, addr_family))
402*387f9dfdSAndroid Build Coastguard Worker
403*387f9dfdSAndroid Build Coastguard Workerdef print_ipv4_event(cpu, data, size):
404*387f9dfdSAndroid Build Coastguard Worker    event = b["ipv4_events"].event(data)
405*387f9dfdSAndroid Build Coastguard Worker    print_event(event, AF_INET)
406*387f9dfdSAndroid Build Coastguard Worker
407*387f9dfdSAndroid Build Coastguard Workerdef print_ipv6_event(cpu, data, size):
408*387f9dfdSAndroid Build Coastguard Worker    event = b["ipv6_events"].event(data)
409*387f9dfdSAndroid Build Coastguard Worker    print_event(event, AF_INET6)
410*387f9dfdSAndroid Build Coastguard Worker
411*387f9dfdSAndroid Build Coastguard Worker# initialize BPF
412*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text)
413*387f9dfdSAndroid Build Coastguard Worker
414*387f9dfdSAndroid Build Coastguard Worker# header
415*387f9dfdSAndroid Build Coastguard Workerif args.time:
416*387f9dfdSAndroid Build Coastguard Worker    if args.csv:
417*387f9dfdSAndroid Build Coastguard Worker        print("%s," % ("TIME"), end="")
418*387f9dfdSAndroid Build Coastguard Worker    else:
419*387f9dfdSAndroid Build Coastguard Worker        print("%-8s " % ("TIME"), end="")
420*387f9dfdSAndroid Build Coastguard Workerif args.timestamp:
421*387f9dfdSAndroid Build Coastguard Worker    if args.csv:
422*387f9dfdSAndroid Build Coastguard Worker        print("%s," % ("TIME(s)"), end="")
423*387f9dfdSAndroid Build Coastguard Worker    else:
424*387f9dfdSAndroid Build Coastguard Worker        print("%-9s " % ("TIME(s)"), end="")
425*387f9dfdSAndroid Build Coastguard Workerprint(header_string % ("SKADDR", "C-PID", "C-COMM",
426*387f9dfdSAndroid Build Coastguard Worker    "IP" if args.wide or args.csv else "",
427*387f9dfdSAndroid Build Coastguard Worker    "LADDR", "LPORT", "RADDR", "RPORT",
428*387f9dfdSAndroid Build Coastguard Worker    "OLDSTATE", "NEWSTATE", "MS"))
429*387f9dfdSAndroid Build Coastguard Worker
430*387f9dfdSAndroid Build Coastguard Workerstart_ts = 0
431*387f9dfdSAndroid Build Coastguard Worker
432*387f9dfdSAndroid Build Coastguard Worker# read events
433*387f9dfdSAndroid Build Coastguard Workerb["ipv4_events"].open_perf_buffer(print_ipv4_event, page_cnt=64)
434*387f9dfdSAndroid Build Coastguard Workerb["ipv6_events"].open_perf_buffer(print_ipv6_event, page_cnt=64)
435*387f9dfdSAndroid Build Coastguard Workerwhile 1:
436*387f9dfdSAndroid Build Coastguard Worker    try:
437*387f9dfdSAndroid Build Coastguard Worker        b.perf_buffer_poll()
438*387f9dfdSAndroid Build Coastguard Worker    except KeyboardInterrupt:
439*387f9dfdSAndroid Build Coastguard Worker        exit()
440