What is Layer 7 DDoS and Why Is It Harder to Stop?
A Layer 7 DDoS attack (also called an application-layer DDoS or HTTP flood) overwhelms a web server by sending enormous volumes of seemingly legitimate HTTP requests rather than raw network packets.
Unlike Layer 3/4 floods, Layer 7 attacks complete a full TCP three-way handshake — making them indistinguishable from real users at the network level. They bypass standard iptables rate-limiting rules without exhausting CPU resources first. Modern botnets frequently use this technique because traditional firewalls cannot inspect HTTP headers without terminating the TCP connection — an operation that is far too expensive at high traffic volumes.
Why XDP + eBPF Is the Right Tool
eBPF (Extended Berkeley Packet Filter) allows you to run sandboxed programs inside the Linux kernel without modifying kernel source code. Paired with XDP (eXpress Data Path), these programs execute directly inside the NIC driver — the earliest possible point in the networking stack.
XDP is the fastest software-based mitigation available on Linux. On a 10Gbps unmetered Bare Metal Servers, an XDP program can process and drop packets faster than the OS can schedule a user-space process to even acknowledge them.
The Challenge: Parsing All Four Network Layers in eBPF
XDP operates at the lowest level of the Linux networking stack. To reach Layer 7 (HTTP data), your eBPF program must manually walk the entire packet structure: Ethernet (14 bytes), IPv4 (20 bytes), and TCP (20 bytes). The Linux kernel eBPF verifier performs strict bounds checking on every memory access.
Step 1: Write the eBPF C Program
This guide is tested on Ubuntu 24.04 LTS. Create a file named l7_firewall.c. When it detects a malicious HTTP signature, it returns XDP_DROP, discarding the packet instantly at the NIC level.
c
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/in.h>
#include <bpf/bpf_helpers.h>
SEC("xdp")
int xdp_l7_filter(struct xdp_md *ctx) {
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct ethhdr *eth = data;
if ((void *)(eth + 1) > data_end) return XDP_PASS;
if (eth->h_proto != __constant_htons(ETH_P_IP)) return XDP_PASS;
struct iphdr *ip = (void *)(eth + 1);
if ((void *)(ip + 1) > data_end) return XDP_PASS;
if (ip->protocol != IPPROTO_TCP) return XDP_PASS;
struct tcphdr *tcp = (void *)ip + (ip->ihl * 4);
if ((void *)(tcp + 1) > data_end) return XDP_PASS;
unsigned char *payload = (unsigned char *)tcp + (tcp->doff * 4);
if ((void *)(payload + 14) > data_end) return XDP_PASS;
if (payload[0] == 'G' && payload[1] == 'E' && payload[2] == 'T' &&
payload[3] == ' ' && payload[4] == '/' && payload[5] == 'a' &&
payload[6] == 't' && payload[7] == 't' && payload[8] == 'a' &&
payload[9] == 'c' && payload[10] == 'k') {
return XDP_DROP;
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
Top comments (0)