Skip to content
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
7 changes: 5 additions & 2 deletions .mk/bc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ define PROGRAMS
"xfrm_input_kprobe": "kprobe",
"xfrm_input_kretprobe": "kretprobe",
"xfrm_output_kprobe": "kprobe",
"xfrm_output_kretprobe": "kretprobe"
"xfrm_output_kretprobe": "kretprobe",
"probe_entry_SSL_write": "uprobe"
}
endef

Expand All @@ -38,7 +39,9 @@ define MAPS
"filter_map":"lpm_trie",
"peer_filter_map":"lpm_trie",
"ipsec_ingress_map":"hash",
"ipsec_egress_map":"hash"
"ipsec_egress_map":"hash",
"ssl_data_event_map":"ringbuf",
"dns_name_map":"per_cpu_array"
}
endef

Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ ARG TARGETARCH
FROM docker.io/library/golang:1.24 as builder

ARG TARGETARCH
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this must not be removed, it's used in the line below:

RUN CGO_ENABLED=0 GOARCH=$TARGETARCH go build

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm that I don't remember why will revert as well and if needed I will keep it locally

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe when running from mac you need to pass explicitly MULTIARCH_TARGETS=arm64

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps that's also what make you have different bytecode than the CI (and hence get it rejected)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that option is there for make docker-generate


ARG LDFLAGS

WORKDIR /opt/app-root
Expand Down
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ endif
LOCAL_GENERATOR_IMAGE ?= ebpf-generator:latest
CILIUM_EBPF_VERSION := v0.19.0
GOLANGCI_LINT_VERSION = v2.2.1
GO_VERSION = "1.24.4"
PROTOC_VERSION = "3.19.4"
GO_VERSION = 1.24.4
PROTOC_VERSION = 3.19.4
PROTOC_GEN_GO_VERSION="v1.35.1"
PROTOC_GEN_GO_GRPC_VERSION="v1.5.1"
CLANG ?= clang
Expand Down Expand Up @@ -151,7 +151,7 @@ generate: gen-bpf gen-protobuf
.PHONY: docker-generate
docker-generate: ## Create the container that generates the eBPF binaries
@echo "### Creating the container that generates the eBPF binaries"
$(OCI_BIN) build . -f scripts/generators.Dockerfile -t $(LOCAL_GENERATOR_IMAGE) --platform=linux/amd64 --build-arg EXTENSION="x86_64" --build-arg PROTOCVERSION="$(PROTOC_VERSION)" --build-arg GOVERSION="$(GO_VERSION)"
$(OCI_BIN) buildx build . -f scripts/generators.Dockerfile -t $(LOCAL_GENERATOR_IMAGE) --platform=linux/amd64 --build-arg EXTENSION="x86_64" --build-arg PROTOCVERSION="$(PROTOC_VERSION)" --build-arg GOVERSION="$(GO_VERSION)" --load
$(OCI_BIN) run --privileged --rm -v $(shell pwd):/src $(LOCAL_GENERATOR_IMAGE)

.PHONY: compile
Expand Down Expand Up @@ -205,7 +205,7 @@ create-and-deploy-kind-cluster: prereqs ## Create a kind cluster and deploy the

.PHONY: destroy-kind-cluster
destroy-kind-cluster: ## Destroy the kind cluster.
oc delete -f scripts/agent.yml
kubectl delete -f scripts/agent.yml
kind delete cluster

##@ Images
Expand Down
1 change: 1 addition & 0 deletions bpf/configs.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ volatile const u8 enable_network_events_monitoring = 0;
volatile const u8 network_events_monitoring_groupid = 0;
volatile const u8 enable_pkt_translation_tracking = 0;
volatile const u8 enable_ipsec = 0;
volatile const u8 enable_openssl_tracking = 0;
#endif //__CONFIGS_H__
17 changes: 11 additions & 6 deletions bpf/dns_tracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,17 @@ static __always_inline int track_dns_packet(struct __sk_buff *skb, pkt_info *pkt
pkt->dns_flags = flags;

// Copy raw QNAME bytes (label-encoded) and let userspace decode to dotted form
__builtin_memset(pkt->dns_name, 0, DNS_NAME_MAX_LEN);
u32 qname_off = dns_offset + sizeof(struct dns_header);
// Best-effort fixed-size copy; safe for verifier (constant size)
(void)bpf_skb_load_bytes(skb, qname_off, pkt->dns_name, DNS_NAME_MAX_LEN - 1);
// Ensure null-termination
pkt->dns_name[DNS_NAME_MAX_LEN - 1] = '\0';
// Use per-CPU map to avoid stack limit
u32 key = 0;
dns_name_buffer *dns_buf = bpf_map_lookup_elem(&dns_name_map, &key);
if (dns_buf) {
u32 qname_off = dns_offset + sizeof(struct dns_header);
// Best-effort fixed-size copy; safe for verifier (constant size)
(void)bpf_skb_load_bytes(skb, qname_off, dns_buf->name, DNS_NAME_MAX_LEN - 1);
// Ensure null-termination
dns_buf->name[DNS_NAME_MAX_LEN - 1] = '\0';
pkt->dns_name = dns_buf->name;
}
} // end of dns response
}
return ret;
Expand Down
13 changes: 11 additions & 2 deletions bpf/flows.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@
*/
#include "ipsec.h"

/*
* Defines ssl tracker
*/
#include "openssl_tracker.h"

// return 0 on success, 1 if capacity reached
static __always_inline int add_observed_intf(flow_metrics *value, pkt_info *pkt, u32 if_index,
u8 direction) {
Expand Down Expand Up @@ -118,7 +123,9 @@ static inline void update_dns(additional_metrics *extra_metrics, pkt_info *pkt,
extra_metrics->dns_record.id = pkt->dns_id;
extra_metrics->dns_record.flags = pkt->dns_flags;
extra_metrics->dns_record.latency = pkt->dns_latency;
__builtin_memcpy(extra_metrics->dns_record.name, pkt->dns_name, DNS_NAME_MAX_LEN);
if (pkt->dns_name != NULL) {
__builtin_memcpy(extra_metrics->dns_record.name, pkt->dns_name, DNS_NAME_MAX_LEN);
}
}
if (dns_errno != 0) {
extra_metrics->dns_record.errno = dns_errno;
Expand Down Expand Up @@ -254,7 +261,9 @@ static inline int flow_monitor(struct __sk_buff *skb, u8 direction) {
new_metrics.dns_record.id = pkt.dns_id;
new_metrics.dns_record.flags = pkt.dns_flags;
new_metrics.dns_record.latency = pkt.dns_latency;
__builtin_memcpy(new_metrics.dns_record.name, pkt.dns_name, DNS_NAME_MAX_LEN);
if (pkt.dns_name != NULL) {
__builtin_memcpy(new_metrics.dns_record.name, pkt.dns_name, DNS_NAME_MAX_LEN);
}
new_metrics.dns_record.errno = dns_errno;
long ret =
bpf_map_update_elem(&additional_flow_metrics, &id, &new_metrics, BPF_NOEXIST);
Expand Down
16 changes: 16 additions & 0 deletions bpf/maps_definition.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ struct {
__uint(pinning, LIBBPF_PIN_BY_NAME);
} global_counters SEC(".maps");

// Per-CPU temporary storage for DNS name (avoids stack limit)
struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__type(key, u32);
__type(value, dns_name_buffer);
__uint(max_entries, 1);
__uint(pinning, LIBBPF_PIN_BY_NAME);
} dns_name_map SEC(".maps");

// LPM trie map used to filter traffic by IP address CIDR
struct {
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
Expand Down Expand Up @@ -97,4 +106,11 @@ struct {
__uint(pinning, LIBBPF_PIN_BY_NAME);
} ipsec_egress_map SEC(".maps");

// Ringbuf for SSL data events
struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 1 << 27); // 16KB * 1000 events/sec * 5sec "eviction time" = ~128MB
__uint(pinning, LIBBPF_PIN_BY_NAME);
} ssl_data_event_map SEC(".maps");

#endif //__MAPS_DEFINITION_H__
65 changes: 65 additions & 0 deletions bpf/openssl_tracker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* OpenSSL monitoring uprobe/uretprobe eBPF hook.
*/

#ifndef __OPENSSL_TRACKER_H__
#define __OPENSSL_TRACKER_H__

#include "utils.h"

static inline void generate_SSL_data_event(struct pt_regs *ctx, u64 pid_tgid, u8 ssl_type,
const char *buf, uint32_t len) {
if (len <= 0) {
return;
}

struct ssl_data_event_t *event;
event = bpf_ringbuf_reserve(&ssl_data_event_map, sizeof(*event), 0);
if (!event) {
return;
}
event->timestamp_ns = bpf_ktime_get_ns();
event->pid_tgid = pid_tgid;
event->ssl_type = ssl_type;
event->data_len = len < MAX_DATA_SIZE_OPENSSL ? len : MAX_DATA_SIZE_OPENSSL;
bpf_probe_read_user(&event->data, event->data_len, buf);
bpf_ringbuf_submit(event, 0);
}

// int SSL_write(SSL *ssl, const void *buf, int num);
// https://github.com/openssl/openssl/blob/master/ssl/ssl_lib.c#L2666
SEC("uprobe/SSL_write")
int probe_entry_SSL_write(struct pt_regs *ctx) {
if (enable_openssl_tracking == 0) {
return 0;
}

u64 pid_tgid = bpf_get_current_pid_tgid();

BPF_PRINTK("openssl uprobe/SSL_write pid: %d\n", pid_tgid);
// https://github.com/openssl/openssl/blob/master/ssl/ssl_local.h#L1233
void *ssl = (void *)PT_REGS_PARM1(ctx);

u32 ssl_type;
int ret;

ret = bpf_probe_read_user(&ssl_type, sizeof(ssl_type), (u32 *)ssl);
if (ret) {
BPF_PRINTK("(OPENSSL) bpf_probe_read ssl_type_ptr failed, ret: %d\n", ret);
return 0;
}
const char *buf = (const char *)PT_REGS_PARM2(ctx);
uint32_t num = (uint32_t)PT_REGS_PARM3(ctx); // Third parameter: number of bytes to write

BPF_PRINTK("openssl uprobe/SSL_write type: %d, buf: %p, num: %d\n", ssl_type, buf, num);

// Read the data immediately in the uprobe (before SSL_write processes it)
// This captures the plaintext before encryption
if (num > 0) {
generate_SSL_data_event(ctx, pid_tgid, ssl_type, buf, num);
}

return 0;
}

#endif /* __OPENSSL_TRACKER_H__ */
20 changes: 19 additions & 1 deletion bpf/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ typedef __u64 u64;
#define MAX_PAYLOAD_SIZE 256
#define DNS_NAME_MAX_LEN 32

// Per-CPU temporary storage for DNS name (avoids stack limit)
typedef struct dns_name_buffer_t {
char name[DNS_NAME_MAX_LEN];
} dns_name_buffer;

// according to field 61 in https://www.iana.org/assignments/ipfix/ipfix.xhtml
typedef enum direction_t {
INGRESS,
Expand Down Expand Up @@ -194,7 +199,7 @@ typedef struct pkt_info_t {
u16 dns_id;
u16 dns_flags;
u64 dns_latency;
char dns_name[DNS_NAME_MAX_LEN];
char *dns_name;
} pkt_info;

// Structure for payload metadata
Expand Down Expand Up @@ -280,4 +285,17 @@ struct filter_value_t {
// Force emitting enums/structs into the ELF
const static struct filter_value_t *unused12 __attribute__((unused));

#define MAX_DATA_SIZE_OPENSSL 1024 * 16
// SSL data event
struct ssl_data_event_t {
u64 timestamp_ns;
u64 pid_tgid;
s32 data_len;
u8 ssl_type;
char data[MAX_DATA_SIZE_OPENSSL];
} ssl_data_event;

// Force emitting enums/structs into the ELF
const static struct ssl_data_event_t *unused13 __attribute__((unused));

#endif /* __TYPES_H__ */
Loading
Loading