blob: cb3e83b48d54641e2f4455a4c12fd691946de535 [file] [log] [blame]
Alexey Ivanovcc01a9c2019-01-16 09:50:46 -08001#!/usr/bin/python
Alexei Starovoitovbdf07732016-01-14 10:09:20 -08002# @lint-avoid-python-3-compatibility-imports
Brendan Greggf06d3b42015-10-15 17:21:32 -07003#
Alexei Starovoitovbdf07732016-01-14 10:09:20 -08004# tcpconnect Trace TCP connect()s.
5# For Linux, uses BCC, eBPF. Embedded C.
Brendan Greggf06d3b42015-10-15 17:21:32 -07006#
chantra52938052016-09-10 09:44:50 -07007# USAGE: tcpconnect [-h] [-t] [-p PID] [-P PORT [PORT ...]]
Brendan Greggf06d3b42015-10-15 17:21:32 -07008#
9# All connection attempts are traced, even if they ultimately fail.
10#
Brendan Gregg24825522016-02-14 16:32:29 -080011# This uses dynamic tracing of kernel functions, and will need to be updated
12# to match kernel changes.
13#
Brendan Greggf06d3b42015-10-15 17:21:32 -070014# Copyright (c) 2015 Brendan Gregg.
15# Licensed under the Apache License, Version 2.0 (the "License")
16#
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080017# 25-Sep-2015 Brendan Gregg Created this.
Brendan Gregg24825522016-02-14 16:32:29 -080018# 14-Feb-2016 " " Switch to bpf_perf_output.
Takuma Kumeb181a8e2019-01-10 05:49:59 +090019# 09-Jan-2019 Takuma Kume Support filtering by UID
Brendan Greggf06d3b42015-10-15 17:21:32 -070020
21from __future__ import print_function
22from bcc import BPF
japrocaed9b1e2019-01-04 20:21:46 +030023from bcc.utils import printb
Brendan Greggf06d3b42015-10-15 17:21:32 -070024import argparse
chantra52938052016-09-10 09:44:50 -070025from socket import inet_ntop, ntohs, AF_INET, AF_INET6
Mark Drayton11de2982016-06-26 21:14:44 +010026from struct import pack
Brendan Greggf06d3b42015-10-15 17:21:32 -070027
28# arguments
29examples = """examples:
30 ./tcpconnect # trace all TCP connect()s
31 ./tcpconnect -t # include timestamps
32 ./tcpconnect -p 181 # only trace PID 181
chantra52938052016-09-10 09:44:50 -070033 ./tcpconnect -P 80 # only trace port 80
34 ./tcpconnect -P 80,81 # only trace port 80 and 81
Takuma Kumeb181a8e2019-01-10 05:49:59 +090035 ./tcpconnect -U # include UID
36 ./tcpconnect -u 1000 # only trace UID 1000
Brendan Greggf06d3b42015-10-15 17:21:32 -070037"""
38parser = argparse.ArgumentParser(
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080039 description="Trace TCP connects",
40 formatter_class=argparse.RawDescriptionHelpFormatter,
41 epilog=examples)
Brendan Greggf06d3b42015-10-15 17:21:32 -070042parser.add_argument("-t", "--timestamp", action="store_true",
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080043 help="include timestamp on output")
Brendan Greggf06d3b42015-10-15 17:21:32 -070044parser.add_argument("-p", "--pid",
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080045 help="trace this PID only")
chantra52938052016-09-10 09:44:50 -070046parser.add_argument("-P", "--port",
47 help="comma-separated list of destination ports to trace.")
Takuma Kumeb181a8e2019-01-10 05:49:59 +090048parser.add_argument("-U", "--print-uid", action="store_true",
49 help="include UID on output")
50parser.add_argument("-u", "--uid",
51 help="trace this UID only")
Nathan Scottcf0792f2018-02-02 16:56:50 +110052parser.add_argument("--ebpf", action="store_true",
53 help=argparse.SUPPRESS)
Brendan Greggf06d3b42015-10-15 17:21:32 -070054args = parser.parse_args()
55debug = 0
56
57# define BPF program
58bpf_text = """
59#include <uapi/linux/ptrace.h>
60#include <net/sock.h>
61#include <bcc/proto.h>
62
63BPF_HASH(currsock, u32, struct sock *);
64
Brendan Gregg24825522016-02-14 16:32:29 -080065// separate data structs for ipv4 and ipv6
66struct ipv4_data_t {
Brendan Gregg24825522016-02-14 16:32:29 -080067 u64 ts_us;
Joe Yin36ce1122018-08-17 06:04:00 +080068 u32 pid;
Takuma Kumeb181a8e2019-01-10 05:49:59 +090069 u32 uid;
Joe Yin36ce1122018-08-17 06:04:00 +080070 u32 saddr;
71 u32 daddr;
Mark Drayton11de2982016-06-26 21:14:44 +010072 u64 ip;
Joe Yin36ce1122018-08-17 06:04:00 +080073 u16 dport;
Brendan Gregg24825522016-02-14 16:32:29 -080074 char task[TASK_COMM_LEN];
75};
76BPF_PERF_OUTPUT(ipv4_events);
77
78struct ipv6_data_t {
Brendan Gregg24825522016-02-14 16:32:29 -080079 u64 ts_us;
Joe Yin36ce1122018-08-17 06:04:00 +080080 u32 pid;
Takuma Kumeb181a8e2019-01-10 05:49:59 +090081 u32 uid;
Mark Drayton11de2982016-06-26 21:14:44 +010082 unsigned __int128 saddr;
83 unsigned __int128 daddr;
Brendan Gregg24825522016-02-14 16:32:29 -080084 u64 ip;
Joe Yin36ce1122018-08-17 06:04:00 +080085 u16 dport;
Brendan Gregg24825522016-02-14 16:32:29 -080086 char task[TASK_COMM_LEN];
87};
88BPF_PERF_OUTPUT(ipv6_events);
89
Brendan Greggf06d3b42015-10-15 17:21:32 -070090int trace_connect_entry(struct pt_regs *ctx, struct sock *sk)
91{
Brendan Gregg8cd3efd2019-04-07 12:32:53 -070092 u64 pid_tgid = bpf_get_current_pid_tgid();
93 u32 pid = pid_tgid >> 32;
94 u32 tid = pid_tgid;
chantra52938052016-09-10 09:44:50 -070095 FILTER_PID
Brendan Greggf06d3b42015-10-15 17:21:32 -070096
Takuma Kumeb181a8e2019-01-10 05:49:59 +090097 u32 uid = bpf_get_current_uid_gid();
98 FILTER_UID
99
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800100 // stash the sock ptr for lookup on return
Brendan Gregg8cd3efd2019-04-07 12:32:53 -0700101 currsock.update(&tid, &sk);
Brendan Greggf06d3b42015-10-15 17:21:32 -0700102
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800103 return 0;
Brendan Greggf06d3b42015-10-15 17:21:32 -0700104};
105
106static int trace_connect_return(struct pt_regs *ctx, short ipver)
107{
Naveen N. Rao4afa96a2016-05-03 14:54:21 +0530108 int ret = PT_REGS_RC(ctx);
Brendan Gregg8cd3efd2019-04-07 12:32:53 -0700109 u64 pid_tgid = bpf_get_current_pid_tgid();
110 u32 pid = pid_tgid >> 32;
111 u32 tid = pid_tgid;
Brendan Greggf06d3b42015-10-15 17:21:32 -0700112
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800113 struct sock **skpp;
Brendan Gregg8cd3efd2019-04-07 12:32:53 -0700114 skpp = currsock.lookup(&tid);
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800115 if (skpp == 0) {
116 return 0; // missed entry
117 }
Brendan Greggf06d3b42015-10-15 17:21:32 -0700118
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800119 if (ret != 0) {
120 // failed to send SYNC packet, may not have populated
121 // socket __sk_common.{skc_rcv_saddr, ...}
Brendan Gregg8cd3efd2019-04-07 12:32:53 -0700122 currsock.delete(&tid);
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800123 return 0;
124 }
Brendan Greggf06d3b42015-10-15 17:21:32 -0700125
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800126 // pull in details
127 struct sock *skp = *skpp;
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200128 u16 dport = skp->__sk_common.skc_dport;
Brendan Greggf06d3b42015-10-15 17:21:32 -0700129
chantra52938052016-09-10 09:44:50 -0700130 FILTER_PORT
131
Brendan Gregg24825522016-02-14 16:32:29 -0800132 if (ipver == 4) {
133 struct ipv4_data_t data4 = {.pid = pid, .ip = ipver};
Takuma Kumeb181a8e2019-01-10 05:49:59 +0900134 data4.uid = bpf_get_current_uid_gid();
Brendan Gregg24825522016-02-14 16:32:29 -0800135 data4.ts_us = bpf_ktime_get_ns() / 1000;
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200136 data4.saddr = skp->__sk_common.skc_rcv_saddr;
137 data4.daddr = skp->__sk_common.skc_daddr;
Brendan Gregg24825522016-02-14 16:32:29 -0800138 data4.dport = ntohs(dport);
139 bpf_get_current_comm(&data4.task, sizeof(data4.task));
140 ipv4_events.perf_submit(ctx, &data4, sizeof(data4));
141
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800142 } else /* 6 */ {
Brendan Gregg24825522016-02-14 16:32:29 -0800143 struct ipv6_data_t data6 = {.pid = pid, .ip = ipver};
Takuma Kumeb181a8e2019-01-10 05:49:59 +0900144 data6.uid = bpf_get_current_uid_gid();
Brendan Gregg24825522016-02-14 16:32:29 -0800145 data6.ts_us = bpf_ktime_get_ns() / 1000;
Mark Drayton11de2982016-06-26 21:14:44 +0100146 bpf_probe_read(&data6.saddr, sizeof(data6.saddr),
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200147 skp->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
Mark Drayton11de2982016-06-26 21:14:44 +0100148 bpf_probe_read(&data6.daddr, sizeof(data6.daddr),
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200149 skp->__sk_common.skc_v6_daddr.in6_u.u6_addr32);
Brendan Gregg24825522016-02-14 16:32:29 -0800150 data6.dport = ntohs(dport);
151 bpf_get_current_comm(&data6.task, sizeof(data6.task));
152 ipv6_events.perf_submit(ctx, &data6, sizeof(data6));
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800153 }
Brendan Greggf06d3b42015-10-15 17:21:32 -0700154
Brendan Gregg8cd3efd2019-04-07 12:32:53 -0700155 currsock.delete(&tid);
Brendan Greggf06d3b42015-10-15 17:21:32 -0700156
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800157 return 0;
Brendan Greggf06d3b42015-10-15 17:21:32 -0700158}
159
160int trace_connect_v4_return(struct pt_regs *ctx)
161{
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800162 return trace_connect_return(ctx, 4);
Brendan Greggf06d3b42015-10-15 17:21:32 -0700163}
164
165int trace_connect_v6_return(struct pt_regs *ctx)
166{
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800167 return trace_connect_return(ctx, 6);
Brendan Greggf06d3b42015-10-15 17:21:32 -0700168}
169"""
170
171# code substitutions
172if args.pid:
chantra52938052016-09-10 09:44:50 -0700173 bpf_text = bpf_text.replace('FILTER_PID',
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800174 'if (pid != %s) { return 0; }' % args.pid)
chantra52938052016-09-10 09:44:50 -0700175if args.port:
176 dports = [int(dport) for dport in args.port.split(',')]
177 dports_if = ' && '.join(['dport != %d' % ntohs(dport) for dport in dports])
178 bpf_text = bpf_text.replace('FILTER_PORT',
179 'if (%s) { currsock.delete(&pid); return 0; }' % dports_if)
Takuma Kumeb181a8e2019-01-10 05:49:59 +0900180if args.uid:
181 bpf_text = bpf_text.replace('FILTER_UID',
182 'if (uid != %s) { return 0; }' % args.uid)
chantra52938052016-09-10 09:44:50 -0700183
184bpf_text = bpf_text.replace('FILTER_PID', '')
185bpf_text = bpf_text.replace('FILTER_PORT', '')
Takuma Kumeb181a8e2019-01-10 05:49:59 +0900186bpf_text = bpf_text.replace('FILTER_UID', '')
chantra52938052016-09-10 09:44:50 -0700187
Nathan Scottcf0792f2018-02-02 16:56:50 +1100188if debug or args.ebpf:
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800189 print(bpf_text)
Nathan Scottcf0792f2018-02-02 16:56:50 +1100190 if args.ebpf:
191 exit()
Brendan Greggf06d3b42015-10-15 17:21:32 -0700192
Brendan Gregg24825522016-02-14 16:32:29 -0800193# process event
194def print_ipv4_event(cpu, data, size):
Xiaozhou Liu31563032019-02-14 14:33:58 +0800195 event = b["ipv4_events"].event(data)
Mark Drayton11de2982016-06-26 21:14:44 +0100196 global start_ts
Brendan Gregg24825522016-02-14 16:32:29 -0800197 if args.timestamp:
198 if start_ts == 0:
199 start_ts = event.ts_us
Gary Lin6c793312019-04-18 15:17:56 +0800200 printb(b"%-9.3f" % ((float(event.ts_us) - start_ts) / 1000000), nl="")
Takuma Kumeb181a8e2019-01-10 05:49:59 +0900201 if args.print_uid:
Gary Lin6c793312019-04-18 15:17:56 +0800202 printb(b"%-6d" % event.uid, nl="")
japrocaed9b1e2019-01-04 20:21:46 +0300203 printb(b"%-6d %-12.12s %-2d %-16s %-16s %-4d" % (event.pid,
Yonghong Songebe19512019-01-10 14:54:16 -0800204 event.task, event.ip,
205 inet_ntop(AF_INET, pack("I", event.saddr)).encode(),
206 inet_ntop(AF_INET, pack("I", event.daddr)).encode(), event.dport))
Brendan Gregg9e0b0872016-03-28 12:11:45 -0700207
Brendan Gregg24825522016-02-14 16:32:29 -0800208def print_ipv6_event(cpu, data, size):
Xiaozhou Liu31563032019-02-14 14:33:58 +0800209 event = b["ipv6_events"].event(data)
Mark Drayton11de2982016-06-26 21:14:44 +0100210 global start_ts
Brendan Gregg24825522016-02-14 16:32:29 -0800211 if args.timestamp:
212 if start_ts == 0:
213 start_ts = event.ts_us
Gary Lin6c793312019-04-18 15:17:56 +0800214 printb(b"%-9.3f" % ((float(event.ts_us) - start_ts) / 1000000), nl="")
Takuma Kumeb181a8e2019-01-10 05:49:59 +0900215 if args.print_uid:
Gary Lin6c793312019-04-18 15:17:56 +0800216 printb(b"%-6d" % event.uid, nl="")
japrocaed9b1e2019-01-04 20:21:46 +0300217 printb(b"%-6d %-12.12s %-2d %-16s %-16s %-4d" % (event.pid,
Yonghong Songebe19512019-01-10 14:54:16 -0800218 event.task, event.ip,
219 inet_ntop(AF_INET6, event.saddr).encode(), inet_ntop(AF_INET6, event.daddr).encode(),
jeromemarchandb96ebcd2018-10-10 01:58:15 +0200220 event.dport))
Brendan Gregg24825522016-02-14 16:32:29 -0800221
Brendan Greggf06d3b42015-10-15 17:21:32 -0700222# initialize BPF
223b = BPF(text=bpf_text)
224b.attach_kprobe(event="tcp_v4_connect", fn_name="trace_connect_entry")
225b.attach_kprobe(event="tcp_v6_connect", fn_name="trace_connect_entry")
226b.attach_kretprobe(event="tcp_v4_connect", fn_name="trace_connect_v4_return")
227b.attach_kretprobe(event="tcp_v6_connect", fn_name="trace_connect_v6_return")
228
229# header
230if args.timestamp:
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800231 print("%-9s" % ("TIME(s)"), end="")
Takuma Kumeb181a8e2019-01-10 05:49:59 +0900232if args.print_uid:
233 print("%-6s" % ("UID"), end="")
Brendan Greggf06d3b42015-10-15 17:21:32 -0700234print("%-6s %-12s %-2s %-16s %-16s %-4s" % ("PID", "COMM", "IP", "SADDR",
235 "DADDR", "DPORT"))
236
237start_ts = 0
238
Brendan Gregg24825522016-02-14 16:32:29 -0800239# read events
240b["ipv4_events"].open_perf_buffer(print_ipv4_event)
241b["ipv6_events"].open_perf_buffer(print_ipv6_event)
Brendan Greggf06d3b42015-10-15 17:21:32 -0700242while 1:
Jerome Marchand51671272018-12-19 01:57:24 +0100243 try:
244 b.perf_buffer_poll()
245 except KeyboardInterrupt:
246 exit()