blob: e230f6551b6da24597c8f07ece13867ec7eb77a1 [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{
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080092 u32 pid = bpf_get_current_pid_tgid();
chantra52938052016-09-10 09:44:50 -070093 FILTER_PID
Brendan Greggf06d3b42015-10-15 17:21:32 -070094
Takuma Kumeb181a8e2019-01-10 05:49:59 +090095 u32 uid = bpf_get_current_uid_gid();
96 FILTER_UID
97
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080098 // stash the sock ptr for lookup on return
99 currsock.update(&pid, &sk);
Brendan Greggf06d3b42015-10-15 17:21:32 -0700100
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800101 return 0;
Brendan Greggf06d3b42015-10-15 17:21:32 -0700102};
103
104static int trace_connect_return(struct pt_regs *ctx, short ipver)
105{
Naveen N. Rao4afa96a2016-05-03 14:54:21 +0530106 int ret = PT_REGS_RC(ctx);
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800107 u32 pid = bpf_get_current_pid_tgid();
Brendan Greggf06d3b42015-10-15 17:21:32 -0700108
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800109 struct sock **skpp;
110 skpp = currsock.lookup(&pid);
111 if (skpp == 0) {
112 return 0; // missed entry
113 }
Brendan Greggf06d3b42015-10-15 17:21:32 -0700114
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800115 if (ret != 0) {
116 // failed to send SYNC packet, may not have populated
117 // socket __sk_common.{skc_rcv_saddr, ...}
118 currsock.delete(&pid);
119 return 0;
120 }
Brendan Greggf06d3b42015-10-15 17:21:32 -0700121
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800122 // pull in details
123 struct sock *skp = *skpp;
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200124 u16 dport = skp->__sk_common.skc_dport;
Brendan Greggf06d3b42015-10-15 17:21:32 -0700125
chantra52938052016-09-10 09:44:50 -0700126 FILTER_PORT
127
Brendan Gregg24825522016-02-14 16:32:29 -0800128 if (ipver == 4) {
129 struct ipv4_data_t data4 = {.pid = pid, .ip = ipver};
Takuma Kumeb181a8e2019-01-10 05:49:59 +0900130 data4.uid = bpf_get_current_uid_gid();
Brendan Gregg24825522016-02-14 16:32:29 -0800131 data4.ts_us = bpf_ktime_get_ns() / 1000;
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200132 data4.saddr = skp->__sk_common.skc_rcv_saddr;
133 data4.daddr = skp->__sk_common.skc_daddr;
Brendan Gregg24825522016-02-14 16:32:29 -0800134 data4.dport = ntohs(dport);
135 bpf_get_current_comm(&data4.task, sizeof(data4.task));
136 ipv4_events.perf_submit(ctx, &data4, sizeof(data4));
137
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800138 } else /* 6 */ {
Brendan Gregg24825522016-02-14 16:32:29 -0800139 struct ipv6_data_t data6 = {.pid = pid, .ip = ipver};
Takuma Kumeb181a8e2019-01-10 05:49:59 +0900140 data6.uid = bpf_get_current_uid_gid();
Brendan Gregg24825522016-02-14 16:32:29 -0800141 data6.ts_us = bpf_ktime_get_ns() / 1000;
Mark Drayton11de2982016-06-26 21:14:44 +0100142 bpf_probe_read(&data6.saddr, sizeof(data6.saddr),
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200143 skp->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
Mark Drayton11de2982016-06-26 21:14:44 +0100144 bpf_probe_read(&data6.daddr, sizeof(data6.daddr),
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200145 skp->__sk_common.skc_v6_daddr.in6_u.u6_addr32);
Brendan Gregg24825522016-02-14 16:32:29 -0800146 data6.dport = ntohs(dport);
147 bpf_get_current_comm(&data6.task, sizeof(data6.task));
148 ipv6_events.perf_submit(ctx, &data6, sizeof(data6));
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800149 }
Brendan Greggf06d3b42015-10-15 17:21:32 -0700150
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800151 currsock.delete(&pid);
Brendan Greggf06d3b42015-10-15 17:21:32 -0700152
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800153 return 0;
Brendan Greggf06d3b42015-10-15 17:21:32 -0700154}
155
156int trace_connect_v4_return(struct pt_regs *ctx)
157{
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800158 return trace_connect_return(ctx, 4);
Brendan Greggf06d3b42015-10-15 17:21:32 -0700159}
160
161int trace_connect_v6_return(struct pt_regs *ctx)
162{
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800163 return trace_connect_return(ctx, 6);
Brendan Greggf06d3b42015-10-15 17:21:32 -0700164}
165"""
166
167# code substitutions
168if args.pid:
chantra52938052016-09-10 09:44:50 -0700169 bpf_text = bpf_text.replace('FILTER_PID',
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800170 'if (pid != %s) { return 0; }' % args.pid)
chantra52938052016-09-10 09:44:50 -0700171if args.port:
172 dports = [int(dport) for dport in args.port.split(',')]
173 dports_if = ' && '.join(['dport != %d' % ntohs(dport) for dport in dports])
174 bpf_text = bpf_text.replace('FILTER_PORT',
175 'if (%s) { currsock.delete(&pid); return 0; }' % dports_if)
Takuma Kumeb181a8e2019-01-10 05:49:59 +0900176if args.uid:
177 bpf_text = bpf_text.replace('FILTER_UID',
178 'if (uid != %s) { return 0; }' % args.uid)
chantra52938052016-09-10 09:44:50 -0700179
180bpf_text = bpf_text.replace('FILTER_PID', '')
181bpf_text = bpf_text.replace('FILTER_PORT', '')
Takuma Kumeb181a8e2019-01-10 05:49:59 +0900182bpf_text = bpf_text.replace('FILTER_UID', '')
chantra52938052016-09-10 09:44:50 -0700183
Nathan Scottcf0792f2018-02-02 16:56:50 +1100184if debug or args.ebpf:
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800185 print(bpf_text)
Nathan Scottcf0792f2018-02-02 16:56:50 +1100186 if args.ebpf:
187 exit()
Brendan Greggf06d3b42015-10-15 17:21:32 -0700188
Brendan Gregg24825522016-02-14 16:32:29 -0800189# process event
190def print_ipv4_event(cpu, data, size):
Xiaozhou Liu31563032019-02-14 14:33:58 +0800191 event = b["ipv4_events"].event(data)
Mark Drayton11de2982016-06-26 21:14:44 +0100192 global start_ts
Brendan Gregg24825522016-02-14 16:32:29 -0800193 if args.timestamp:
194 if start_ts == 0:
195 start_ts = event.ts_us
Mark Drayton11de2982016-06-26 21:14:44 +0100196 print("%-9.3f" % ((float(event.ts_us) - start_ts) / 1000000), end="")
Takuma Kumeb181a8e2019-01-10 05:49:59 +0900197 if args.print_uid:
198 print("%-6d" % event.uid, end="")
japrocaed9b1e2019-01-04 20:21:46 +0300199 printb(b"%-6d %-12.12s %-2d %-16s %-16s %-4d" % (event.pid,
Yonghong Songebe19512019-01-10 14:54:16 -0800200 event.task, event.ip,
201 inet_ntop(AF_INET, pack("I", event.saddr)).encode(),
202 inet_ntop(AF_INET, pack("I", event.daddr)).encode(), event.dport))
Brendan Gregg9e0b0872016-03-28 12:11:45 -0700203
Brendan Gregg24825522016-02-14 16:32:29 -0800204def print_ipv6_event(cpu, data, size):
Xiaozhou Liu31563032019-02-14 14:33:58 +0800205 event = b["ipv6_events"].event(data)
Mark Drayton11de2982016-06-26 21:14:44 +0100206 global start_ts
Brendan Gregg24825522016-02-14 16:32:29 -0800207 if args.timestamp:
208 if start_ts == 0:
209 start_ts = event.ts_us
Mark Drayton11de2982016-06-26 21:14:44 +0100210 print("%-9.3f" % ((float(event.ts_us) - start_ts) / 1000000), end="")
Takuma Kumeb181a8e2019-01-10 05:49:59 +0900211 if args.print_uid:
212 print("%-6d" % event.uid, end="")
japrocaed9b1e2019-01-04 20:21:46 +0300213 printb(b"%-6d %-12.12s %-2d %-16s %-16s %-4d" % (event.pid,
Yonghong Songebe19512019-01-10 14:54:16 -0800214 event.task, event.ip,
215 inet_ntop(AF_INET6, event.saddr).encode(), inet_ntop(AF_INET6, event.daddr).encode(),
jeromemarchandb96ebcd2018-10-10 01:58:15 +0200216 event.dport))
Brendan Gregg24825522016-02-14 16:32:29 -0800217
Brendan Greggf06d3b42015-10-15 17:21:32 -0700218# initialize BPF
219b = BPF(text=bpf_text)
220b.attach_kprobe(event="tcp_v4_connect", fn_name="trace_connect_entry")
221b.attach_kprobe(event="tcp_v6_connect", fn_name="trace_connect_entry")
222b.attach_kretprobe(event="tcp_v4_connect", fn_name="trace_connect_v4_return")
223b.attach_kretprobe(event="tcp_v6_connect", fn_name="trace_connect_v6_return")
224
225# header
226if args.timestamp:
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800227 print("%-9s" % ("TIME(s)"), end="")
Takuma Kumeb181a8e2019-01-10 05:49:59 +0900228if args.print_uid:
229 print("%-6s" % ("UID"), end="")
Brendan Greggf06d3b42015-10-15 17:21:32 -0700230print("%-6s %-12s %-2s %-16s %-16s %-4s" % ("PID", "COMM", "IP", "SADDR",
231 "DADDR", "DPORT"))
232
233start_ts = 0
234
Brendan Gregg24825522016-02-14 16:32:29 -0800235# read events
236b["ipv4_events"].open_perf_buffer(print_ipv4_event)
237b["ipv6_events"].open_perf_buffer(print_ipv6_event)
Brendan Greggf06d3b42015-10-15 17:21:32 -0700238while 1:
Jerome Marchand51671272018-12-19 01:57:24 +0100239 try:
240 b.perf_buffer_poll()
241 except KeyboardInterrupt:
242 exit()