I've been rebuilding some internal egress controls and the overhead of our Squid proxies is becoming a real pain. Everyone defaults to a layer 7 proxy (Squid, Caddy, Envoy) for HTTP(S) filtering, but I'm wondering why more people aren't looking at eBPF for this.
The proxy model means all traffic gets funneled through a userspace process, parsed, then re-forwarded. Even with keep-alive, it's a bottleneck and a huge attack surface. If the goal is to enforce policy—block certain domains, reject non-conformant TLS, detect tunneling—do we need a full protocol parse in userspace?
eBPF programs attached to `socket` or `sk_skb` hooks can inspect and filter layer 7 data in the kernel. You could:
* Match on cleartext HTTP Host headers
* Enforce TLS SNI against an allowlist
* Detect patterns of DNS tunneling in TCP/UDP payloads
* Drop or redirect packets before they hit a proxy
The main advantage is doing it *before* the expensive round-trip to userspace. For memory safety, you write the filter logic in restricted C, compile to BPF, and load it. The kernel verifies it. No `unsafe` Rust even needed on the loader side.
But the limitations are real:
* HTTPS inspection requires a MITM proxy, full stop. eBPF can't decrypt. You could only filter on SNI or raw TCP patterns.
* Complex HTTP policy (like inspecting API paths in a POST) gets messy fast in BPF. It's possible, but you're writing low-level packet reassembly logic.
* Maintenance. A Squid config is one thing; a BPF program that needs to track kernel API changes is another.
I'm prototyping a Rust-based loader that attaches a BPF program to do SNI-based allow/deny. The core filter looks like this (simplified):
```c
// BPF program snippet for TLS Client Hello SNI matching
struct tls_hdr {
uint8_t type;
uint16_t version;
uint16_t length;
} __attribute__((packed));
SEC("socket")
int filter_sni(struct __sk_buff *skb) {
// Parse IP, TCP, then TLS handshake header
// Locate SNI extension, compare against pinned map of allowed domains
// Return SK_DROP if violation
}
```
The Rust part uses `aya-rs` to load and manage the BPF program and the map of allowed domains.
So the question: is this a viable path for high-throughput, low-latency egress control where you don't need deep HTTPS inspection? Or is the complexity not worth it compared to a tuned Envoy deployment? Specifically for agent traffic, where every millisecond and extra memory copy counts, I'm leaning toward eBPF.
Fearless concurrency. Paranoid safety.