Table of contents
In this blog we are going to explore a POC that I did with eBPF . I have a basic express server which has a route /env which exposes a secret key, I restricted access to that route with the help of ePBF
Environment setup
Used VirtualBox to run a Debina image (12.5.0) and setup a lab.
Now once the virtual OS was running, installed the below dependencies for eBPF development.
sudo apt-get update
sudo apt-get install linux-headers-$(uname -r)
sudo apt-get install llvm clang
sudo apt-get install bpfcc-tools libbpfcc-dev libbpf-dev
sudo aptitude -y install bpftool
to install node
sudo apt-get install node npm
Application server
now that the environment is setup it's time to write some code let's start with the express server.
const express = require('express')
const app = express()
app.use(express.json())
app.all('/',(req,res)=>{
res.status(200).json({'message' : "hello there !"})
})
app.get('/env',(req,res)=>{
return res.status(200).json({'key':'secret'});
})
app.listen(3001,()=>{
console.log( --- server started on 3001 ----)
})
the server has two routes one is the base route the other one is /env
which exposes a secret key.
now with the help of eBPF we will try to block request to the /env
path on our machine.
injecting eBPF code
In the eBPF code logic what I am going to do is check every http packet on the xdp data path, if the request path contains /env drop the packet else let it through.
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <bpf/bpf_helpers.h>
// Define IPPROTO_TCP if not already defined
#ifndef IPPROTO_TCP
#define IPPROTO_TCP 6
#endif
static int strlen(const char *str) {
int len = 0;
while (*str != '\0') {
len++;
str++;
}
return len;
}
static int strncmp(const char *s1, const char *s2, __u64 len) {
for (__u64 i = 0; i < len; i++) {
if (s1[i] != s2[i])
return s1[i] - s2[i];
if (s1[i] == '\0')
return 0;
}
return 0;
}
SEC("xdp")
int hello(struct xdp_md *ctx) {
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct ethhdr *eth = data;
if (data + sizeof(*eth) > data_end)
return XDP_PASS;
if (eth->h_proto != __constant_htons(ETH_P_IP))
return XDP_PASS;
struct iphdr *ip = data + sizeof(struct ethhdr);
if (data + sizeof(struct ethhdr) + sizeof(struct iphdr) > data_end)
return XDP_PASS;
if (ip->protocol != IPPROTO_TCP)
return XDP_PASS;
struct tcphdr *tcp = data + sizeof(struct ethhdr) + (ip->ihl << 2);
if (data + sizeof(struct ethhdr) + (ip->ihl << 2) + sizeof(struct tcphdr) > data_end)
return XDP_PASS;
// Pointer to the start of TCP payload
void *tcp_payload = data + sizeof(struct ethhdr) + (ip->ihl << 2) + (tcp->doff << 2);
void *tcp_payload_end = data_end;
// HTTP request line for the specific path
char *request_line = "GET /env HTTP/1.1";
int request_line_len = strlen(request_line);
bpf_printk("%s",tcp_payload);
// Check if the HTTP request line matches the specific path
if (tcp_payload + request_line_len <= tcp_payload_end &&
strncmp(tcp_payload, request_line, request_line_len) == 0) {
// Match found, drop the packet
bpf_printk("Match found, dropping packet\n");
return XDP_DROP;
}
bpf_printk("Match now found, allow packet\n");
// No match found, allow the packet to pass through
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
now to compile the code with the makefile below
TARGETS = hello
all: $(TARGETS)
.PHONY: all
$(TARGETS): %: %.bpf.o
%.bpf.o: %.bpf.c
clang \
-target bpf \
-I/usr/include/$(shell uname -m)-linux-gnu \
-g \
-O2 -o $@ -c $<
clean:
- rm *.bpf.o
- rm -f /sys/fs/bpf/hello
after running the makefile ( make hello
) , there will be a object file named , in this case its hello.bpf.c
now attach the eBPF program to the local loopback network interface with the below command
ip link set dev lo xdp obj hello.bpf.o sec xdp
we can see the attached program with bpftool net list
and to monitor the logs so that we can see the inner working of the eBPF program
bpftool prog trace log
now if we hit the server on base url with we can see the logs on the terminal.
now if I hit the /env
we can see that the packets are blocked.
to detach the program
bpftool net detach xdp dev lo
It was fun experiment .
and I know ....
until next time ๐๐ฝโโ๏ธ.