Skip to content

Commit

Permalink
libbpf-tools: tcpconnect: take source port into consideration
Browse files Browse the repository at this point in the history
Originally, the tcpconnect utility didn't display the source port when tracing
events and ignored it (intentionally) when counting new connections. Add a new
option -s (or --source-port) to display the source port when tracing, or to use
the source port as part of the key when counting connections. This option is
unset by default to provide the original output.

Signed-off-by: Anton Protopopov <[email protected]>
  • Loading branch information
aspsk committed Jul 28, 2022
1 parent cb23ebb commit 4c2d123
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 22 deletions.
25 changes: 17 additions & 8 deletions libbpf-tools/tcpconnect.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const volatile int filter_ports_len = 0;
const volatile uid_t filter_uid = -1;
const volatile pid_t filter_pid = 0;
const volatile bool do_count = 0;
const volatile bool source_port = 0;

/* Define here, because there are conflicts with include files */
#define AF_INET 2
Expand Down Expand Up @@ -81,21 +82,22 @@ enter_tcp_connect(struct pt_regs *ctx, struct sock *sk)
return 0;
}

static __always_inline void count_v4(struct sock *sk, __u16 dport)
static __always_inline void count_v4(struct sock *sk, __u16 sport, __u16 dport)
{
struct ipv4_flow_key key = {};
static __u64 zero;
__u64 *val;

BPF_CORE_READ_INTO(&key.saddr, sk, __sk_common.skc_rcv_saddr);
BPF_CORE_READ_INTO(&key.daddr, sk, __sk_common.skc_daddr);
key.sport = sport;
key.dport = dport;
val = bpf_map_lookup_or_try_init(&ipv4_count, &key, &zero);
if (val)
__atomic_add_fetch(val, 1, __ATOMIC_RELAXED);
}

static __always_inline void count_v6(struct sock *sk, __u16 dport)
static __always_inline void count_v6(struct sock *sk, __u16 sport, __u16 dport)
{
struct ipv6_flow_key key = {};
static const __u64 zero;
Expand All @@ -105,6 +107,7 @@ static __always_inline void count_v6(struct sock *sk, __u16 dport)
__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
BPF_CORE_READ_INTO(&key.daddr, sk,
__sk_common.skc_v6_daddr.in6_u.u6_addr32);
key.sport = sport;
key.dport = dport;

val = bpf_map_lookup_or_try_init(&ipv6_count, &key, &zero);
Expand All @@ -113,7 +116,7 @@ static __always_inline void count_v6(struct sock *sk, __u16 dport)
}

static __always_inline void
trace_v4(struct pt_regs *ctx, pid_t pid, struct sock *sk, __u16 dport)
trace_v4(struct pt_regs *ctx, pid_t pid, struct sock *sk, __u16 sport, __u16 dport)
{
struct event event = {};

Expand All @@ -123,6 +126,7 @@ trace_v4(struct pt_regs *ctx, pid_t pid, struct sock *sk, __u16 dport)
event.ts_us = bpf_ktime_get_ns() / 1000;
BPF_CORE_READ_INTO(&event.saddr_v4, sk, __sk_common.skc_rcv_saddr);
BPF_CORE_READ_INTO(&event.daddr_v4, sk, __sk_common.skc_daddr);
event.sport = sport;
event.dport = dport;
bpf_get_current_comm(event.task, sizeof(event.task));

Expand All @@ -131,7 +135,7 @@ trace_v4(struct pt_regs *ctx, pid_t pid, struct sock *sk, __u16 dport)
}

static __always_inline void
trace_v6(struct pt_regs *ctx, pid_t pid, struct sock *sk, __u16 dport)
trace_v6(struct pt_regs *ctx, pid_t pid, struct sock *sk, __u16 sport, __u16 dport)
{
struct event event = {};

Expand All @@ -143,6 +147,7 @@ trace_v6(struct pt_regs *ctx, pid_t pid, struct sock *sk, __u16 dport)
__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
BPF_CORE_READ_INTO(&event.daddr_v6, sk,
__sk_common.skc_v6_daddr.in6_u.u6_addr32);
event.sport = sport;
event.dport = dport;
bpf_get_current_comm(event.task, sizeof(event.task));

Expand All @@ -158,6 +163,7 @@ exit_tcp_connect(struct pt_regs *ctx, int ret, int ip_ver)
__u32 tid = pid_tgid;
struct sock **skpp;
struct sock *sk;
__u16 sport = 0;
__u16 dport;

skpp = bpf_map_lookup_elem(&sockets, &tid);
Expand All @@ -169,20 +175,23 @@ exit_tcp_connect(struct pt_regs *ctx, int ret, int ip_ver)

sk = *skpp;

if (source_port)
BPF_CORE_READ_INTO(&sport, sk, __sk_common.skc_num);
BPF_CORE_READ_INTO(&dport, sk, __sk_common.skc_dport);

if (filter_port(dport))
goto end;

if (do_count) {
if (ip_ver == 4)
count_v4(sk, dport);
count_v4(sk, sport, dport);
else
count_v6(sk, dport);
count_v6(sk, sport, dport);
} else {
if (ip_ver == 4)
trace_v4(ctx, pid, sk, dport);
trace_v4(ctx, pid, sk, sport, dport);
else
trace_v6(ctx, pid, sk, dport);
trace_v6(ctx, pid, sk, sport, dport);
}

end:
Expand Down
60 changes: 46 additions & 14 deletions libbpf-tools/tcpconnect.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ static const struct argp_option opts[] = {
{ "print-uid", 'U', NULL, 0, "Include UID on output" },
{ "pid", 'p', "PID", 0, "Process PID to trace" },
{ "uid", 'u', "UID", 0, "Process UID to trace" },
{ "source-port", 's', NULL, 0, "Consider source port when counting" },
{ "port", 'P', "PORTS", 0,
"Comma-separated list of destination ports to trace" },
{ "cgroupmap", 'C', "PATH", 0, "trace cgroups in this map" },
Expand All @@ -127,6 +128,7 @@ static struct env {
uid_t uid;
int nports;
int ports[MAX_PORTS];
bool source_port;
} env = {
.uid = (uid_t) -1,
};
Expand All @@ -146,6 +148,9 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
case 'c':
env.count = true;
break;
case 's':
env.source_port = true;
break;
case 't':
env.print_timestamp = true;
break;
Expand Down Expand Up @@ -221,10 +226,14 @@ static void print_count_ipv4(int map_fd)
src.s_addr = keys[i].saddr;
dst.s_addr = keys[i].daddr;

printf("%-25s %-25s %-20d %-10llu\n",
printf("%-25s %-25s",
inet_ntop(AF_INET, &src, s, sizeof(s)),
inet_ntop(AF_INET, &dst, d, sizeof(d)),
ntohs(keys[i].dport), counts[i]);
inet_ntop(AF_INET, &dst, d, sizeof(d)));
if (env.source_port)
printf(" %-20d", keys[i].sport);
printf(" %-20d", ntohs(keys[i].dport));
printf(" %-10llu", counts[i]);
printf("\n");
}
}

Expand All @@ -250,21 +259,33 @@ static void print_count_ipv6(int map_fd)
memcpy(src.s6_addr, keys[i].saddr, sizeof(src.s6_addr));
memcpy(dst.s6_addr, keys[i].daddr, sizeof(src.s6_addr));

printf("%-25s %-25s %-20d %-10llu\n",
printf("%-25s %-25s",
inet_ntop(AF_INET6, &src, s, sizeof(s)),
inet_ntop(AF_INET6, &dst, d, sizeof(d)),
ntohs(keys[i].dport), counts[i]);
inet_ntop(AF_INET6, &dst, d, sizeof(d)));
if (env.source_port)
printf(" %-20d", keys[i].sport);
printf(" %-20d", ntohs(keys[i].dport));
printf(" %-10llu", counts[i]);
printf("\n");
}
}

static void print_count(int map_fd_ipv4, int map_fd_ipv6)
static void print_count_header()
{
static const char *header_fmt = "\n%-25s %-25s %-20s %-10s\n";
printf("\n%-25s %-25s", "LADDR", "RADDR");
if (env.source_port)
printf(" %-20s", "LPORT");
printf(" %-20s", "RPORT");
printf(" %-10s", "CONNECTS");
printf("\n");
}

static void print_count(int map_fd_ipv4, int map_fd_ipv6)
{
while (!exiting)
pause();

printf(header_fmt, "LADDR", "RADDR", "RPORT", "CONNECTS");
print_count_header();
print_count_ipv4(map_fd_ipv4);
print_count_ipv6(map_fd_ipv6);
}
Expand All @@ -275,8 +296,11 @@ static void print_events_header()
printf("%-9s", "TIME(s)");
if (env.print_uid)
printf("%-6s", "UID");
printf("%-6s %-12s %-2s %-16s %-16s %-4s\n",
"PID", "COMM", "IP", "SADDR", "DADDR", "DPORT");
printf("%-6s %-12s %-2s %-16s %-16s",
"PID", "COMM", "IP", "SADDR", "DADDR");
if (env.source_port)
printf(" %-5s", "SPORT");
printf(" %-5s\n", "DPORT");
}

static void handle_event(void *ctx, int cpu, void *data, __u32 data_sz)
Expand Down Expand Up @@ -310,12 +334,18 @@ static void handle_event(void *ctx, int cpu, void *data, __u32 data_sz)
if (env.print_uid)
printf("%-6d", event->uid);

printf("%-6d %-12.12s %-2d %-16s %-16s %-4d\n",
printf("%-6d %-12.12s %-2d %-16s %-16s",
event->pid, event->task,
event->af == AF_INET ? 4 : 6,
inet_ntop(event->af, &s, src, sizeof(src)),
inet_ntop(event->af, &d, dst, sizeof(dst)),
ntohs(event->dport));
inet_ntop(event->af, &d, dst, sizeof(dst)));

if (env.source_port)
printf(" %-5d", event->sport);

printf(" %-5d", ntohs(event->dport));

printf("\n");
}

static void handle_lost_events(void *ctx, int cpu, __u64 lost_cnt)
Expand Down Expand Up @@ -394,6 +424,8 @@ int main(int argc, char **argv)
obj->rodata->filter_ports[i] = htons(env.ports[i]);
}
}
if (env.source_port)
obj->rodata->source_port = true;

err = tcpconnect_bpf__load(obj);
if (err) {
Expand Down
3 changes: 3 additions & 0 deletions libbpf-tools/tcpconnect.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@
struct ipv4_flow_key {
__u32 saddr;
__u32 daddr;
__u16 sport;
__u16 dport;
};

struct ipv6_flow_key {
__u8 saddr[16];
__u8 daddr[16];
__u16 sport;
__u16 dport;
};

Expand All @@ -37,6 +39,7 @@ struct event {
__u32 af; // AF_INET or AF_INET6
__u32 pid;
__u32 uid;
__u16 sport;
__u16 dport;
};

Expand Down

0 comments on commit 4c2d123

Please sign in to comment.