aboutsummaryrefslogtreecommitdiff
path: root/pa4_ipsec/ebpf_ipsec.c
diff options
context:
space:
mode:
authorJack Sangdahl <jack@pngu.org>2024-12-15 22:37:30 -0700
committerJack Sangdahl <jack@pngu.org>2024-12-15 22:37:30 -0700
commit9c5b2396436398a3e205831c007ecc4e2b2c604e (patch)
tree763566660faf574ab04fba71b82e3c32c0daac0d /pa4_ipsec/ebpf_ipsec.c
parentd3b273cbebd8a4d6b890d11bd4ae505b45abf739 (diff)
downloadecen5273-master.tar.gz
ecen5273-master.zip
Programming Assignment 4: eBPF IPsecHEADmaster
Signed-off-by: Jack Sangdahl <jack@pngu.org>
Diffstat (limited to 'pa4_ipsec/ebpf_ipsec.c')
-rw-r--r--pa4_ipsec/ebpf_ipsec.c194
1 files changed, 194 insertions, 0 deletions
diff --git a/pa4_ipsec/ebpf_ipsec.c b/pa4_ipsec/ebpf_ipsec.c
new file mode 100644
index 0000000..1a2800a
--- /dev/null
+++ b/pa4_ipsec/ebpf_ipsec.c
@@ -0,0 +1,194 @@
+// eBPF IPsec
+// Jack Sangdahl
+// 28 November 2024
+#include <vmlinux.h>
+
+#include <bpf/bpf_endian.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+
+#define TC_ACT_OK 0
+#define ETH_P_IP 0x0800 /* Internet Protocol packet */
+#define UDP_HDR_LEN 8 /* UDP header size */
+#define UDP_PORT 12345 /* Port number to filter */
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __uint(max_entries, 1);
+ __type(key, __u32);
+ __type(value, __u64);
+} ingress_counter SEC(".maps");
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __uint(max_entries, 1);
+ __type(key, __u32);
+ __type(value, __u64);
+} egress_counter SEC(".maps");
+
+struct {
+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+ __uint(max_entries, 1);
+ __type(key, __u32);
+ __type(value, __u32);
+} shared_key SEC(".maps");
+
+struct {
+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+ __uint(max_entries, 1);
+ __type(key, __u32);
+ __type(value, __u32);
+} key_ready SEC(".maps");
+
+static __always_inline int handle_packet(struct __sk_buff *ctx, bool ingress);
+static __always_inline void count_packets(struct __sk_buff *ctx, bool ingress);
+static __always_inline __u32 generate_private_key(void);
+static __always_inline __u32 mod_exp(__u32 base, __u32 exp, __u32 mod);
+static __always_inline __u32 extract_public_key(void *data, void *data_end);
+static __always_inline void xor_encrypt_decrypt(void *payload, __u32 len,
+ __u32 shared_key);
+static __always_inline __u32 derive_shared_key(__u32 public_key,
+ __u32 private_key);
+static __always_inline void replace_with_public_key(void *data, void *data_end,
+ __u32 public_key);
+static __always_inline void print_udp_content(void *data, void *data_end,
+ struct udphdr *l4);
+
+/// @tchook {"ifindex":2, "attach_point":"BPF_TC_INGRESS"}
+/// @tcopts {"handle":1, "priority":1}
+SEC("tc")
+int tc_ingress(struct __sk_buff *ctx) { return handle_packet(ctx, true); }
+
+/// @tchook {"ifindex":2, "attach_point":"BPF_TC_EGRESS"}
+/// @tcopts {"handle":1, "priority":1}
+SEC("tc")
+int tc_egress(struct __sk_buff *ctx) { return handle_packet(ctx, false); }
+
+static __always_inline int handle_packet(struct __sk_buff *ctx, bool ingress) {
+ void *data_end = (void *)(__u64)ctx->data_end;
+ void *data = (void *)(__u64)ctx->data;
+ struct ethhdr *l2;
+ struct iphdr *l3;
+ struct udphdr *l4;
+ if (ctx->protocol != bpf_htons(ETH_P_IP))
+ return TC_ACT_OK;
+ l2 = data;
+ if ((void *)(l2 + 1) > data_end)
+ return TC_ACT_OK;
+ l3 = (struct iphdr *)(l2 + 1);
+ if ((void *)(l3 + 1) > data_end)
+ return TC_ACT_OK;
+ if (l3->protocol != IPPROTO_UDP)
+ return TC_ACT_OK;
+ l4 = (struct udphdr *)(l3 + 1);
+ if ((void *)(l4 + 1) > data_end)
+ return TC_ACT_OK;
+ if (bpf_ntohs(l4->source) != UDP_PORT && bpf_ntohs(l4->dest) != UDP_PORT)
+ return TC_ACT_OK;
+ bpf_printk("Received UDP packet on port 12345: src_port: %d, dst_port: %d",
+ bpf_ntohs(l4->source), bpf_ntohs(l4->dest));
+ __u32 key = 0;
+ __u32 *shared_key_ptr = bpf_map_lookup_elem(&shared_key, &key);
+ __u32 *key_ready_ptr = bpf_map_lookup_elem(&key_ready, &key);
+ if (shared_key_ptr && key_ready_ptr && *key_ready_ptr == 1) {
+ void *payload = (void *)(l4 + 1);
+ __u16 payload_len = bpf_ntohs(l4->len) - UDP_HDR_LEN;
+ if (payload + payload_len <= data_end)
+ if (ingress) {
+ xor_encrypt_decrypt(payload, payload_len, *shared_key_ptr);
+ bpf_printk("Decrypted UDP payload: %s", (char *)payload);
+ } else {
+ xor_encrypt_decrypt(payload, payload_len, *shared_key_ptr);
+ bpf_printk("Encrypted UDP payload: %s", (char *)payload);
+ }
+ }
+ count_packets(ctx, ingress);
+ return TC_ACT_OK;
+}
+
+static __always_inline void count_packets(struct __sk_buff *ctx, bool ingress) {
+ __u32 key = 0;
+ __u64 *count;
+ if (ingress) {
+ count = bpf_map_lookup_elem(&ingress_counter, &key);
+ if (count) {
+ __sync_fetch_and_add(count, 1);
+ bpf_printk("Ingress packet count: %llu", *count);
+ }
+ } else {
+ count = bpf_map_lookup_elem(&egress_counter, &key);
+ if (count) {
+ __sync_fetch_and_add(count, 1);
+ bpf_printk("Egress packet count: %llu", *count);
+ }
+ }
+}
+
+static __always_inline __u32 generate_private_key(void) {
+ return bpf_get_prandom_u32() % 23;
+}
+
+static __always_inline void xor_encrypt_decrypt(void *payload, __u32 len,
+ __u32 shared_key) {
+ __u8 *data = (__u8 *)payload;
+ for (__u32 i = 0; i < len; i++)
+ data[i] ^= ((__u8 *)&shared_key)[i % sizeof(shared_key)];
+}
+
+static __always_inline __u32 mod_exp(__u32 base, __u32 exp, __u32 mod) {
+ __u32 result = 1;
+ while (exp) {
+ if (exp % 2 == 1)
+ result = (result * base) % mod;
+ base = (base * base) % mod;
+ exp /= 2;
+ }
+ return result;
+}
+
+static __always_inline __u32 extract_public_key(void *data, void *data_end) {
+ char buf[16] = {};
+ if ((data + 16) > data_end)
+ return 0;
+ bpf_probe_read_kernel_str(buf, sizeof(buf), data);
+ unsigned long result;
+ int ret = bpf_strtoul(buf, result, 10, 0);
+ if (ret < 0)
+ return ret;
+ return result;
+}
+
+static __always_inline __u32 derive_shared_key(__u32 public_key,
+ __u32 private_key) {
+ return mod_exp(public_key, private_key, 23);
+}
+
+static __always_inline void replace_with_public_key(void *data, void *data_end,
+ __u32 public_key) {
+ char buf[16] = {};
+ int len = bpf_snprintf(buf, sizeof(buf), "%u", (__u64 *)&public_key,
+ sizeof(public_key));
+ if ((data + len) <= data_end) {
+ bpf_probe_read_kernel_str(data, len, buf);
+ bpf_printk("Replaced payload with public key: %s", buf);
+ }
+}
+
+static __always_inline void print_udp_content(void *data, void *data_end,
+ struct udphdr *l4) {
+ void *payload = (void *)(l4 + 1);
+ if (payload >= data_end)
+ return;
+ __u16 payload_len = bpf_ntohs(l4->len) - UDP_HDR_LEN;
+ if (payload + payload_len > data_end)
+ return;
+ char buf[33] = {};
+ __u32 len = payload_len < 32 ? payload_len : 32;
+ if (payload + len <= data_end) {
+ bpf_probe_read_kernel(buf, len, payload);
+ buf[len] = '\0';
+ bpf_printk("UDP payload: %s", buf);
+ }
+}
+
+char __license[] SEC("license") = "GPL";