blob: 5bec83c313ab4de852745771b5c9b5595d922474 [file] [log] [blame]
Iago López Galeirasf37434b2017-03-30 19:07:47 +02001#!/usr/bin/python
2#
3# tcpv4tracer Trace TCP connections.
4# For Linux, uses BCC, eBPF. Embedded C.
5#
6# USAGE: tcpv4tracer [-h] [-v] [-p PID] [-N NETNS]
7#
8# You should generally try to avoid writing long scripts that measure multiple
9# functions and walk multiple kernel structures, as they will be a burden to
10# maintain as the kernel changes.
11# The following code should be replaced, and simplified, when static TCP probes
12# exist.
13#
14# Copyright 2017 Kinvolk GmbH
15#
16# Licensed under the Apache License, Version 2.0 (the "License")
17from __future__ import print_function
18from bcc import BPF
19
20import argparse as ap
21import ctypes
22from socket import inet_ntop, AF_INET, AF_INET6
23from struct import pack
24
25parser = ap.ArgumentParser(description="Trace TCP connections",
26 formatter_class=ap.RawDescriptionHelpFormatter)
Iago López Galeiras6426cd42017-08-04 16:57:20 +020027parser.add_argument("-t", "--timestamp", action="store_true",
28 help="include timestamp on output")
Iago López Galeirasf37434b2017-03-30 19:07:47 +020029parser.add_argument("-p", "--pid", default=0, type=int,
30 help="trace this PID only")
31parser.add_argument("-N", "--netns", default=0, type=int,
32 help="trace this Network Namespace only")
33parser.add_argument("-v", "--verbose", action="store_true",
34 help="include Network Namespace in the output")
Nathan Scottcf0792f2018-02-02 16:56:50 +110035parser.add_argument("--ebpf", action="store_true",
Gal Pressman1980d632018-02-05 14:55:53 +020036 help=ap.SUPPRESS)
Iago López Galeirasf37434b2017-03-30 19:07:47 +020037args = parser.parse_args()
38
39bpf_text = """
40#include <uapi/linux/ptrace.h>
41#pragma clang diagnostic push
42#pragma clang diagnostic ignored "-Wtautological-compare"
43#include <net/sock.h>
44#pragma clang diagnostic pop
45#include <net/inet_sock.h>
46#include <net/net_namespace.h>
47#include <bcc/proto.h>
48
49#define TCP_EVENT_TYPE_CONNECT 1
50#define TCP_EVENT_TYPE_ACCEPT 2
51#define TCP_EVENT_TYPE_CLOSE 3
52
53struct tcp_ipv4_event_t {
Iago López Galeirasfff792d2017-08-04 18:13:05 +020054 u64 ts_ns;
Iago López Galeirasf37434b2017-03-30 19:07:47 +020055 u32 type;
56 u32 pid;
57 char comm[TASK_COMM_LEN];
58 u8 ip;
59 u32 saddr;
60 u32 daddr;
61 u16 sport;
62 u16 dport;
63 u32 netns;
64};
65BPF_PERF_OUTPUT(tcp_ipv4_event);
66
67struct tcp_ipv6_event_t {
Iago López Galeirasfff792d2017-08-04 18:13:05 +020068 u64 ts_ns;
Iago López Galeirasf37434b2017-03-30 19:07:47 +020069 u32 type;
70 u32 pid;
71 char comm[TASK_COMM_LEN];
72 u8 ip;
73 unsigned __int128 saddr;
74 unsigned __int128 daddr;
75 u16 sport;
76 u16 dport;
77 u32 netns;
78};
79BPF_PERF_OUTPUT(tcp_ipv6_event);
80
81// tcp_set_state doesn't run in the context of the process that initiated the
82// connection so we need to store a map TUPLE -> PID to send the right PID on
83// the event
84struct ipv4_tuple_t {
85 u32 saddr;
86 u32 daddr;
87 u16 sport;
88 u16 dport;
89 u32 netns;
90};
91
92struct ipv6_tuple_t {
93 unsigned __int128 saddr;
94 unsigned __int128 daddr;
95 u16 sport;
96 u16 dport;
97 u32 netns;
98};
99
100struct pid_comm_t {
101 u64 pid;
102 char comm[TASK_COMM_LEN];
103};
104
105BPF_HASH(tuplepid_ipv4, struct ipv4_tuple_t, struct pid_comm_t);
106BPF_HASH(tuplepid_ipv6, struct ipv6_tuple_t, struct pid_comm_t);
107
108BPF_HASH(connectsock, u64, struct sock *);
109
110static int read_ipv4_tuple(struct ipv4_tuple_t *tuple, struct sock *skp)
111{
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200112 u32 net_ns_inum = 0;
113 u32 saddr = skp->__sk_common.skc_rcv_saddr;
114 u32 daddr = skp->__sk_common.skc_daddr;
115 struct inet_sock *sockp = (struct inet_sock *)skp;
116 u16 sport = sockp->inet_sport;
117 u16 dport = skp->__sk_common.skc_dport;
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200118#ifdef CONFIG_NET_NS
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200119 possible_net_t skc_net = skp->__sk_common.skc_net;
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200120 bpf_probe_read(&net_ns_inum, sizeof(net_ns_inum), &skc_net.net->ns.inum);
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200121#endif
122
123 ##FILTER_NETNS##
124
125 tuple->saddr = saddr;
126 tuple->daddr = daddr;
127 tuple->sport = sport;
128 tuple->dport = dport;
129 tuple->netns = net_ns_inum;
130
131 // if addresses or ports are 0, ignore
132 if (saddr == 0 || daddr == 0 || sport == 0 || dport == 0) {
133 return 0;
134 }
135
136 return 1;
137}
138
139static int read_ipv6_tuple(struct ipv6_tuple_t *tuple, struct sock *skp)
140{
141 u32 net_ns_inum = 0;
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200142 unsigned __int128 saddr = 0, daddr = 0;
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200143 struct inet_sock *sockp = (struct inet_sock *)skp;
144 u16 sport = sockp->inet_sport;
145 u16 dport = skp->__sk_common.skc_dport;
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200146#ifdef CONFIG_NET_NS
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200147 possible_net_t skc_net = skp->__sk_common.skc_net;
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200148 bpf_probe_read(&net_ns_inum, sizeof(net_ns_inum), &skc_net.net->ns.inum);
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200149#endif
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200150 bpf_probe_read(&saddr, sizeof(saddr),
151 skp->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
152 bpf_probe_read(&daddr, sizeof(daddr),
153 skp->__sk_common.skc_v6_daddr.in6_u.u6_addr32);
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200154
155 ##FILTER_NETNS##
156
157 tuple->saddr = saddr;
158 tuple->daddr = daddr;
159 tuple->sport = sport;
160 tuple->dport = dport;
161 tuple->netns = net_ns_inum;
162
163 // if addresses or ports are 0, ignore
164 if (saddr == 0 || daddr == 0 || sport == 0 || dport == 0) {
165 return 0;
166 }
167
168 return 1;
169}
170
171static bool check_family(struct sock *sk, u16 expected_family) {
172 u64 zero = 0;
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200173 u16 family = sk->__sk_common.skc_family;
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200174 return family == expected_family;
175}
176
177int trace_connect_v4_entry(struct pt_regs *ctx, struct sock *sk)
178{
179 u64 pid = bpf_get_current_pid_tgid();
180
181 ##FILTER_PID##
182
183 // stash the sock ptr for lookup on return
184 connectsock.update(&pid, &sk);
185
186 return 0;
187}
188
189int trace_connect_v4_return(struct pt_regs *ctx)
190{
191 int ret = PT_REGS_RC(ctx);
192 u64 pid = bpf_get_current_pid_tgid();
193
194 struct sock **skpp;
195 skpp = connectsock.lookup(&pid);
196 if (skpp == 0) {
197 return 0; // missed entry
198 }
199
200 connectsock.delete(&pid);
201
202 if (ret != 0) {
203 // failed to send SYNC packet, may not have populated
204 // socket __sk_common.{skc_rcv_saddr, ...}
205 return 0;
206 }
207
208 // pull in details
209 struct sock *skp = *skpp;
210 struct ipv4_tuple_t t = { };
211 if (!read_ipv4_tuple(&t, skp)) {
212 return 0;
213 }
214
215 struct pid_comm_t p = { };
216 p.pid = pid;
217 bpf_get_current_comm(&p.comm, sizeof(p.comm));
218
219 tuplepid_ipv4.update(&t, &p);
220
221 return 0;
222}
223
224int trace_connect_v6_entry(struct pt_regs *ctx, struct sock *sk)
225{
226 u64 pid = bpf_get_current_pid_tgid();
227
228 ##FILTER_PID##
229
230 // stash the sock ptr for lookup on return
231 connectsock.update(&pid, &sk);
232
233 return 0;
234}
235
236int trace_connect_v6_return(struct pt_regs *ctx)
237{
238 int ret = PT_REGS_RC(ctx);
239 u64 pid = bpf_get_current_pid_tgid();
240
241 struct sock **skpp;
242 skpp = connectsock.lookup(&pid);
243 if (skpp == 0) {
244 return 0; // missed entry
245 }
246
247 connectsock.delete(&pid);
248
249 if (ret != 0) {
250 // failed to send SYNC packet, may not have populated
251 // socket __sk_common.{skc_rcv_saddr, ...}
252 return 0;
253 }
254
255 // pull in details
256 struct sock *skp = *skpp;
257 struct ipv6_tuple_t t = { };
258 if (!read_ipv6_tuple(&t, skp)) {
259 return 0;
260 }
261
262 struct pid_comm_t p = { };
263 p.pid = pid;
264 bpf_get_current_comm(&p.comm, sizeof(p.comm));
265
266 tuplepid_ipv6.update(&t, &p);
267
268 return 0;
269}
270
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200271int trace_tcp_set_state_entry(struct pt_regs *ctx, struct sock *skp, int state)
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200272{
273 if (state != TCP_ESTABLISHED && state != TCP_CLOSE) {
274 return 0;
275 }
276
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200277 u8 ipver = 0;
278 if (check_family(skp, AF_INET)) {
279 ipver = 4;
280 struct ipv4_tuple_t t = { };
281 if (!read_ipv4_tuple(&t, skp)) {
282 return 0;
283 }
284
285 if (state == TCP_CLOSE) {
286 tuplepid_ipv4.delete(&t);
287 return 0;
288 }
289
290 struct pid_comm_t *p;
291 p = tuplepid_ipv4.lookup(&t);
292 if (p == 0) {
293 return 0; // missed entry
294 }
295
296 struct tcp_ipv4_event_t evt4 = { };
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200297 evt4.ts_ns = bpf_ktime_get_ns();
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200298 evt4.type = TCP_EVENT_TYPE_CONNECT;
299 evt4.pid = p->pid >> 32;
300 evt4.ip = ipver;
301 evt4.saddr = t.saddr;
302 evt4.daddr = t.daddr;
303 evt4.sport = ntohs(t.sport);
304 evt4.dport = ntohs(t.dport);
305 evt4.netns = t.netns;
306
307 int i;
308 for (i = 0; i < TASK_COMM_LEN; i++) {
309 evt4.comm[i] = p->comm[i];
310 }
311
312 tcp_ipv4_event.perf_submit(ctx, &evt4, sizeof(evt4));
313 tuplepid_ipv4.delete(&t);
314 } else if (check_family(skp, AF_INET6)) {
315 ipver = 6;
316 struct ipv6_tuple_t t = { };
317 if (!read_ipv6_tuple(&t, skp)) {
318 return 0;
319 }
320
321 if (state == TCP_CLOSE) {
322 tuplepid_ipv6.delete(&t);
323 return 0;
324 }
325
326 struct pid_comm_t *p;
327 p = tuplepid_ipv6.lookup(&t);
328 if (p == 0) {
329 return 0; // missed entry
330 }
331
332 struct tcp_ipv6_event_t evt6 = { };
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200333 evt6.ts_ns = bpf_ktime_get_ns();
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200334 evt6.type = TCP_EVENT_TYPE_CONNECT;
335 evt6.pid = p->pid >> 32;
336 evt6.ip = ipver;
337 evt6.saddr = t.saddr;
338 evt6.daddr = t.daddr;
339 evt6.sport = ntohs(t.sport);
340 evt6.dport = ntohs(t.dport);
341 evt6.netns = t.netns;
342
343 int i;
344 for (i = 0; i < TASK_COMM_LEN; i++) {
345 evt6.comm[i] = p->comm[i];
346 }
347
348 tcp_ipv6_event.perf_submit(ctx, &evt6, sizeof(evt6));
349 tuplepid_ipv6.delete(&t);
350 }
351 // else drop
352
353 return 0;
354}
355
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200356int trace_close_entry(struct pt_regs *ctx, struct sock *skp)
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200357{
358 u64 pid = bpf_get_current_pid_tgid();
359
360 ##FILTER_PID##
361
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200362 u8 oldstate = skp->sk_state;
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200363 // Don't generate close events for connections that were never
364 // established in the first place.
365 if (oldstate == TCP_SYN_SENT ||
366 oldstate == TCP_SYN_RECV ||
367 oldstate == TCP_NEW_SYN_RECV)
368 return 0;
369
370 u8 ipver = 0;
371 if (check_family(skp, AF_INET)) {
372 ipver = 4;
373 struct ipv4_tuple_t t = { };
374 if (!read_ipv4_tuple(&t, skp)) {
375 return 0;
376 }
377
378 struct tcp_ipv4_event_t evt4 = { };
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200379 evt4.ts_ns = bpf_ktime_get_ns();
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200380 evt4.type = TCP_EVENT_TYPE_CLOSE;
381 evt4.pid = pid >> 32;
382 evt4.ip = ipver;
383 evt4.saddr = t.saddr;
384 evt4.daddr = t.daddr;
385 evt4.sport = ntohs(t.sport);
386 evt4.dport = ntohs(t.dport);
387 evt4.netns = t.netns;
388 bpf_get_current_comm(&evt4.comm, sizeof(evt4.comm));
389
390 tcp_ipv4_event.perf_submit(ctx, &evt4, sizeof(evt4));
391 } else if (check_family(skp, AF_INET6)) {
392 ipver = 6;
393 struct ipv6_tuple_t t = { };
394 if (!read_ipv6_tuple(&t, skp)) {
395 return 0;
396 }
397
398 struct tcp_ipv6_event_t evt6 = { };
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200399 evt6.ts_ns = bpf_ktime_get_ns();
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200400 evt6.type = TCP_EVENT_TYPE_CLOSE;
401 evt6.pid = pid >> 32;
402 evt6.ip = ipver;
403 evt6.saddr = t.saddr;
404 evt6.daddr = t.daddr;
405 evt6.sport = ntohs(t.sport);
406 evt6.dport = ntohs(t.dport);
407 evt6.netns = t.netns;
408 bpf_get_current_comm(&evt6.comm, sizeof(evt6.comm));
409
410 tcp_ipv6_event.perf_submit(ctx, &evt6, sizeof(evt6));
411 }
412 // else drop
413
414 return 0;
415};
416
417int trace_accept_return(struct pt_regs *ctx)
418{
419 struct sock *newsk = (struct sock *)PT_REGS_RC(ctx);
420 u64 pid = bpf_get_current_pid_tgid();
421
422 ##FILTER_PID##
423
424 if (newsk == NULL) {
425 return 0;
426 }
427
428 // pull in details
429 u16 lport = 0, dport = 0;
430 u32 net_ns_inum = 0;
431 u8 ipver = 0;
432
433 bpf_probe_read(&dport, sizeof(dport), &newsk->__sk_common.skc_dport);
434 bpf_probe_read(&lport, sizeof(lport), &newsk->__sk_common.skc_num);
435
436 // Get network namespace id, if kernel supports it
437#ifdef CONFIG_NET_NS
Iago López Galeiras926d6672017-12-12 21:25:25 +0000438 possible_net_t skc_net = { };
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200439 bpf_probe_read(&skc_net, sizeof(skc_net), &newsk->__sk_common.skc_net);
440 bpf_probe_read(&net_ns_inum, sizeof(net_ns_inum), &skc_net.net->ns.inum);
441#else
442 net_ns_inum = 0;
443#endif
444
445 ##FILTER_NETNS##
446
447 if (check_family(newsk, AF_INET)) {
448 ipver = 4;
449
450 struct tcp_ipv4_event_t evt4 = { 0 };
451
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200452 evt4.ts_ns = bpf_ktime_get_ns();
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200453 evt4.type = TCP_EVENT_TYPE_ACCEPT;
454 evt4.netns = net_ns_inum;
455 evt4.pid = pid >> 32;
456 evt4.ip = ipver;
457
458 bpf_probe_read(&evt4.saddr, sizeof(evt4.saddr),
459 &newsk->__sk_common.skc_rcv_saddr);
460 bpf_probe_read(&evt4.daddr, sizeof(evt4.daddr),
461 &newsk->__sk_common.skc_daddr);
462
463 evt4.sport = lport;
464 evt4.dport = ntohs(dport);
465 bpf_get_current_comm(&evt4.comm, sizeof(evt4.comm));
466
467 // do not send event if IP address is 0.0.0.0 or port is 0
468 if (evt4.saddr != 0 && evt4.daddr != 0 &&
469 evt4.sport != 0 && evt4.dport != 0) {
470 tcp_ipv4_event.perf_submit(ctx, &evt4, sizeof(evt4));
471 }
472 } else if (check_family(newsk, AF_INET6)) {
473 ipver = 6;
474
475 struct tcp_ipv6_event_t evt6 = { 0 };
476
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200477 evt6.ts_ns = bpf_ktime_get_ns();
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200478 evt6.type = TCP_EVENT_TYPE_ACCEPT;
479 evt6.netns = net_ns_inum;
480 evt6.pid = pid >> 32;
481 evt6.ip = ipver;
482
483 bpf_probe_read(&evt6.saddr, sizeof(evt6.saddr),
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200484 newsk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200485 bpf_probe_read(&evt6.daddr, sizeof(evt6.daddr),
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200486 newsk->__sk_common.skc_v6_daddr.in6_u.u6_addr32);
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200487
488 evt6.sport = lport;
489 evt6.dport = ntohs(dport);
490 bpf_get_current_comm(&evt6.comm, sizeof(evt6.comm));
491
492 // do not send event if IP address is 0.0.0.0 or port is 0
493 if (evt6.saddr != 0 && evt6.daddr != 0 &&
494 evt6.sport != 0 && evt6.dport != 0) {
495 tcp_ipv6_event.perf_submit(ctx, &evt6, sizeof(evt6));
496 }
497 }
498 // else drop
499
500 return 0;
501}
502"""
503
504TASK_COMM_LEN = 16 # linux/sched.h
505
506
507class TCPIPV4Evt(ctypes.Structure):
508 _fields_ = [
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200509 ("ts_ns", ctypes.c_ulonglong),
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200510 ("type", ctypes.c_uint),
511 ("pid", ctypes.c_uint),
512 ("comm", ctypes.c_char * TASK_COMM_LEN),
513 ("ip", ctypes.c_ubyte),
514 ("saddr", ctypes.c_uint),
515 ("daddr", ctypes.c_uint),
516 ("sport", ctypes.c_ushort),
517 ("dport", ctypes.c_ushort),
518 ("netns", ctypes.c_uint)
519 ]
520
521
522class TCPIPV6Evt(ctypes.Structure):
523 _fields_ = [
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200524 ("ts_ns", ctypes.c_ulonglong),
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200525 ("type", ctypes.c_uint),
526 ("pid", ctypes.c_uint),
527 ("comm", ctypes.c_char * TASK_COMM_LEN),
528 ("ip", ctypes.c_ubyte),
529 ("saddr", (ctypes.c_ulong * 2)),
530 ("daddr", (ctypes.c_ulong * 2)),
531 ("sport", ctypes.c_ushort),
532 ("dport", ctypes.c_ushort),
533 ("netns", ctypes.c_uint)
534 ]
535
536
537verbose_types = {"C": "connect", "A": "accept",
538 "X": "close", "U": "unknown"}
539
540
541def print_ipv4_event(cpu, data, size):
542 event = ctypes.cast(data, ctypes.POINTER(TCPIPV4Evt)).contents
Iago López Galeiras6426cd42017-08-04 16:57:20 +0200543 global start_ts
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200544
Iago López Galeiras6426cd42017-08-04 16:57:20 +0200545 if args.timestamp:
546 if start_ts == 0:
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200547 start_ts = event.ts_ns
548 if args.verbose:
549 print("%-14d" % (event.ts_ns - start_ts), end="")
550 else:
Paul Chaignon7297af02017-10-07 11:06:58 +0200551 print("%-9.3f" % ((event.ts_ns - start_ts) / 1000000000.0), end="")
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200552 if event.type == 1:
553 type_str = "C"
554 elif event.type == 2:
555 type_str = "A"
556 elif event.type == 3:
557 type_str = "X"
558 else:
559 type_str = "U"
560
561 if args.verbose:
562 print("%-12s " % (verbose_types[type_str]), end="")
563 else:
564 print("%-2s " % (type_str), end="")
565
566 print("%-6d %-16s %-2d %-16s %-16s %-6d %-6d" %
567 (event.pid, event.comm.decode('utf-8'),
568 event.ip,
569 inet_ntop(AF_INET, pack("I", event.saddr)),
570 inet_ntop(AF_INET, pack("I", event.daddr)),
571 event.sport,
572 event.dport), end="")
573 if args.verbose and not args.netns:
574 print(" %-8d" % event.netns)
575 else:
576 print()
577
578
579def print_ipv6_event(cpu, data, size):
580 event = ctypes.cast(data, ctypes.POINTER(TCPIPV6Evt)).contents
Iago López Galeiras6426cd42017-08-04 16:57:20 +0200581 global start_ts
582 if args.timestamp:
583 if start_ts == 0:
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200584 start_ts = event.ts_ns
585 if args.verbose:
586 print("%-14d" % (event.ts_ns - start_ts), end="")
587 else:
Paul Chaignon7297af02017-10-07 11:06:58 +0200588 print("%-9.3f" % ((event.ts_ns - start_ts) / 1000000000.0), end="")
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200589 if event.type == 1:
590 type_str = "C"
591 elif event.type == 2:
592 type_str = "A"
593 elif event.type == 3:
594 type_str = "X"
595 else:
596 type_str = "U"
597
598 if args.verbose:
599 print("%-12s " % (verbose_types[type_str]), end="")
600 else:
601 print("%-2s " % (type_str), end="")
602
603 print("%-6d %-16s %-2d %-16s %-16s %-6d %-6d" %
604 (event.pid, event.comm.decode('utf-8'),
605 event.ip,
Paul Chaignon7297af02017-10-07 11:06:58 +0200606 "[" + inet_ntop(AF_INET6, event.saddr) + "]",
607 "[" + inet_ntop(AF_INET6, event.daddr) + "]",
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200608 event.sport,
609 event.dport), end="")
610 if args.verbose and not args.netns:
611 print(" %-8d" % event.netns)
612 else:
613 print()
614
615
616pid_filter = ""
617netns_filter = ""
618
619if args.pid:
620 pid_filter = 'if (pid >> 32 != %d) { return 0; }' % args.pid
621if args.netns:
622 netns_filter = 'if (net_ns_inum != %d) { return 0; }' % args.netns
623
624bpf_text = bpf_text.replace('##FILTER_PID##', pid_filter)
625bpf_text = bpf_text.replace('##FILTER_NETNS##', netns_filter)
626
Nathan Scottcf0792f2018-02-02 16:56:50 +1100627if args.ebpf:
628 print(bpf_text)
629 exit()
630
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200631# initialize BPF
632b = BPF(text=bpf_text)
633b.attach_kprobe(event="tcp_v4_connect", fn_name="trace_connect_v4_entry")
634b.attach_kretprobe(event="tcp_v4_connect", fn_name="trace_connect_v4_return")
635b.attach_kprobe(event="tcp_v6_connect", fn_name="trace_connect_v6_entry")
636b.attach_kretprobe(event="tcp_v6_connect", fn_name="trace_connect_v6_return")
637b.attach_kprobe(event="tcp_set_state", fn_name="trace_tcp_set_state_entry")
638b.attach_kprobe(event="tcp_close", fn_name="trace_close_entry")
639b.attach_kretprobe(event="inet_csk_accept", fn_name="trace_accept_return")
640
641print("Tracing TCP established connections. Ctrl-C to end.")
642
643# header
644if args.verbose:
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200645 if args.timestamp:
646 print("%-14s" % ("TIME(ns)"), end="")
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200647 print("%-12s %-6s %-16s %-2s %-16s %-16s %-6s %-7s" % ("TYPE",
648 "PID", "COMM", "IP", "SADDR", "DADDR", "SPORT", "DPORT"), end="")
649 if not args.netns:
650 print("%-8s" % "NETNS", end="")
651 print()
652else:
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200653 if args.timestamp:
654 print("%-9s" % ("TIME(s)"), end="")
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200655 print("%-2s %-6s %-16s %-2s %-16s %-16s %-6s %-6s" %
656 ("T", "PID", "COMM", "IP", "SADDR", "DADDR", "SPORT", "DPORT"))
657
Iago López Galeiras6426cd42017-08-04 16:57:20 +0200658start_ts = 0
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200659
660def inet_ntoa(addr):
661 dq = ''
662 for i in range(0, 4):
663 dq = dq + str(addr & 0xff)
664 if (i != 3):
665 dq = dq + '.'
666 addr = addr >> 8
667 return dq
668
669
670b["tcp_ipv4_event"].open_perf_buffer(print_ipv4_event)
671b["tcp_ipv6_event"].open_perf_buffer(print_ipv6_event)
672while True:
673 b.kprobe_poll()