Skip to content

eBPF

Role

The eBPF module runs on Linux and rewrites packet-level values before they leave your machine. It works alongside STATIC to normalize the network-layer fingerprint that tools like p0f and nmap use for OS detection.


Overview

The eBPF module attaches to Linux Traffic Control (tc) egress hooks and rewrites packet-level values that can be used for passive OS and stack fingerprinting via tools like p0f or nmap.

tcpdump output


Implementation

The eBPF layer complements STATIC.

Why both?

Mismatches between network fingerprints and higher-level browser identity can still expose the host as synthetic or misaligned traffic.

  • STATIC handles TLS, HTTP, JavaScript injection, and control-plane behavior.
  • The eBPF layer handles lower-level packet mutation on Linux inside the Rose-based distribution path.

On Windows, the managed desktop product path reaches this Linux layer by booting the 404 distribution through WSL2.

On CLI-managed Linux paths, you can build and attach it directly yourself.


Kernel and toolchain requirements

You need a Linux environment with:

  • Linux kernel 4.15+ (5.4+ recommended)
  • clang
  • llvm
  • llvm-strip
  • tc
  • iproute2
  • libbpf-dev
  • linux-headers-$(uname -r)
  • /usr/include/bpf/bpf_helpers.h
  • /usr/include/linux/bpf.h

Configuration

Packet behavior now has a live profile-driven path on Linux.

The current Linux packet-profile model is:

  • the Linux boot path pins the fingerprint_profiles BPF map
  • STATIC derives a packet profile from the selected profile JSON
  • the active packet profile is written into the pinned map
  • the eBPF classifier reads from that map and falls back to built-in defaults only when no userspace value is present

You can still inspect and modify the kernel-side code directly if you are developing the packet layer, but normal packet behavior is no longer limited to compile-time globals.

Native OS Options:

OS TTL Window Size Window Scale ISN MSS* Timestamps TCP Option Order
Windows 128 64 kb (64240 bytes) 8 Randomized Varies based on connection Not used MSS,NOP,WS,NOP,NOP,SACK
MacOS 64 64 kb (65535 bytes) 6 Randomized Varies based on connection Internal counter MSS,NOP,WS,NOP,NOP,TS,SACK,EOL
Linux 64 64 kb (65535 bytes - 5840 bytes for 2.4/2.6 kernels) 7 Randomized Varies based on connection Internal counter - sometimes randomized MSS,SACK,TS,NOP,WS

1. Open ttl_editor.c and modify the #define values at the top: (optional)

#define FORCE_TTL 255
#define SPOOF_TCP_WINDOW_SIZE 65535
#define SPOOF_TCP_MSS 1460
#define SPOOF_TCP_WINDOW_SCALE 5
// etc.

Current Linux packet-profile model

The selected profile can now drive the active packet profile on Linux through the pinned BPF map path.

Default Implementation Options

IPv4:

  • TTL (Time To Live) → forced to 255
  • TOS (Type of Service) → set to 0x10
  • IP ID (Identification) → randomized per packet
  • TCP window size → 65535
  • TCP initial sequence number → randomized (again)
  • TCP window scale → 5
  • TCP MSS (Maximum Segment Size) → 1460
  • TCP timestamps → randomized

IPv6:

  • Hop limit → forced to 255
  • Flow label → randomized
  • TCP parameters (same as IPv4)

Build path

The Makefile in src/ebpf builds:

  • ttl_editor.o

Typical local invocation:

make -C src/ebpf clean all

You can also build it from inside the directory directly:

cd src/ebpf
make deps-install
make

This is the same object that is packaged into the Rose-based distribution build path.


Attach path

Attach:

sudo tc qdisc add dev <interface> clsact
sudo tc filter add dev <interface> egress bpf da obj ttl_editor.o sec classifier

Remove:

sudo tc filter del dev <interface> egress
sudo tc qdisc del dev <interface> clsact

Verify and inspect

Verify attachment:

sudo tc filter show dev <interface> egress

Inspect outgoing traffic:

tcpdump -i <interface> -vvv -Q out
tcpdump -i <interface> -vvv -c 20 -Q out 'tcp[tcpflags] & tcp-syn != 0'
tcpdump -i <interface> -vvv -nn -Q out | grep -E 'ttl|win|mss|wscale'
tcpdump -i <interface> -vvv -XX -Q out
tcpdump -i <interface> -vvv -Q out port 443

VM forwarding

If you want to expose a host machine through a Linux VM that is running the packet layer, use a bridged adapter for internet access and a host-only adapter between the host and guest.

On the Linux guest, enable IPv4 and IPv6 forwarding and apply the normal forwarding and NAT rules for the host-only and bridged interfaces.

sudo sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -w net.ipv6.conf.all.forwarding=1
echo "net.ipv6.conf.all.forwarding=1" | sudo tee -a /etc/sysctl.conf

sudo iptables -A FORWARD -i <host-only-interface> -j ACCEPT
sudo iptables -A FORWARD -o <host-only-interface> -j ACCEPT
sudo ip6tables -A FORWARD -i <host-only-interface> -j ACCEPT
sudo ip6tables -A FORWARD -o <host-only-interface> -j ACCEPT

sudo iptables -t nat -A POSTROUTING -o <bridged-interface> -j MASQUERADE
sudo ip6tables -t nat -A POSTROUTING -o <bridged-interface> -j MASQUERADE

On the host, point the default route at the guest's host-only adapter IP.