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

Add UDP probes in anticipation of DNS monitoring #206

Merged
merged 49 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
d243908
add upd send/recv msg probes
fearful-symmetry Aug 30, 2024
52bbe58
format
fearful-symmetry Aug 30, 2024
21af8bb
first pass at DNS packet fetching
fearful-symmetry Sep 6, 2024
fbf1608
use skb functions
fearful-symmetry Sep 6, 2024
608b1a5
Revert "use skb functions"
fearful-symmetry Sep 9, 2024
b8c6559
try to make recvmsg portable
fearful-symmetry Sep 9, 2024
58bb331
only use kprobes for udp methods, pray this works
fearful-symmetry Sep 9, 2024
5527d13
verifier logic has changed?
fearful-symmetry Sep 9, 2024
d76c6df
Merge remote-tracking branch 'origin/main' into udp-connect-probes
fearful-symmetry Sep 10, 2024
06d8327
testing skb methods
fearful-symmetry Sep 10, 2024
5aa36cd
clean up skb code
fearful-symmetry Sep 10, 2024
049b2c1
format
fearful-symmetry Sep 10, 2024
d8c7e25
still testing
fearful-symmetry Sep 10, 2024
40fa09a
typo
fearful-symmetry Sep 10, 2024
5477112
still cleaning up test code
fearful-symmetry Sep 10, 2024
d2770ff
cleanup
fearful-symmetry Sep 10, 2024
17a5e4d
rename enums
fearful-symmetry Sep 11, 2024
c3a53b3
format
fearful-symmetry Sep 11, 2024
5ce5121
cleanup, use proper skbuff offsets
fearful-symmetry Sep 11, 2024
067fe9e
use varlen for packet body
fearful-symmetry Sep 11, 2024
30bc829
use json for output
fearful-symmetry Sep 11, 2024
ed64454
further cleanup
fearful-symmetry Sep 11, 2024
6baa2a1
cleanup
fearful-symmetry Sep 12, 2024
2a263af
skip peeked calls in kprobe
fearful-symmetry Sep 12, 2024
251154e
change DNS max packet size
fearful-symmetry Sep 12, 2024
e59b322
add counter for headlen==0 events
fearful-symmetry Sep 16, 2024
520c8d4
cleanup, error handling
fearful-symmetry Sep 17, 2024
7ea1643
add new counter for sk_buff failures
fearful-symmetry Sep 17, 2024
72b356c
format..
fearful-symmetry Sep 17, 2024
43f126a
update name
fearful-symmetry Sep 17, 2024
55f89af
update docs, var name
fearful-symmetry Sep 17, 2024
49e1ea1
tiny rewording
haesbaert Sep 17, 2024
274ac5a
add tests, clean up json
fearful-symmetry Sep 18, 2024
7542b84
Merge remote-tracking branch 'origin/udp-connect-probes' into udp-con…
fearful-symmetry Sep 18, 2024
28231f2
use host command
fearful-symmetry Sep 18, 2024
c25ae02
use path..
fearful-symmetry Sep 18, 2024
00bd9d9
use arg array
fearful-symmetry Sep 18, 2024
5b494d1
use bash for test
fearful-symmetry Sep 18, 2024
88f021e
use bash for test
fearful-symmetry Sep 18, 2024
318f491
use sh
fearful-symmetry Sep 18, 2024
1f55596
test with a special binary...
fearful-symmetry Sep 18, 2024
d149867
format
fearful-symmetry Sep 18, 2024
b74eec9
clean up
fearful-symmetry Sep 18, 2024
fbe2a42
format...
fearful-symmetry Sep 18, 2024
08648ca
set correct read len for outgoing packets
fearful-symmetry Sep 18, 2024
5c027da
revert changes to utils
fearful-symmetry Sep 18, 2024
d38841f
use better udp send
fearful-symmetry Sep 19, 2024
802fa43
format
fearful-symmetry Sep 19, 2024
e827ae9
clean up
fearful-symmetry Sep 19, 2024
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
28 changes: 26 additions & 2 deletions GPL/Events/EbpfEventProto.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
#define EBPF_EVENTPROBE_EBPFEVENTPROTO_H

#define TASK_COMM_LEN 16
// The theoretical max size of DNS packets over UDP is 512.
// Like so many things in DNS this number probaby isn't 100% accurate.
// DNS extensions in RFC2671 and RFC6891 mean the actual size can be larger.
#define MAX_DNS_PACKET 1500

#ifndef __KERNEL__
#include <stdint.h>
Expand Down Expand Up @@ -40,6 +44,7 @@ enum ebpf_event_type {
EBPF_EVENT_PROCESS_SHMGET = (1 << 17),
EBPF_EVENT_PROCESS_PTRACE = (1 << 18),
EBPF_EVENT_PROCESS_LOAD_MODULE = (1 << 19),
EBPF_EVENT_NETWORK_DNS_PKT = (1 << 20),
};

struct ebpf_event_header {
Expand All @@ -66,6 +71,7 @@ enum ebpf_varlen_field_type {
EBPF_VL_FIELD_SYMLINK_TARGET_PATH,
EBPF_VL_FIELD_MOD_VERSION,
EBPF_VL_FIELD_MOD_SRCVERSION,
EBPF_VL_FIELD_DNS_BODY,
};

// Convenience macro to iterate all the variable length fields in an event
Expand Down Expand Up @@ -341,13 +347,19 @@ struct ebpf_process_load_module_event {

enum ebpf_net_info_transport {
EBPF_NETWORK_EVENT_TRANSPORT_TCP = 1,
EBPF_NETWORK_EVENT_TRANSPORT_UDP = 2,
};

enum ebpf_net_info_af {
EBPF_NETWORK_EVENT_AF_INET = 1,
EBPF_NETWORK_EVENT_AF_INET6 = 2,
};

enum ebpf_net_udp_info {
EBPF_NETWORK_EVENT_SKB_CONSUME_UDP = 1,
EBPF_NETWORK_EVENT_IP_SEND_UDP = 2,
fearful-symmetry marked this conversation as resolved.
Show resolved Hide resolved
};

struct ebpf_net_info_tcp_close {
uint64_t bytes_sent;
uint64_t bytes_received;
Expand Down Expand Up @@ -379,10 +391,22 @@ struct ebpf_net_event {
char comm[TASK_COMM_LEN];
} __attribute__((packed));

struct ebpf_dns_event {
struct ebpf_event_header hdr;
struct ebpf_pid_info pids;
struct ebpf_net_info net;
char comm[TASK_COMM_LEN];
enum ebpf_net_udp_info udp_evt;
uint64_t original_len;
// Variable length fields: dns body
struct ebpf_varlen_fields_start vl_fields;
} __attribute__((packed));

// Basic event statistics
struct ebpf_event_stats {
uint64_t lost; // lost events due to a full ringbuffer
uint64_t sent; // events sent through the ringbuffer
uint64_t lost; // lost events due to a full ringbuffer
uint64_t sent; // events sent through the ringbuffer
uint64_t dns_zero_body; // indicates that the dns body of a sk_buff was unavailable
};

#endif // EBPF_EVENTPROBE_EBPFEVENTPROTO_H
160 changes: 160 additions & 0 deletions GPL/Events/Network/Probe.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "Helpers.h"
#include "Network.h"
#include "State.h"
#include "Varlen.h"

DECL_FUNC_RET(inet_csk_accept);

Expand All @@ -43,6 +44,165 @@ static int inet_csk_accept__exit(struct sock *sk)
return 0;
}

static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type)
{
if (skb == NULL) {
goto out;
}

if (ebpf_events_is_trusted_pid())
goto out;

struct ebpf_dns_event *event = get_event_buffer();
if (event == NULL)
goto out;

// read from skbuf
unsigned char *skb_head = BPF_CORE_READ(skb, head);
// get lengths
u16 net_header_offset = BPF_CORE_READ(skb, network_header);
u16 transport_header_offset = BPF_CORE_READ(skb, transport_header);
size_t network_header_size = 0;
u8 proto = 0;

struct iphdr ip_hdr;
bpf_core_read(&ip_hdr, sizeof(struct iphdr), skb_head + net_header_offset);
if (ip_hdr.version == 4) {
proto = ip_hdr.protocol;

if (bpf_probe_read(event->net.saddr, 4, &ip_hdr.saddr) != 0) {
goto out;
};

if (bpf_probe_read(event->net.daddr, 4, &ip_hdr.daddr) != 0) {
goto out;
}
network_header_size = sizeof(struct iphdr);
event->net.family = EBPF_NETWORK_EVENT_AF_INET;
} else if (ip_hdr.version == 6) {
struct ipv6hdr ip6_hdr;
bpf_core_read(&ip6_hdr, sizeof(struct ipv6hdr), skb_head + net_header_offset);
proto = ip6_hdr.nexthdr;

if (bpf_probe_read(event->net.saddr6, 16, ip6_hdr.saddr.in6_u.u6_addr8) != 0) {
goto out;
}

if (bpf_probe_read(event->net.daddr6, 16, ip6_hdr.daddr.in6_u.u6_addr8) != 0) {
goto out;
}

network_header_size = sizeof(struct ipv6hdr);
event->net.family = EBPF_NETWORK_EVENT_AF_INET6;
} else {
goto out;
}

if (proto != IPPROTO_UDP) {
goto out;
}

struct udphdr udp_hdr;
if (bpf_core_read(&udp_hdr, sizeof(struct udphdr), skb_head + transport_header_offset) != 0) {
goto out;
}

uint16_t dport = bpf_ntohs(udp_hdr.dest);
uint16_t sport = bpf_ntohs(udp_hdr.source);
// filter out non-DNS packets
if (sport != 53 && dport != 53) {
goto out;
}

event->net.dport = dport;
event->net.sport = sport;
event->net.transport = EBPF_NETWORK_EVENT_TRANSPORT_UDP;

struct task_struct *task = (struct task_struct *)bpf_get_current_task();
ebpf_pid_info__fill(&event->pids, task);
bpf_get_current_comm(event->comm, TASK_COMM_LEN);
event->hdr.ts = bpf_ktime_get_ns();

// constrain the read size to make the verifier happy
// see skb_headlen() in skbuff.h
size_t readsize = BPF_CORE_READ(skb, len);
size_t datalen = BPF_CORE_READ(skb, data_len);
size_t headlen = readsize - datalen;
// headlen of zero indicates we have no non-paged data, and thus cannot read
// anything from the root data node
if (headlen == 0) {
u32 zero = 0;
struct ebpf_event_stats *es = bpf_map_lookup_elem(&ringbuf_stats, &zero);
if (es != NULL) {
es->dns_zero_body++;
}
goto out;
}

size_t body_size = headlen;
// for ip_send_skb(), we're at a point in the network stack where we've just prepended the IP
// header, so the normal headlen for the skb_buff includes the headers. Reset them so we *just*
// read the application body.
if (evt_type == EBPF_NETWORK_EVENT_IP_SEND_UDP) {
body_size = headlen - (sizeof(struct udphdr) + network_header_size);
}

event->original_len = headlen;
if (body_size > MAX_DNS_PACKET) {
body_size = MAX_DNS_PACKET;
}

ebpf_vl_fields__init(&event->vl_fields);
struct ebpf_varlen_field *field;
field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_DNS_BODY);
long ret = bpf_probe_read_kernel(field->data, body_size,
skb_head + transport_header_offset + sizeof(struct udphdr));
fearful-symmetry marked this conversation as resolved.
Show resolved Hide resolved
if (ret != 0) {
bpf_printk("error reading in data buffer: %d", ret);
goto out;
}
ebpf_vl_field__set_size(&event->vl_fields, field, body_size);

event->hdr.type = EBPF_EVENT_NETWORK_DNS_PKT;
event->udp_evt = evt_type;
ebpf_ringbuf_write(&ringbuf, event, EVENT_SIZE(event), 0);

out:
return 0;
}

SEC("fentry/ip_send_skb")
int BPF_PROG(fentry__ip_send_skb, struct net *net, struct sk_buff *skb)
{
return udp_skb_handle(skb, EBPF_NETWORK_EVENT_IP_SEND_UDP);
}

SEC("fentry/skb_consume_udp")
int BPF_PROG(fentry__skb_consume_udp, struct sock *sk, struct sk_buff *skb, int len)
{
// skip peek operations
if (len < 0) {
return 0;
}
return udp_skb_handle(skb, EBPF_NETWORK_EVENT_SKB_CONSUME_UDP);
}

SEC("kprobe/ip_send_skb")
int BPF_KPROBE(kprobe__ip_send_udp, struct net *net, struct sk_buff *skb)
{
return udp_skb_handle(skb, EBPF_NETWORK_EVENT_IP_SEND_UDP);
}

SEC("kprobe/skb_consume_udp")
int BPF_KPROBE(kprobe__skb_consume_udp, struct net *net, struct sk_buff *skb, int len)
{
// skip peek operations
if (len < 0) {
return 0;
}
return udp_skb_handle(skb, EBPF_NETWORK_EVENT_SKB_CONSUME_UDP);
fearful-symmetry marked this conversation as resolved.
Show resolved Hide resolved
}

SEC("fexit/inet_csk_accept")
int BPF_PROG(fexit__inet_csk_accept)
{
Expand Down
52 changes: 48 additions & 4 deletions non-GPL/Events/EventsTrace/EventsTrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ enum cmdline_opts {
NETWORK_CONNECTION_ATTEMPTED,
NETWORK_CONNECTION_ACCEPTED,
NETWORK_CONNECTION_CLOSED,
NETWORK_DNS_PKT,
CMDLINE_MAX
};

Expand All @@ -89,6 +90,7 @@ static uint64_t cmdline_to_lib[CMDLINE_MAX] = {
x(NETWORK_CONNECTION_ATTEMPTED)
x(NETWORK_CONNECTION_ACCEPTED)
x(NETWORK_CONNECTION_CLOSED)
x(NETWORK_DNS_PKT)
#undef x
// clang-format on
};
Expand All @@ -114,6 +116,7 @@ static const struct argp_option opts[] = {
{"process-load-module", PROCESS_LOAD_MODULE, NULL, false, "Print kernel module load events", 0},
{"net-conn-accept", NETWORK_CONNECTION_ACCEPTED, NULL, false,
"Print network connection accepted events", 0},
{"net-conn-dns-pkt", NETWORK_DNS_PKT, NULL, false, "Print DNS events", 0},
{"net-conn-attempt", NETWORK_CONNECTION_ATTEMPTED, NULL, false,
"Print network connection attempted events", 0},
{"net-conn-closed", NETWORK_CONNECTION_CLOSED, NULL, false,
Expand Down Expand Up @@ -173,6 +176,7 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
case NETWORK_CONNECTION_ACCEPTED:
case NETWORK_CONNECTION_ATTEMPTED:
case NETWORK_CONNECTION_CLOSED:
case NETWORK_DNS_PKT:
g_events_env |= cmdline_to_lib[key];
break;
case ARGP_KEY_ARG:
Expand Down Expand Up @@ -965,9 +969,8 @@ static void out_ip6_addr(const char *name, const void *addr)
printf("\"%s\":\"%s\"", name, buf);
}

static void out_net_info(const char *name, struct ebpf_net_event *evt)
static void out_net_info(const char *name, struct ebpf_net_info *net, struct ebpf_event_header *hdr)
{
struct ebpf_net_info *net = &evt->net;

printf("\"%s\":", name);
out_object_start();
Expand All @@ -977,6 +980,10 @@ static void out_net_info(const char *name, struct ebpf_net_event *evt)
out_string("transport", "TCP");
out_comma();
break;
case EBPF_NETWORK_EVENT_TRANSPORT_UDP:
out_string("transport", "UDP");
out_comma();
break;
fearful-symmetry marked this conversation as resolved.
Show resolved Hide resolved
}

switch (net->family) {
Expand Down Expand Up @@ -1015,7 +1022,7 @@ static void out_net_info(const char *name, struct ebpf_net_event *evt)
out_comma();
out_int("network_namespace", net->netns);

switch (evt->hdr.type) {
switch (hdr->type) {
case EBPF_EVENT_NETWORK_CONNECTION_CLOSED:
out_comma();
out_uint("bytes_sent", net->tcp.close.bytes_sent);
Expand All @@ -1037,7 +1044,7 @@ static void out_network_event(const char *name, struct ebpf_net_event *evt)
out_pid_info("pids", &evt->pids);
out_comma();

out_net_info("net", evt);
out_net_info("net", &evt->net, &evt->hdr);
out_comma();

out_string("comm", (const char *)&evt->comm);
Expand All @@ -1051,6 +1058,40 @@ static void out_network_connection_accepted_event(struct ebpf_net_event *evt)
out_network_event("NETWORK_CONNECTION_ACCEPTED", evt);
}

static void out_network_dns_event(struct ebpf_dns_event *event)
{
out_object_start();
out_event_type("DNS_EVENT");
out_comma();

out_pid_info("pids", &event->pids);
out_comma();

out_net_info("net", &event->net, &event->hdr);
out_comma();

out_string("comm", (const char *)&event->comm);
out_comma();

printf("\"data\":");
out_array_start();
struct ebpf_varlen_field *field;
FOR_EACH_VARLEN_FIELD(event->vl_fields, field)
{
for (size_t i = 0; i < field->size; i++) {
uint8_t part = field->data[i];
printf("%d", part);
if (i < field->size - 1) {
printf(", ");
}
}
}
out_array_end();

out_object_end();
out_newline();
}

static void out_network_connection_attempted_event(struct ebpf_net_event *evt)
{
out_network_event("NETWORK_CONNECTION_ATTEMPTED", evt);
Expand Down Expand Up @@ -1130,6 +1171,9 @@ static int event_ctx_callback(struct ebpf_event_header *evt_hdr)
case EBPF_EVENT_NETWORK_CONNECTION_CLOSED:
out_network_connection_closed_event((struct ebpf_net_event *)evt_hdr);
break;
case EBPF_EVENT_NETWORK_DNS_PKT:
out_network_dns_event((struct ebpf_dns_event *)evt_hdr);
break;
}

return 0;
Expand Down
Loading
Loading