blob: ac84326a6586a8ec6416dd4e2531aacac0e9ff81 [file] [log] [blame]
Brendan Greggf06d3b42015-10-15 17:21:32 -07001#!/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.
Brendan Greggf06d3b42015-10-15 17:21:32 -070019
20from __future__ import print_function
21from bcc import BPF
22import argparse
chantra52938052016-09-10 09:44:50 -070023from socket import inet_ntop, ntohs, AF_INET, AF_INET6
Mark Drayton11de2982016-06-26 21:14:44 +010024from struct import pack
Brendan Gregg24825522016-02-14 16:32:29 -080025import ctypes as ct
Brendan Greggf06d3b42015-10-15 17:21:32 -070026
27# arguments
28examples = """examples:
29 ./tcpconnect # trace all TCP connect()s
30 ./tcpconnect -t # include timestamps
31 ./tcpconnect -p 181 # only trace PID 181
chantra52938052016-09-10 09:44:50 -070032 ./tcpconnect -P 80 # only trace port 80
33 ./tcpconnect -P 80,81 # only trace port 80 and 81
Brendan Greggf06d3b42015-10-15 17:21:32 -070034"""
35parser = argparse.ArgumentParser(
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080036 description="Trace TCP connects",
37 formatter_class=argparse.RawDescriptionHelpFormatter,
38 epilog=examples)
Brendan Greggf06d3b42015-10-15 17:21:32 -070039parser.add_argument("-t", "--timestamp", action="store_true",
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080040 help="include timestamp on output")
Brendan Greggf06d3b42015-10-15 17:21:32 -070041parser.add_argument("-p", "--pid",
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080042 help="trace this PID only")
chantra52938052016-09-10 09:44:50 -070043parser.add_argument("-P", "--port",
44 help="comma-separated list of destination ports to trace.")
Nathan Scottcf0792f2018-02-02 16:56:50 +110045parser.add_argument("--ebpf", action="store_true",
46 help=argparse.SUPPRESS)
Brendan Greggf06d3b42015-10-15 17:21:32 -070047args = parser.parse_args()
48debug = 0
49
50# define BPF program
51bpf_text = """
52#include <uapi/linux/ptrace.h>
53#include <net/sock.h>
54#include <bcc/proto.h>
55
56BPF_HASH(currsock, u32, struct sock *);
57
Brendan Gregg24825522016-02-14 16:32:29 -080058// separate data structs for ipv4 and ipv6
59struct ipv4_data_t {
Brendan Gregg24825522016-02-14 16:32:29 -080060 u64 ts_us;
Joe Yin36ce1122018-08-17 06:04:00 +080061 u32 pid;
62 u32 saddr;
63 u32 daddr;
Mark Drayton11de2982016-06-26 21:14:44 +010064 u64 ip;
Joe Yin36ce1122018-08-17 06:04:00 +080065 u16 dport;
Brendan Gregg24825522016-02-14 16:32:29 -080066 char task[TASK_COMM_LEN];
67};
68BPF_PERF_OUTPUT(ipv4_events);
69
70struct ipv6_data_t {
Brendan Gregg24825522016-02-14 16:32:29 -080071 u64 ts_us;
Joe Yin36ce1122018-08-17 06:04:00 +080072 u32 pid;
Mark Drayton11de2982016-06-26 21:14:44 +010073 unsigned __int128 saddr;
74 unsigned __int128 daddr;
Brendan Gregg24825522016-02-14 16:32:29 -080075 u64 ip;
Joe Yin36ce1122018-08-17 06:04:00 +080076 u16 dport;
Brendan Gregg24825522016-02-14 16:32:29 -080077 char task[TASK_COMM_LEN];
78};
79BPF_PERF_OUTPUT(ipv6_events);
80
Brendan Greggf06d3b42015-10-15 17:21:32 -070081int trace_connect_entry(struct pt_regs *ctx, struct sock *sk)
82{
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080083 u32 pid = bpf_get_current_pid_tgid();
chantra52938052016-09-10 09:44:50 -070084 FILTER_PID
Brendan Greggf06d3b42015-10-15 17:21:32 -070085
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080086 // stash the sock ptr for lookup on return
87 currsock.update(&pid, &sk);
Brendan Greggf06d3b42015-10-15 17:21:32 -070088
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080089 return 0;
Brendan Greggf06d3b42015-10-15 17:21:32 -070090};
91
92static int trace_connect_return(struct pt_regs *ctx, short ipver)
93{
Naveen N. Rao4afa96a2016-05-03 14:54:21 +053094 int ret = PT_REGS_RC(ctx);
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080095 u32 pid = bpf_get_current_pid_tgid();
Brendan Greggf06d3b42015-10-15 17:21:32 -070096
Alexei Starovoitovbdf07732016-01-14 10:09:20 -080097 struct sock **skpp;
98 skpp = currsock.lookup(&pid);
99 if (skpp == 0) {
100 return 0; // missed entry
101 }
Brendan Greggf06d3b42015-10-15 17:21:32 -0700102
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800103 if (ret != 0) {
104 // failed to send SYNC packet, may not have populated
105 // socket __sk_common.{skc_rcv_saddr, ...}
106 currsock.delete(&pid);
107 return 0;
108 }
Brendan Greggf06d3b42015-10-15 17:21:32 -0700109
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800110 // pull in details
111 struct sock *skp = *skpp;
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200112 u16 dport = skp->__sk_common.skc_dport;
Brendan Greggf06d3b42015-10-15 17:21:32 -0700113
chantra52938052016-09-10 09:44:50 -0700114 FILTER_PORT
115
Brendan Gregg24825522016-02-14 16:32:29 -0800116 if (ipver == 4) {
117 struct ipv4_data_t data4 = {.pid = pid, .ip = ipver};
118 data4.ts_us = bpf_ktime_get_ns() / 1000;
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200119 data4.saddr = skp->__sk_common.skc_rcv_saddr;
120 data4.daddr = skp->__sk_common.skc_daddr;
Brendan Gregg24825522016-02-14 16:32:29 -0800121 data4.dport = ntohs(dport);
122 bpf_get_current_comm(&data4.task, sizeof(data4.task));
123 ipv4_events.perf_submit(ctx, &data4, sizeof(data4));
124
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800125 } else /* 6 */ {
Brendan Gregg24825522016-02-14 16:32:29 -0800126 struct ipv6_data_t data6 = {.pid = pid, .ip = ipver};
127 data6.ts_us = bpf_ktime_get_ns() / 1000;
Mark Drayton11de2982016-06-26 21:14:44 +0100128 bpf_probe_read(&data6.saddr, sizeof(data6.saddr),
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200129 skp->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
Mark Drayton11de2982016-06-26 21:14:44 +0100130 bpf_probe_read(&data6.daddr, sizeof(data6.daddr),
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200131 skp->__sk_common.skc_v6_daddr.in6_u.u6_addr32);
Brendan Gregg24825522016-02-14 16:32:29 -0800132 data6.dport = ntohs(dport);
133 bpf_get_current_comm(&data6.task, sizeof(data6.task));
134 ipv6_events.perf_submit(ctx, &data6, sizeof(data6));
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800135 }
Brendan Greggf06d3b42015-10-15 17:21:32 -0700136
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800137 currsock.delete(&pid);
Brendan Greggf06d3b42015-10-15 17:21:32 -0700138
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800139 return 0;
Brendan Greggf06d3b42015-10-15 17:21:32 -0700140}
141
142int trace_connect_v4_return(struct pt_regs *ctx)
143{
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800144 return trace_connect_return(ctx, 4);
Brendan Greggf06d3b42015-10-15 17:21:32 -0700145}
146
147int trace_connect_v6_return(struct pt_regs *ctx)
148{
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800149 return trace_connect_return(ctx, 6);
Brendan Greggf06d3b42015-10-15 17:21:32 -0700150}
151"""
152
153# code substitutions
154if args.pid:
chantra52938052016-09-10 09:44:50 -0700155 bpf_text = bpf_text.replace('FILTER_PID',
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800156 'if (pid != %s) { return 0; }' % args.pid)
chantra52938052016-09-10 09:44:50 -0700157if args.port:
158 dports = [int(dport) for dport in args.port.split(',')]
159 dports_if = ' && '.join(['dport != %d' % ntohs(dport) for dport in dports])
160 bpf_text = bpf_text.replace('FILTER_PORT',
161 'if (%s) { currsock.delete(&pid); return 0; }' % dports_if)
162
163bpf_text = bpf_text.replace('FILTER_PID', '')
164bpf_text = bpf_text.replace('FILTER_PORT', '')
165
Nathan Scottcf0792f2018-02-02 16:56:50 +1100166if debug or args.ebpf:
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800167 print(bpf_text)
Nathan Scottcf0792f2018-02-02 16:56:50 +1100168 if args.ebpf:
169 exit()
Brendan Greggf06d3b42015-10-15 17:21:32 -0700170
Brendan Gregg24825522016-02-14 16:32:29 -0800171# event data
172TASK_COMM_LEN = 16 # linux/sched.h
Mark Drayton11de2982016-06-26 21:14:44 +0100173
Brendan Gregg24825522016-02-14 16:32:29 -0800174class Data_ipv4(ct.Structure):
175 _fields_ = [
176 ("ts_us", ct.c_ulonglong),
Joe Yin36ce1122018-08-17 06:04:00 +0800177 ("pid", ct.c_uint),
178 ("saddr", ct.c_uint),
179 ("daddr", ct.c_uint),
Mark Drayton11de2982016-06-26 21:14:44 +0100180 ("ip", ct.c_ulonglong),
Joe Yin36ce1122018-08-17 06:04:00 +0800181 ("dport", ct.c_ushort),
Brendan Gregg24825522016-02-14 16:32:29 -0800182 ("task", ct.c_char * TASK_COMM_LEN)
183 ]
Mark Drayton11de2982016-06-26 21:14:44 +0100184
Brendan Gregg24825522016-02-14 16:32:29 -0800185class Data_ipv6(ct.Structure):
186 _fields_ = [
187 ("ts_us", ct.c_ulonglong),
Joe Yin36ce1122018-08-17 06:04:00 +0800188 ("pid", ct.c_uint),
Mark Drayton11de2982016-06-26 21:14:44 +0100189 ("saddr", (ct.c_ulonglong * 2)),
190 ("daddr", (ct.c_ulonglong * 2)),
Brendan Gregg24825522016-02-14 16:32:29 -0800191 ("ip", ct.c_ulonglong),
Joe Yin36ce1122018-08-17 06:04:00 +0800192 ("dport", ct.c_ushort),
Brendan Gregg24825522016-02-14 16:32:29 -0800193 ("task", ct.c_char * TASK_COMM_LEN)
194 ]
195
196# process event
197def print_ipv4_event(cpu, data, size):
198 event = ct.cast(data, ct.POINTER(Data_ipv4)).contents
Mark Drayton11de2982016-06-26 21:14:44 +0100199 global start_ts
Brendan Gregg24825522016-02-14 16:32:29 -0800200 if args.timestamp:
201 if start_ts == 0:
202 start_ts = event.ts_us
Mark Drayton11de2982016-06-26 21:14:44 +0100203 print("%-9.3f" % ((float(event.ts_us) - start_ts) / 1000000), end="")
Rafael F78948e42017-03-26 14:54:25 +0200204 print("%-6d %-12.12s %-2d %-16s %-16s %-4d" % (event.pid,
jeromemarchandb96ebcd2018-10-10 01:58:15 +0200205 event.task.decode('utf-8', 'replace'), event.ip,
Rafael F78948e42017-03-26 14:54:25 +0200206 inet_ntop(AF_INET, pack("I", event.saddr)),
Mark Drayton11de2982016-06-26 21:14:44 +0100207 inet_ntop(AF_INET, pack("I", event.daddr)), event.dport))
Brendan Gregg9e0b0872016-03-28 12:11:45 -0700208
Brendan Gregg24825522016-02-14 16:32:29 -0800209def print_ipv6_event(cpu, data, size):
210 event = ct.cast(data, ct.POINTER(Data_ipv6)).contents
Mark Drayton11de2982016-06-26 21:14:44 +0100211 global start_ts
Brendan Gregg24825522016-02-14 16:32:29 -0800212 if args.timestamp:
213 if start_ts == 0:
214 start_ts = event.ts_us
Mark Drayton11de2982016-06-26 21:14:44 +0100215 print("%-9.3f" % ((float(event.ts_us) - start_ts) / 1000000), end="")
Brendan Gregg9e0b0872016-03-28 12:11:45 -0700216 print("%-6d %-12.12s %-2d %-16s %-16s %-4d" % (event.pid,
jeromemarchandb96ebcd2018-10-10 01:58:15 +0200217 event.task.decode('utf-8', 'replace'), event.ip,
218 inet_ntop(AF_INET6, event.saddr), inet_ntop(AF_INET6, event.daddr),
219 event.dport))
Brendan Gregg24825522016-02-14 16:32:29 -0800220
Brendan Greggf06d3b42015-10-15 17:21:32 -0700221# initialize BPF
222b = BPF(text=bpf_text)
223b.attach_kprobe(event="tcp_v4_connect", fn_name="trace_connect_entry")
224b.attach_kprobe(event="tcp_v6_connect", fn_name="trace_connect_entry")
225b.attach_kretprobe(event="tcp_v4_connect", fn_name="trace_connect_v4_return")
226b.attach_kretprobe(event="tcp_v6_connect", fn_name="trace_connect_v6_return")
227
228# header
229if args.timestamp:
Alexei Starovoitovbdf07732016-01-14 10:09:20 -0800230 print("%-9s" % ("TIME(s)"), end="")
Brendan Greggf06d3b42015-10-15 17:21:32 -0700231print("%-6s %-12s %-2s %-16s %-16s %-4s" % ("PID", "COMM", "IP", "SADDR",
232 "DADDR", "DPORT"))
233
234start_ts = 0
235
Brendan Gregg24825522016-02-14 16:32:29 -0800236# read events
237b["ipv4_events"].open_perf_buffer(print_ipv4_event)
238b["ipv6_events"].open_perf_buffer(print_ipv6_event)
Brendan Greggf06d3b42015-10-15 17:21:32 -0700239while 1:
Teng Qindbf00292018-02-28 21:47:50 -0800240 b.perf_buffer_poll()