From 557033ef15a7023005d0cbec3460bb1ee8bf0d40 Mon Sep 17 00:00:00 2001 From: Joseph Voss Date: Wed, 21 Apr 2021 15:17:14 -0400 Subject: [PATCH 1/6] Initial pass at udpcount sensor --- csrc/udpcount.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 csrc/udpcount.c diff --git a/csrc/udpcount.c b/csrc/udpcount.c new file mode 100644 index 0000000..717d0ad --- /dev/null +++ b/csrc/udpcount.c @@ -0,0 +1,73 @@ +#include +#include +#include + +struct event_data_t { + u32 pid; + u32 saddr; + u32 daddr; + u16 sport; + u16 dport; + u64 tx_b; + u64 rx_b; + char comm[TASK_COMM_LEN]; + u32 uid; +}; + +BPF_PERF_OUTPUT(udp_sockets); + +// Populate event_data_t from ctx and socket info +static void build_udp_event(struct pt_regs *ctx, struct sock *sk, struct event_data_t *ed) { + // Create pid, uid, comm from ctx + ed->pid = bpf_get_current_pid_tgid() >> 32; + ed->uid = bpf_get_current_uid_gid(); + bpf_get_current_comm(&ed->comm, sizeof(ed->comm)); + + // Create port and addr info from sock + // lport is either used in a filter here, or later + u16 sport = sk->__sk_common.skc_num; + // destination port, switched to host byte order + //dport = (dport >> 8) | ((dport << 8) & 0x00FF00); + u16 dport = sk->__sk_common.skc_dport; + dport = ntohs(dport); + + // Load data into struct + ed->sport = sport; + ed->dport = dport; + ed->saddr = sk->__sk_common.skc_rcv_saddr; + ed->daddr = sk->__sk_common.skc_daddr; +} + +int syscall__udp_sendmsg(struct pt_regs *ctx, struct sock *sk, struct msghdr *msg, size_t len) { + + struct event_data_t edata; + // Set 0 padding + __builtin_memset(&edata, 0, sizeof(edata)); + + // Set byte count from packet + edata.tx_b = (u64) len; + edata.rx_b = 0; + + // Populate output data + build_udp_event(ctx, sk, &edata); + + udp_sockets.perf_submit(ctx, &edata, sizeof(edata)); + return 0; +} + +int syscall__udp_recvmsg (struct pt_regs *ctx, struct sock *sk, struct msghdr *msg, size_t len, int noblock, int flags, int *addr_len) { + + struct event_data_t edata; + // Set 0 padding + __builtin_memset(&edata, 0, sizeof(edata)); + + // Set byte count from packet + edata.tx_b = 0; + edata.rx_b = (u64) len; + + // Populate output data + build_udp_event(ctx, sk, &edata); + + udp_sockets.perf_submit(ctx, &edata, sizeof(edata)); + return 0; +} From 84f443b424872ccad45e29bcba1a95de8630bf13 Mon Sep 17 00:00:00 2001 From: Joseph Voss Date: Thu, 22 Apr 2021 14:00:04 -0400 Subject: [PATCH 2/6] Adds lifetime calculation for socket --- csrc/udpcount.c | 89 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 73 insertions(+), 16 deletions(-) diff --git a/csrc/udpcount.c b/csrc/udpcount.c index 717d0ad..8eb1ed0 100644 --- a/csrc/udpcount.c +++ b/csrc/udpcount.c @@ -8,14 +8,23 @@ struct event_data_t { u32 daddr; u16 sport; u16 dport; - u64 tx_b; - u64 rx_b; + u32 tx_b; + u32 rx_b; + u64 span_us; char comm[TASK_COMM_LEN]; u32 uid; }; BPF_PERF_OUTPUT(udp_sockets); +struct sendrecv_t { + u32 tx_b; + u32 rx_b; + u64 events; +}; +BPF_HASH(socket_span, struct sock *, u64); +BPF_HASH(socket_data, struct sock *, struct sendrecv_t); + // Populate event_data_t from ctx and socket info static void build_udp_event(struct pt_regs *ctx, struct sock *sk, struct event_data_t *ed) { // Create pid, uid, comm from ctx @@ -40,32 +49,80 @@ static void build_udp_event(struct pt_regs *ctx, struct sock *sk, struct event_d int syscall__udp_sendmsg(struct pt_regs *ctx, struct sock *sk, struct msghdr *msg, size_t len) { - struct event_data_t edata; - // Set 0 padding - __builtin_memset(&edata, 0, sizeof(edata)); + // Look up current socket data, add rx_b, update - // Set byte count from packet - edata.tx_b = (u64) len; - edata.rx_b = 0; + struct sendrecv_t * srp = socket_data.lookup(&sk); + // If missed create, init now + struct sendrecv_t sr = {.tx_b = 0, .rx_b = 0, .events = 0}; + if (srp != 0) { + sr = *srp; + } + sr.tx_b += (u32) len; + sr.events += 1; + socket_data.update(&sk, &sr); - // Populate output data - build_udp_event(ctx, sk, &edata); - - udp_sockets.perf_submit(ctx, &edata, sizeof(edata)); return 0; } int syscall__udp_recvmsg (struct pt_regs *ctx, struct sock *sk, struct msghdr *msg, size_t len, int noblock, int flags, int *addr_len) { + + // Look up current socket data, add rx_b, update + + struct sendrecv_t * srp = socket_data.lookup(&sk); + // If missed create, init now + struct sendrecv_t sr = {.tx_b = 0, .rx_b = 0, .events = 0}; + if (srp != 0) { + sr = *srp; + } + sr.rx_b += (u32) len; + sr.events += 1; + socket_data.update(&sk, &sr); + + return 0; +} + +// Capture sock creation time, init empty socket data +int syscall__ip4_datagram_connect(struct pt_regs *ctx, struct sock *sk, struct sockaddr *uaddr, int addr_len) { + // Save start time + u64 ts = bpf_ktime_get_ns(); + socket_span.update(&sk, &ts); + // Init socket data counter + struct sendrecv_t sr = {.tx_b = 0, .rx_b = 0, .events = 0}; + socket_data.update(&sk, &sr); + return 0; +} + +// Calculate span, sav +int syscall__udp_destroy_sock(struct pt_regs *ctx, struct sock *sk) { struct event_data_t edata; // Set 0 padding __builtin_memset(&edata, 0, sizeof(edata)); - // Set byte count from packet - edata.tx_b = 0; - edata.rx_b = (u64) len; + // calculate lifespan + u64 *tsp, delta_us; + tsp = socket_span.lookup(&sk); + if (tsp == 0) { + socket_data.delete(&sk); // may not exist + socket_span.delete(&sk); // may not exist + return 0; // missed create + } + delta_us = (bpf_ktime_get_ns() - *tsp) / 1000; + socket_span.delete(&sk); + edata.span_us = delta_us; + + // Fetch data counter + struct sendrecv_t *srp = socket_data.lookup(&sk); + if (srp == 0) { + socket_data.delete(&sk); // may not exist + socket_span.delete(&sk); // may not exist + return 0; // missed create + } + edata.tx_b = srp->tx_b; + edata.rx_b = srp->rx_b; + socket_data.delete(&sk); - // Populate output data + // Load comm, port, addrs into struct build_udp_event(ctx, sk, &edata); udp_sockets.perf_submit(ctx, &edata, sizeof(edata)); From 305e876650e50202b0e2e83edb42959024b3295a Mon Sep 17 00:00:00 2001 From: Joseph Voss Date: Thu, 22 Apr 2021 16:22:11 -0400 Subject: [PATCH 3/6] Move deletes to after perf_submit, don't use ntohs --- csrc/udpcount.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/csrc/udpcount.c b/csrc/udpcount.c index 8eb1ed0..138d82c 100644 --- a/csrc/udpcount.c +++ b/csrc/udpcount.c @@ -12,6 +12,7 @@ struct event_data_t { u32 rx_b; u64 span_us; char comm[TASK_COMM_LEN]; + u64 events; u32 uid; }; @@ -38,7 +39,8 @@ static void build_udp_event(struct pt_regs *ctx, struct sock *sk, struct event_d // destination port, switched to host byte order //dport = (dport >> 8) | ((dport << 8) & 0x00FF00); u16 dport = sk->__sk_common.skc_dport; - dport = ntohs(dport); + //dport = ntohs(dport); + dport = (dport >> 8) | ((dport << 8) & 0x00FF00); // Load data into struct ed->sport = sport; @@ -108,7 +110,6 @@ int syscall__udp_destroy_sock(struct pt_regs *ctx, struct sock *sk) { return 0; // missed create } delta_us = (bpf_ktime_get_ns() - *tsp) / 1000; - socket_span.delete(&sk); edata.span_us = delta_us; // Fetch data counter @@ -120,11 +121,13 @@ int syscall__udp_destroy_sock(struct pt_regs *ctx, struct sock *sk) { } edata.tx_b = srp->tx_b; edata.rx_b = srp->rx_b; - socket_data.delete(&sk); + edata.events = srp->events; // Load comm, port, addrs into struct build_udp_event(ctx, sk, &edata); udp_sockets.perf_submit(ctx, &edata, sizeof(edata)); + socket_data.delete(&sk); + socket_span.delete(&sk); return 0; } From 20fd5010240b0bf8987b9401a41da7c174277e0f Mon Sep 17 00:00:00 2001 From: Joseph Voss Date: Thu, 22 Apr 2021 16:23:06 -0400 Subject: [PATCH 4/6] Add udpcount example config --- configs/udpcount.yaml | 53 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 configs/udpcount.yaml diff --git a/configs/udpcount.yaml b/configs/udpcount.yaml new file mode 100644 index 0000000..5ae0a4d --- /dev/null +++ b/configs/udpcount.yaml @@ -0,0 +1,53 @@ +--- +globals: + socketPath: "/var/run/telegraf.sock" + verboseFormat: influx +programs: + - source: /usr/share/greggd/c/udpcount.c + # Events to bind program to + events: + - type: kprobe + loadFunc: syscall__udp_sendmsg + attachTo: udp_sendmsg + - type: kprobe + loadFunc: syscall__udp_recvmsg + attachTo: udp_recvmsg + - type: kprobe + loadFunc: syscall__ip4_datagram_connect + attachTo: ip4_datagram_connect + - type: kprobe + loadFunc: syscall__udp_destroy_sock + attachTo: udp_destroy_sock + outputs: + - type: BPF_PERF_OUTPUT + id: udp_sockets + format: + - name: pid + type: u32 + isTag: true + - name: saddr + type: u32 + isIP: true + - name: raddr + type: u32 + isIP: true + - name: sport + type: u16 + isTag: true + - name: rport + type: u16 + isTag: true + - name: tx_b + type: u32 + - name: rx_b + type: u32 + - name: span + type: u64 + - name: comm + type: char[16] + isTag: true + - name: events + type: u64 + - name: uid + type: u32 + isTag: true From 00e390df65170a60e6a294cd4a1a21d0fefa866c Mon Sep 17 00:00:00 2001 From: Joseph Voss Date: Thu, 22 Apr 2021 16:40:57 -0400 Subject: [PATCH 5/6] Refactor cleanup --- csrc/udpcount.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/csrc/udpcount.c b/csrc/udpcount.c index 138d82c..b172bbf 100644 --- a/csrc/udpcount.c +++ b/csrc/udpcount.c @@ -101,24 +101,18 @@ int syscall__udp_destroy_sock(struct pt_regs *ctx, struct sock *sk) { // Set 0 padding __builtin_memset(&edata, 0, sizeof(edata)); - // calculate lifespan + // Lookup values we need u64 *tsp, delta_us; + struct sendrecv_t *srp; tsp = socket_span.lookup(&sk); - if (tsp == 0) { - socket_data.delete(&sk); // may not exist - socket_span.delete(&sk); // may not exist - return 0; // missed create - } + srp = socket_data.lookup(&sk); + // Check if we missed the socket creation. Exit if so + if (tsp == 0) || (srp == 0) goto destroy_end; + + // calculate lifespan delta_us = (bpf_ktime_get_ns() - *tsp) / 1000; edata.span_us = delta_us; - - // Fetch data counter - struct sendrecv_t *srp = socket_data.lookup(&sk); - if (srp == 0) { - socket_data.delete(&sk); // may not exist - socket_span.delete(&sk); // may not exist - return 0; // missed create - } + // calculate data sent edata.tx_b = srp->tx_b; edata.rx_b = srp->rx_b; edata.events = srp->events; @@ -126,7 +120,10 @@ int syscall__udp_destroy_sock(struct pt_regs *ctx, struct sock *sk) { // Load comm, port, addrs into struct build_udp_event(ctx, sk, &edata); + // Output udp_sockets.perf_submit(ctx, &edata, sizeof(edata)); + +destory_end:; socket_data.delete(&sk); socket_span.delete(&sk); return 0; From 4d87e816b0a4ec6f96e80c9348cc55d0d2cdf99f Mon Sep 17 00:00:00 2001 From: Joseph Voss Date: Thu, 22 Apr 2021 16:49:32 -0400 Subject: [PATCH 6/6] Add ipv6 filter --- csrc/udpcount.c | 51 +++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/csrc/udpcount.c b/csrc/udpcount.c index b172bbf..011ce79 100644 --- a/csrc/udpcount.c +++ b/csrc/udpcount.c @@ -101,29 +101,34 @@ int syscall__udp_destroy_sock(struct pt_regs *ctx, struct sock *sk) { // Set 0 padding __builtin_memset(&edata, 0, sizeof(edata)); - // Lookup values we need - u64 *tsp, delta_us; - struct sendrecv_t *srp; - tsp = socket_span.lookup(&sk); - srp = socket_data.lookup(&sk); - // Check if we missed the socket creation. Exit if so - if (tsp == 0) || (srp == 0) goto destroy_end; - - // calculate lifespan - delta_us = (bpf_ktime_get_ns() - *tsp) / 1000; - edata.span_us = delta_us; - // calculate data sent - edata.tx_b = srp->tx_b; - edata.rx_b = srp->rx_b; - edata.events = srp->events; - - // Load comm, port, addrs into struct - build_udp_event(ctx, sk, &edata); - - // Output - udp_sockets.perf_submit(ctx, &edata, sizeof(edata)); - -destory_end:; + // Check if ipv4 or ipv6 + // TODO: implement ipv6 + u16 family = sk=>__sk_common.skc_family; + if (family == AF_INET) { + // Lookup values we need + u64 *tsp, delta_us; + struct sendrecv_t *srp; + tsp = socket_span.lookup(&sk); + srp = socket_data.lookup(&sk); + // Check if we missed the socket creation. Exit if so + if ((tsp == 0) || (srp == 0)) goto destroy_end; + + // calculate lifespan + delta_us = (bpf_ktime_get_ns() - *tsp) / 1000; + edata.span_us = delta_us; + // calculate data sent + edata.tx_b = srp->tx_b; + edata.rx_b = srp->rx_b; + edata.events = srp->events; + + // Load comm, port, addrs into struct + build_udp_event(ctx, sk, &edata); + + // Output + udp_sockets.perf_submit(ctx, &edata, sizeof(edata)); + } + +destroy_end:; socket_data.delete(&sk); socket_span.delete(&sk); return 0;