Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial pass at udpcount sensor #4

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions configs/udpcount.yaml
Original file line number Diff line number Diff line change
@@ -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
135 changes: 135 additions & 0 deletions csrc/udpcount.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#include <uapi/linux/ptrace.h>
#include <net/udp.h>
#include <net/sock.h>

struct event_data_t {
u32 pid;
u32 saddr;
u32 daddr;
u16 sport;
u16 dport;
u32 tx_b;
u32 rx_b;
u64 span_us;
char comm[TASK_COMM_LEN];
u64 events;
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
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);
dport = (dport >> 8) | ((dport << 8) & 0x00FF00);

// 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) {

// 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.tx_b += (u32) len;
sr.events += 1;
socket_data.update(&sk, &sr);

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));

// 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;
}