Commit 52938058 authored by chantra's avatar chantra

[tcpconnect] filter traced connection based on destination ports

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
parent 1298998d
......@@ -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)
......
......@@ -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)
......
......@@ -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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment