blob: bb44fbb335853e67696846dfcbbe3fc788cde245 [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")
35args = parser.parse_args()
36
37bpf_text = """
38#include <uapi/linux/ptrace.h>
39#pragma clang diagnostic push
40#pragma clang diagnostic ignored "-Wtautological-compare"
41#include <net/sock.h>
42#pragma clang diagnostic pop
43#include <net/inet_sock.h>
44#include <net/net_namespace.h>
45#include <bcc/proto.h>
46
47#define TCP_EVENT_TYPE_CONNECT 1
48#define TCP_EVENT_TYPE_ACCEPT 2
49#define TCP_EVENT_TYPE_CLOSE 3
50
51struct tcp_ipv4_event_t {
Iago López Galeirasfff792d2017-08-04 18:13:05 +020052 u64 ts_ns;
Iago López Galeirasf37434b2017-03-30 19:07:47 +020053 u32 type;
54 u32 pid;
55 char comm[TASK_COMM_LEN];
56 u8 ip;
57 u32 saddr;
58 u32 daddr;
59 u16 sport;
60 u16 dport;
61 u32 netns;
62};
63BPF_PERF_OUTPUT(tcp_ipv4_event);
64
65struct tcp_ipv6_event_t {
Iago López Galeirasfff792d2017-08-04 18:13:05 +020066 u64 ts_ns;
Iago López Galeirasf37434b2017-03-30 19:07:47 +020067 u32 type;
68 u32 pid;
69 char comm[TASK_COMM_LEN];
70 u8 ip;
71 unsigned __int128 saddr;
72 unsigned __int128 daddr;
73 u16 sport;
74 u16 dport;
75 u32 netns;
76};
77BPF_PERF_OUTPUT(tcp_ipv6_event);
78
79// tcp_set_state doesn't run in the context of the process that initiated the
80// connection so we need to store a map TUPLE -> PID to send the right PID on
81// the event
82struct ipv4_tuple_t {
83 u32 saddr;
84 u32 daddr;
85 u16 sport;
86 u16 dport;
87 u32 netns;
88};
89
90struct ipv6_tuple_t {
91 unsigned __int128 saddr;
92 unsigned __int128 daddr;
93 u16 sport;
94 u16 dport;
95 u32 netns;
96};
97
98struct pid_comm_t {
99 u64 pid;
100 char comm[TASK_COMM_LEN];
101};
102
103BPF_HASH(tuplepid_ipv4, struct ipv4_tuple_t, struct pid_comm_t);
104BPF_HASH(tuplepid_ipv6, struct ipv6_tuple_t, struct pid_comm_t);
105
106BPF_HASH(connectsock, u64, struct sock *);
107
108static int read_ipv4_tuple(struct ipv4_tuple_t *tuple, struct sock *skp)
109{
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200110 u32 net_ns_inum = 0;
111 u32 saddr = skp->__sk_common.skc_rcv_saddr;
112 u32 daddr = skp->__sk_common.skc_daddr;
113 struct inet_sock *sockp = (struct inet_sock *)skp;
114 u16 sport = sockp->inet_sport;
115 u16 dport = skp->__sk_common.skc_dport;
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200116#ifdef CONFIG_NET_NS
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200117 possible_net_t skc_net = skp->__sk_common.skc_net;
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200118 bpf_probe_read(&net_ns_inum, sizeof(net_ns_inum), &skc_net.net->ns.inum);
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200119#endif
120
121 ##FILTER_NETNS##
122
123 tuple->saddr = saddr;
124 tuple->daddr = daddr;
125 tuple->sport = sport;
126 tuple->dport = dport;
127 tuple->netns = net_ns_inum;
128
129 // if addresses or ports are 0, ignore
130 if (saddr == 0 || daddr == 0 || sport == 0 || dport == 0) {
131 return 0;
132 }
133
134 return 1;
135}
136
137static int read_ipv6_tuple(struct ipv6_tuple_t *tuple, struct sock *skp)
138{
139 u32 net_ns_inum = 0;
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200140 unsigned __int128 saddr = 0, daddr = 0;
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200141 struct inet_sock *sockp = (struct inet_sock *)skp;
142 u16 sport = sockp->inet_sport;
143 u16 dport = skp->__sk_common.skc_dport;
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200144#ifdef CONFIG_NET_NS
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200145 possible_net_t skc_net = skp->__sk_common.skc_net;
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200146 bpf_probe_read(&net_ns_inum, sizeof(net_ns_inum), &skc_net.net->ns.inum);
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200147#endif
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200148 bpf_probe_read(&saddr, sizeof(saddr),
149 skp->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
150 bpf_probe_read(&daddr, sizeof(daddr),
151 skp->__sk_common.skc_v6_daddr.in6_u.u6_addr32);
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200152
153 ##FILTER_NETNS##
154
155 tuple->saddr = saddr;
156 tuple->daddr = daddr;
157 tuple->sport = sport;
158 tuple->dport = dport;
159 tuple->netns = net_ns_inum;
160
161 // if addresses or ports are 0, ignore
162 if (saddr == 0 || daddr == 0 || sport == 0 || dport == 0) {
163 return 0;
164 }
165
166 return 1;
167}
168
169static bool check_family(struct sock *sk, u16 expected_family) {
170 u64 zero = 0;
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200171 u16 family = sk->__sk_common.skc_family;
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200172 return family == expected_family;
173}
174
175int trace_connect_v4_entry(struct pt_regs *ctx, struct sock *sk)
176{
177 u64 pid = bpf_get_current_pid_tgid();
178
179 ##FILTER_PID##
180
181 // stash the sock ptr for lookup on return
182 connectsock.update(&pid, &sk);
183
184 return 0;
185}
186
187int trace_connect_v4_return(struct pt_regs *ctx)
188{
189 int ret = PT_REGS_RC(ctx);
190 u64 pid = bpf_get_current_pid_tgid();
191
192 struct sock **skpp;
193 skpp = connectsock.lookup(&pid);
194 if (skpp == 0) {
195 return 0; // missed entry
196 }
197
198 connectsock.delete(&pid);
199
200 if (ret != 0) {
201 // failed to send SYNC packet, may not have populated
202 // socket __sk_common.{skc_rcv_saddr, ...}
203 return 0;
204 }
205
206 // pull in details
207 struct sock *skp = *skpp;
208 struct ipv4_tuple_t t = { };
209 if (!read_ipv4_tuple(&t, skp)) {
210 return 0;
211 }
212
213 struct pid_comm_t p = { };
214 p.pid = pid;
215 bpf_get_current_comm(&p.comm, sizeof(p.comm));
216
217 tuplepid_ipv4.update(&t, &p);
218
219 return 0;
220}
221
222int trace_connect_v6_entry(struct pt_regs *ctx, struct sock *sk)
223{
224 u64 pid = bpf_get_current_pid_tgid();
225
226 ##FILTER_PID##
227
228 // stash the sock ptr for lookup on return
229 connectsock.update(&pid, &sk);
230
231 return 0;
232}
233
234int trace_connect_v6_return(struct pt_regs *ctx)
235{
236 int ret = PT_REGS_RC(ctx);
237 u64 pid = bpf_get_current_pid_tgid();
238
239 struct sock **skpp;
240 skpp = connectsock.lookup(&pid);
241 if (skpp == 0) {
242 return 0; // missed entry
243 }
244
245 connectsock.delete(&pid);
246
247 if (ret != 0) {
248 // failed to send SYNC packet, may not have populated
249 // socket __sk_common.{skc_rcv_saddr, ...}
250 return 0;
251 }
252
253 // pull in details
254 struct sock *skp = *skpp;
255 struct ipv6_tuple_t t = { };
256 if (!read_ipv6_tuple(&t, skp)) {
257 return 0;
258 }
259
260 struct pid_comm_t p = { };
261 p.pid = pid;
262 bpf_get_current_comm(&p.comm, sizeof(p.comm));
263
264 tuplepid_ipv6.update(&t, &p);
265
266 return 0;
267}
268
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200269int trace_tcp_set_state_entry(struct pt_regs *ctx, struct sock *skp, int state)
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200270{
271 if (state != TCP_ESTABLISHED && state != TCP_CLOSE) {
272 return 0;
273 }
274
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200275 u8 ipver = 0;
276 if (check_family(skp, AF_INET)) {
277 ipver = 4;
278 struct ipv4_tuple_t t = { };
279 if (!read_ipv4_tuple(&t, skp)) {
280 return 0;
281 }
282
283 if (state == TCP_CLOSE) {
284 tuplepid_ipv4.delete(&t);
285 return 0;
286 }
287
288 struct pid_comm_t *p;
289 p = tuplepid_ipv4.lookup(&t);
290 if (p == 0) {
291 return 0; // missed entry
292 }
293
294 struct tcp_ipv4_event_t evt4 = { };
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200295 evt4.ts_ns = bpf_ktime_get_ns();
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200296 evt4.type = TCP_EVENT_TYPE_CONNECT;
297 evt4.pid = p->pid >> 32;
298 evt4.ip = ipver;
299 evt4.saddr = t.saddr;
300 evt4.daddr = t.daddr;
301 evt4.sport = ntohs(t.sport);
302 evt4.dport = ntohs(t.dport);
303 evt4.netns = t.netns;
304
305 int i;
306 for (i = 0; i < TASK_COMM_LEN; i++) {
307 evt4.comm[i] = p->comm[i];
308 }
309
310 tcp_ipv4_event.perf_submit(ctx, &evt4, sizeof(evt4));
311 tuplepid_ipv4.delete(&t);
312 } else if (check_family(skp, AF_INET6)) {
313 ipver = 6;
314 struct ipv6_tuple_t t = { };
315 if (!read_ipv6_tuple(&t, skp)) {
316 return 0;
317 }
318
319 if (state == TCP_CLOSE) {
320 tuplepid_ipv6.delete(&t);
321 return 0;
322 }
323
324 struct pid_comm_t *p;
325 p = tuplepid_ipv6.lookup(&t);
326 if (p == 0) {
327 return 0; // missed entry
328 }
329
330 struct tcp_ipv6_event_t evt6 = { };
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200331 evt6.ts_ns = bpf_ktime_get_ns();
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200332 evt6.type = TCP_EVENT_TYPE_CONNECT;
333 evt6.pid = p->pid >> 32;
334 evt6.ip = ipver;
335 evt6.saddr = t.saddr;
336 evt6.daddr = t.daddr;
337 evt6.sport = ntohs(t.sport);
338 evt6.dport = ntohs(t.dport);
339 evt6.netns = t.netns;
340
341 int i;
342 for (i = 0; i < TASK_COMM_LEN; i++) {
343 evt6.comm[i] = p->comm[i];
344 }
345
346 tcp_ipv6_event.perf_submit(ctx, &evt6, sizeof(evt6));
347 tuplepid_ipv6.delete(&t);
348 }
349 // else drop
350
351 return 0;
352}
353
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200354int trace_close_entry(struct pt_regs *ctx, struct sock *skp)
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200355{
356 u64 pid = bpf_get_current_pid_tgid();
357
358 ##FILTER_PID##
359
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200360 u8 oldstate = skp->sk_state;
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200361 // Don't generate close events for connections that were never
362 // established in the first place.
363 if (oldstate == TCP_SYN_SENT ||
364 oldstate == TCP_SYN_RECV ||
365 oldstate == TCP_NEW_SYN_RECV)
366 return 0;
367
368 u8 ipver = 0;
369 if (check_family(skp, AF_INET)) {
370 ipver = 4;
371 struct ipv4_tuple_t t = { };
372 if (!read_ipv4_tuple(&t, skp)) {
373 return 0;
374 }
375
376 struct tcp_ipv4_event_t evt4 = { };
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200377 evt4.ts_ns = bpf_ktime_get_ns();
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200378 evt4.type = TCP_EVENT_TYPE_CLOSE;
379 evt4.pid = pid >> 32;
380 evt4.ip = ipver;
381 evt4.saddr = t.saddr;
382 evt4.daddr = t.daddr;
383 evt4.sport = ntohs(t.sport);
384 evt4.dport = ntohs(t.dport);
385 evt4.netns = t.netns;
386 bpf_get_current_comm(&evt4.comm, sizeof(evt4.comm));
387
388 tcp_ipv4_event.perf_submit(ctx, &evt4, sizeof(evt4));
389 } else if (check_family(skp, AF_INET6)) {
390 ipver = 6;
391 struct ipv6_tuple_t t = { };
392 if (!read_ipv6_tuple(&t, skp)) {
393 return 0;
394 }
395
396 struct tcp_ipv6_event_t evt6 = { };
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200397 evt6.ts_ns = bpf_ktime_get_ns();
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200398 evt6.type = TCP_EVENT_TYPE_CLOSE;
399 evt6.pid = pid >> 32;
400 evt6.ip = ipver;
401 evt6.saddr = t.saddr;
402 evt6.daddr = t.daddr;
403 evt6.sport = ntohs(t.sport);
404 evt6.dport = ntohs(t.dport);
405 evt6.netns = t.netns;
406 bpf_get_current_comm(&evt6.comm, sizeof(evt6.comm));
407
408 tcp_ipv6_event.perf_submit(ctx, &evt6, sizeof(evt6));
409 }
410 // else drop
411
412 return 0;
413};
414
415int trace_accept_return(struct pt_regs *ctx)
416{
417 struct sock *newsk = (struct sock *)PT_REGS_RC(ctx);
418 u64 pid = bpf_get_current_pid_tgid();
419
420 ##FILTER_PID##
421
422 if (newsk == NULL) {
423 return 0;
424 }
425
426 // pull in details
427 u16 lport = 0, dport = 0;
428 u32 net_ns_inum = 0;
429 u8 ipver = 0;
430
431 bpf_probe_read(&dport, sizeof(dport), &newsk->__sk_common.skc_dport);
432 bpf_probe_read(&lport, sizeof(lport), &newsk->__sk_common.skc_num);
433
434 // Get network namespace id, if kernel supports it
435#ifdef CONFIG_NET_NS
436 possible_net_t skc_net;
437 bpf_probe_read(&skc_net, sizeof(skc_net), &newsk->__sk_common.skc_net);
438 bpf_probe_read(&net_ns_inum, sizeof(net_ns_inum), &skc_net.net->ns.inum);
439#else
440 net_ns_inum = 0;
441#endif
442
443 ##FILTER_NETNS##
444
445 if (check_family(newsk, AF_INET)) {
446 ipver = 4;
447
448 struct tcp_ipv4_event_t evt4 = { 0 };
449
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200450 evt4.ts_ns = bpf_ktime_get_ns();
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200451 evt4.type = TCP_EVENT_TYPE_ACCEPT;
452 evt4.netns = net_ns_inum;
453 evt4.pid = pid >> 32;
454 evt4.ip = ipver;
455
456 bpf_probe_read(&evt4.saddr, sizeof(evt4.saddr),
457 &newsk->__sk_common.skc_rcv_saddr);
458 bpf_probe_read(&evt4.daddr, sizeof(evt4.daddr),
459 &newsk->__sk_common.skc_daddr);
460
461 evt4.sport = lport;
462 evt4.dport = ntohs(dport);
463 bpf_get_current_comm(&evt4.comm, sizeof(evt4.comm));
464
465 // do not send event if IP address is 0.0.0.0 or port is 0
466 if (evt4.saddr != 0 && evt4.daddr != 0 &&
467 evt4.sport != 0 && evt4.dport != 0) {
468 tcp_ipv4_event.perf_submit(ctx, &evt4, sizeof(evt4));
469 }
470 } else if (check_family(newsk, AF_INET6)) {
471 ipver = 6;
472
473 struct tcp_ipv6_event_t evt6 = { 0 };
474
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200475 evt6.ts_ns = bpf_ktime_get_ns();
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200476 evt6.type = TCP_EVENT_TYPE_ACCEPT;
477 evt6.netns = net_ns_inum;
478 evt6.pid = pid >> 32;
479 evt6.ip = ipver;
480
481 bpf_probe_read(&evt6.saddr, sizeof(evt6.saddr),
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200482 newsk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200483 bpf_probe_read(&evt6.daddr, sizeof(evt6.daddr),
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200484 newsk->__sk_common.skc_v6_daddr.in6_u.u6_addr32);
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200485
486 evt6.sport = lport;
487 evt6.dport = ntohs(dport);
488 bpf_get_current_comm(&evt6.comm, sizeof(evt6.comm));
489
490 // do not send event if IP address is 0.0.0.0 or port is 0
491 if (evt6.saddr != 0 && evt6.daddr != 0 &&
492 evt6.sport != 0 && evt6.dport != 0) {
493 tcp_ipv6_event.perf_submit(ctx, &evt6, sizeof(evt6));
494 }
495 }
496 // else drop
497
498 return 0;
499}
500"""
501
502TASK_COMM_LEN = 16 # linux/sched.h
503
504
505class TCPIPV4Evt(ctypes.Structure):
506 _fields_ = [
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200507 ("ts_ns", ctypes.c_ulonglong),
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200508 ("type", ctypes.c_uint),
509 ("pid", ctypes.c_uint),
510 ("comm", ctypes.c_char * TASK_COMM_LEN),
511 ("ip", ctypes.c_ubyte),
512 ("saddr", ctypes.c_uint),
513 ("daddr", ctypes.c_uint),
514 ("sport", ctypes.c_ushort),
515 ("dport", ctypes.c_ushort),
516 ("netns", ctypes.c_uint)
517 ]
518
519
520class TCPIPV6Evt(ctypes.Structure):
521 _fields_ = [
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200522 ("ts_ns", ctypes.c_ulonglong),
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200523 ("type", ctypes.c_uint),
524 ("pid", ctypes.c_uint),
525 ("comm", ctypes.c_char * TASK_COMM_LEN),
526 ("ip", ctypes.c_ubyte),
527 ("saddr", (ctypes.c_ulong * 2)),
528 ("daddr", (ctypes.c_ulong * 2)),
529 ("sport", ctypes.c_ushort),
530 ("dport", ctypes.c_ushort),
531 ("netns", ctypes.c_uint)
532 ]
533
534
535verbose_types = {"C": "connect", "A": "accept",
536 "X": "close", "U": "unknown"}
537
538
539def print_ipv4_event(cpu, data, size):
540 event = ctypes.cast(data, ctypes.POINTER(TCPIPV4Evt)).contents
Iago López Galeiras6426cd42017-08-04 16:57:20 +0200541 global start_ts
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200542
Iago López Galeiras6426cd42017-08-04 16:57:20 +0200543 if args.timestamp:
544 if start_ts == 0:
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200545 start_ts = event.ts_ns
546 if args.verbose:
547 print("%-14d" % (event.ts_ns - start_ts), end="")
548 else:
549 print("%-9.3f" % ((float(event.ts_ns) - start_ts) / 1000000000), end="")
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200550 if event.type == 1:
551 type_str = "C"
552 elif event.type == 2:
553 type_str = "A"
554 elif event.type == 3:
555 type_str = "X"
556 else:
557 type_str = "U"
558
559 if args.verbose:
560 print("%-12s " % (verbose_types[type_str]), end="")
561 else:
562 print("%-2s " % (type_str), end="")
563
564 print("%-6d %-16s %-2d %-16s %-16s %-6d %-6d" %
565 (event.pid, event.comm.decode('utf-8'),
566 event.ip,
567 inet_ntop(AF_INET, pack("I", event.saddr)),
568 inet_ntop(AF_INET, pack("I", event.daddr)),
569 event.sport,
570 event.dport), end="")
571 if args.verbose and not args.netns:
572 print(" %-8d" % event.netns)
573 else:
574 print()
575
576
577def print_ipv6_event(cpu, data, size):
578 event = ctypes.cast(data, ctypes.POINTER(TCPIPV6Evt)).contents
Iago López Galeiras6426cd42017-08-04 16:57:20 +0200579 global start_ts
580 if args.timestamp:
581 if start_ts == 0:
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200582 start_ts = event.ts_ns
583 if args.verbose:
584 print("%-14d" % (event.ts_ns - start_ts), end="")
585 else:
586 print("%-9.3f" % ((float(event.ts_ns) - start_ts) / 1000000000), end="")
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200587 if event.type == 1:
588 type_str = "C"
589 elif event.type == 2:
590 type_str = "A"
591 elif event.type == 3:
592 type_str = "X"
593 else:
594 type_str = "U"
595
596 if args.verbose:
597 print("%-12s " % (verbose_types[type_str]), end="")
598 else:
599 print("%-2s " % (type_str), end="")
600
601 print("%-6d %-16s %-2d %-16s %-16s %-6d %-6d" %
602 (event.pid, event.comm.decode('utf-8'),
603 event.ip,
604 "["+inet_ntop(AF_INET6, event.saddr)+"]",
605 "["+inet_ntop(AF_INET6, event.daddr)+"]",
606 event.sport,
607 event.dport), end="")
608 if args.verbose and not args.netns:
609 print(" %-8d" % event.netns)
610 else:
611 print()
612
613
614pid_filter = ""
615netns_filter = ""
616
617if args.pid:
618 pid_filter = 'if (pid >> 32 != %d) { return 0; }' % args.pid
619if args.netns:
620 netns_filter = 'if (net_ns_inum != %d) { return 0; }' % args.netns
621
622bpf_text = bpf_text.replace('##FILTER_PID##', pid_filter)
623bpf_text = bpf_text.replace('##FILTER_NETNS##', netns_filter)
624
625# initialize BPF
626b = BPF(text=bpf_text)
627b.attach_kprobe(event="tcp_v4_connect", fn_name="trace_connect_v4_entry")
628b.attach_kretprobe(event="tcp_v4_connect", fn_name="trace_connect_v4_return")
629b.attach_kprobe(event="tcp_v6_connect", fn_name="trace_connect_v6_entry")
630b.attach_kretprobe(event="tcp_v6_connect", fn_name="trace_connect_v6_return")
631b.attach_kprobe(event="tcp_set_state", fn_name="trace_tcp_set_state_entry")
632b.attach_kprobe(event="tcp_close", fn_name="trace_close_entry")
633b.attach_kretprobe(event="inet_csk_accept", fn_name="trace_accept_return")
634
635print("Tracing TCP established connections. Ctrl-C to end.")
636
637# header
638if args.verbose:
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200639 if args.timestamp:
640 print("%-14s" % ("TIME(ns)"), end="")
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200641 print("%-12s %-6s %-16s %-2s %-16s %-16s %-6s %-7s" % ("TYPE",
642 "PID", "COMM", "IP", "SADDR", "DADDR", "SPORT", "DPORT"), end="")
643 if not args.netns:
644 print("%-8s" % "NETNS", end="")
645 print()
646else:
Iago López Galeirasfff792d2017-08-04 18:13:05 +0200647 if args.timestamp:
648 print("%-9s" % ("TIME(s)"), end="")
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200649 print("%-2s %-6s %-16s %-2s %-16s %-16s %-6s %-6s" %
650 ("T", "PID", "COMM", "IP", "SADDR", "DADDR", "SPORT", "DPORT"))
651
Iago López Galeiras6426cd42017-08-04 16:57:20 +0200652start_ts = 0
Iago López Galeirasf37434b2017-03-30 19:07:47 +0200653
654def inet_ntoa(addr):
655 dq = ''
656 for i in range(0, 4):
657 dq = dq + str(addr & 0xff)
658 if (i != 3):
659 dq = dq + '.'
660 addr = addr >> 8
661 return dq
662
663
664b["tcp_ipv4_event"].open_perf_buffer(print_ipv4_event)
665b["tcp_ipv6_event"].open_perf_buffer(print_ipv6_event)
666while True:
667 b.kprobe_poll()