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