eBPF Kernel Module
Overview
This eBPF program hooks into the Linux kernel's network stack at the TC egress point and modifies outgoing packets before they leave your machine. It rewrites packet-level fingerprints that are visible to network observers and can be used to identify your OS and network stack implementation.

The eBPF module modifies packet-level fingerprints (TTL, TCP window size, sequence numbers, etc.). This requires a Linux kernel.
Kernel requirements
- CONFIG_BPF=y, CONFIG_BPF_SYSCALL=y, CONFIG_NET_CLS_BPF=y, CONFIG_NET_ACT_BPF=y
- Install:
clang,llvm,libbpf-dev,linux-headers-$(uname -r),iproute2
Configuration
Currently, IP/TCP packet header values are assigned via global variables at the top of
src/ebpf/ttl_editor.c. They do not align with values passed fromprofiles.json, this is a major pitfall of the current version and will be integrated with dynamicbpfmapsin a future release.
Modify hardcoded globals to desired values before compiling.
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 |
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)
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.
Build eBPF program
All commands can be copy pasted into your terminal for easy usage!
1.
cd src/ebpf
make deps-install # shows dependency installation command
make # compiles ttl_editor.o
# Manual compilation
clang -O2 -g -target bpf -D__TARGET_ARCH_x86 -I/usr/include/ -I/usr/include/linux -c TTLEDIT-STABLE.c -o <output>.o
Attach to network interface:
2.
sudo tc qdisc add dev <interface> clsact
sudo tc filter add dev <interface> egress bpf da obj ttl_editor.o sec classifier
Remove from interface
3.
Configure a Linux VM for forwarding
Kernel requirements:
- CONFIG_BPF=y, CONFIG_BPF_SYSCALL=y, CONFIG_NET_CLS_BPF=y, CONFIG_NET_ACT_BPF=y
-
Install:
clang,llvm,libbpf-dev,linux-headers-$(uname -r),iproute2 -
Linux kernel 4.15+ (5.4+ recommended)
1. Ensure your VM has two network adapters:
Bridged- connectsVM/Guestto internetHost-Only- creates private network betweenHostandVM/Guest
2. Attach to network interface:
sudo tc qdisc add dev <interface> clsact
sudo tc filter add dev <interface> egress bpf da obj ttl_editor.o sec classifier
On Linux VM (Guest):
# Enable IP forwarding
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
# Allow forwarding on Host-Only interface
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
# Enable NAT/masquerading on Bridged interface
sudo iptables -t nat -A POSTROUTING -o <bridged-interface> -j MASQUERADE
sudo ip6tables -t nat -A POSTROUTING -o <bridged-interface> -j MASQUERADE
On Host machine:
- Set default gateway to
VM/GuestHost-Only adapter IP address - (Windows: Network adapter settings → Properties → TCP/IPv4 → Gateway)
- (Linux/Mac:
sudo route add default gw <vm-host-only-ip>)
Some additional tinkering may be required. Feel free to leave a comment or open an issue with suggestions on improving the setup process.
Verify & Test
1. Verify it's running:
2. Verify w/ tcpdump output, some examples below:
tcpdump -i <interface> -vvv -Q out
# View specific TCP/IP fields:
tcpdump -i <interface> -vvv -c 20 -Q out 'tcp[tcpflags] & tcp-syn != 0' # SYN packets only (-c for 20 packets)
tcpdump -i <interface> -vvv -nn -Q out | grep -E 'ttl|win|mss|wscale' # Filter for specific fields
# More detailed packet inspection:
tcpdump -i <interface> -vvv -XX -Q out # Show full hex dump
tcpdump -i <interface> -vvv -Q out port 443 # HTTPS traffic only
Why eBPF?
Tools like p0f and nmap can passively fingerprint an OS by analyzing packet-level characteristics. This eBPF program attempts to normalize these values to make passive fingerprinting harder.
eBPF programs run in the kernel with strict safety guarantees enforced by the verifier. This program:
- Attaches to a network interface's TC egress hook
- Inspects every outgoing packet
- Modifies packet headers in-place (TTL, TCP options, etc.)
- Recalculates checksums where necessary
- Passes the modified packet onwards
- The verifier ensures the program can't crash the kernel, access arbitrary memory, or run forever. All bounds checks are verified at load time.
Operating systems have distinct network stack implementations. Windows, Linux, macOS, Android, and iOS set different default values for TCP/IP packet headers (TTL, MSS, WinSize/Scale). These fingerprinting vectors are trivial to collect and can identify your OS even if you spoof your HTTP headers and browser fingerprint perfectly. Tools like nmap and p0f allow third party network observers to exploit this fingerprinting vector.
Mismatches between network, JS, and HTTPS values can also be used by servers to identify bot-likely traffic and block connections.