[tcpconnect] filter traced connection based on destination ports
authorchantra <chantr4@gmail.com>
Sat, 10 Sep 2016 16:44:50 +0000 (09:44 -0700)
committerchantra <chantr4@gmail.com>
Fri, 16 Sep 2016 18:15:21 +0000 (11:15 -0700)
Test:
While running:
while [ 1 ]; do nc -w 1 100.127.0.1 80; nc -w 1 100.127.0.1 81; done

root@vagrant:/mnt/bcc# ./tools/tcpconnect.py
PID    COMM         IP SADDR            DADDR            DPORT
19978  nc           4  10.0.2.15        100.127.0.1      80
19979  nc           4  10.0.2.15        100.127.0.1      81
19980  nc           4  10.0.2.15        100.127.0.1      80
19981  nc           4  10.0.2.15        100.127.0.1      81
root@vagrant:/mnt/bcc# ./tools/tcpconnect.py  -P 80
PID    COMM         IP SADDR            DADDR            DPORT
19987  nc           4  10.0.2.15        100.127.0.1      80
19989  nc           4  10.0.2.15        100.127.0.1      80
19991  nc           4  10.0.2.15        100.127.0.1      80
19993  nc           4  10.0.2.15        100.127.0.1      80
19995  nc           4  10.0.2.15        100.127.0.1      80
root@vagrant:/mnt/bcc# ./tools/tcpconnect.py  -P 80,81
PID    COMM         IP SADDR            DADDR            DPORT
8725   nc           4  10.0.2.15        100.127.0.1      80
8726   nc           4  10.0.2.15        100.127.0.1      81
8727   nc           4  10.0.2.15        100.127.0.1      80
8728   nc           4  10.0.2.15        100.127.0.1      81
8729   nc           4  10.0.2.15        100.127.0.1      80

Fixes #681

man/man8/tcpconnect.8
tools/tcpconnect.py
tools/tcpconnect_example.txt

index 27780ae..eb1f4ad 100644 (file)
@@ -2,7 +2,7 @@
 .SH NAME
 tcpconnect \- Trace TCP active connections (connect()). Uses Linux eBPF/bcc.
 .SH SYNOPSIS
-.B tcpconnect [\-h] [\-t] [\-x] [\-p PID]
+.B tcpconnect [\-h] [\-t] [\-x] [\-p PID] [-P PORT]
 .SH DESCRIPTION
 This tool traces active TCP connections (eg, via a connect() syscall;
 accept() are passive connections). This can be useful for general
@@ -27,6 +27,9 @@ Include a timestamp column.
 .TP
 \-p PID
 Trace this process ID only (filtered in-kernel).
+.TP
+\-P PORT
+Comma-separated list of destination ports to trace (filtered in-kernel).
 .SH EXAMPLES
 .TP
 Trace all active TCP connections:
@@ -40,6 +43,10 @@ Trace all TCP connects, and include timestamps:
 Trace PID 181 only:
 #
 .B tcpconnect \-p 181
+.TP
+Trace ports 80 and 81 only:
+#
+.B tcpconnect \-P 80,81
 .SH FIELDS
 .TP
 TIME(s)
index 7615167..5b7f187 100755 (executable)
@@ -4,7 +4,7 @@
 # tcpconnect    Trace TCP connect()s.
 #               For Linux, uses BCC, eBPF. Embedded C.
 #
-# USAGE: tcpconnect [-h] [-t] [-p PID]
+# USAGE: tcpconnect [-h] [-t] [-p PID] [-P PORT [PORT ...]]
 #
 # All connection attempts are traced, even if they ultimately fail.
 #
@@ -20,7 +20,7 @@
 from __future__ import print_function
 from bcc import BPF
 import argparse
-from socket import inet_ntop, AF_INET, AF_INET6
+from socket import inet_ntop, ntohs, AF_INET, AF_INET6
 from struct import pack
 import ctypes as ct
 
@@ -29,6 +29,8 @@ examples = """examples:
     ./tcpconnect           # trace all TCP connect()s
     ./tcpconnect -t        # include timestamps
     ./tcpconnect -p 181    # only trace PID 181
+    ./tcpconnect -P 80     # only trace port 80
+    ./tcpconnect -P 80,81  # only trace port 80 and 81
 """
 parser = argparse.ArgumentParser(
     description="Trace TCP connects",
@@ -38,6 +40,8 @@ parser.add_argument("-t", "--timestamp", action="store_true",
     help="include timestamp on output")
 parser.add_argument("-p", "--pid",
     help="trace this PID only")
+parser.add_argument("-P", "--port",
+    help="comma-separated list of destination ports to trace.")
 args = parser.parse_args()
 debug = 0
 
@@ -76,7 +80,7 @@ BPF_PERF_OUTPUT(ipv6_events);
 int trace_connect_entry(struct pt_regs *ctx, struct sock *sk)
 {
     u32 pid = bpf_get_current_pid_tgid();
-    FILTER
+    FILTER_PID
 
     // stash the sock ptr for lookup on return
     currsock.update(&pid, &sk);
@@ -107,6 +111,8 @@ static int trace_connect_return(struct pt_regs *ctx, short ipver)
     u16 dport = 0;
     bpf_probe_read(&dport, sizeof(dport), &skp->__sk_common.skc_dport);
 
+    FILTER_PORT
+
     if (ipver == 4) {
         struct ipv4_data_t data4 = {.pid = pid, .ip = ipver};
         data4.ts_us = bpf_ktime_get_ns() / 1000;
@@ -148,10 +154,17 @@ int trace_connect_v6_return(struct pt_regs *ctx)
 
 # code substitutions
 if args.pid:
-    bpf_text = bpf_text.replace('FILTER',
+    bpf_text = bpf_text.replace('FILTER_PID',
         'if (pid != %s) { return 0; }' % args.pid)
-else:
-    bpf_text = bpf_text.replace('FILTER', '')
+if args.port:
+    dports = [int(dport) for dport in args.port.split(',')]
+    dports_if = ' && '.join(['dport != %d' % ntohs(dport) for dport in dports])
+    bpf_text = bpf_text.replace('FILTER_PORT',
+        'if (%s) { currsock.delete(&pid); return 0; }' % dports_if)
+
+bpf_text = bpf_text.replace('FILTER_PID', '')
+bpf_text = bpf_text.replace('FILTER_PORT', '')
+
 if debug:
     print(bpf_text)
 
index 4e6cf41..6d2f8f8 100644 (file)
@@ -41,7 +41,7 @@ process to various other addresses. A few connections occur every minute.
 USAGE message:
 
 # ./tcpconnect -h
-usage: tcpconnect [-h] [-t] [-p PID]
+usage: tcpconnect [-h] [-t] [-p PID] [-P PORT]
 
 Trace TCP connects
 
@@ -49,8 +49,12 @@ optional arguments:
   -h, --help         show this help message and exit
   -t, --timestamp    include timestamp on output
   -p PID, --pid PID  trace this PID only
+  -P PORT, --port PORT
+                     comma-separated list of destination ports to trace.
 
 examples:
     ./tcpconnect           # trace all TCP connect()s
     ./tcpconnect -t        # include timestamps
     ./tcpconnect -p 181    # only trace PID 181
+    ./tcpconnect -P 80     # only trace port 80
+    ./tcpconnect -P 80,81  # only trace port 80 and 81