Features • Quick Start • TCP Fingerprinting • Configuration • Research
- Zero netfilter - no packet rewriting framework. All hooks are kprobes + ftrace, native to the kernel's function call chain
- Native TCP emission - the kernel's own TCP stack builds correct packets. ftrace replaces
tcp_options_writefor fingerprinted sockets; original code runs untouched for everything else - Session-persistent - fingerprint applies to the entire TCP session, not just the SYN. Timestamps, window scaling, and options stay consistent throughout
- Wire-verified - all profiles verified at p0f distance 0 with active fingerprint verification (RTO patterns, ECN behavior, option stripping)
- Hot-loadable -
git clone && make && run. Kernel module auto-builds, loads, and unloads cleanly - Zero impact - only proxy connections are modified. All other system TCP traffic is untouched
- Splice zero-copy - high-performance data relay with multi-worker threading
- Multiple formats - p0f v3, JA4T, preset names, and mirror mode. Auto-detected
- IPv4/IPv6 dual stack with native hooks on both
ip_local_outandip6_local_out - Standard SOCKS5
CONNECTandUDP ASSOCIATEcommands
git clone --recursive https://github.com/Muno459/skyproxy
cd skyproxy
make./bin/skyproxy conf/main.ymlThe default auth has a user user with password pass(*). The fingerprint goes inside the parentheses:
# Preset
curl -x socks5h://user:pass(win11)@127.0.0.1:1080 http://example.com
curl -x socks5h://user:pass(macos)@127.0.0.1:1080 http://example.com
# Custom p0f signature (dots replace colons)
curl -x socks5h://user:pass(4.128.0.1460.65535,8.mss,nop,ws,nop,nop,sok.df,id+.0)@127.0.0.1:1080 http://example.com
# Custom JA4T signature
curl -x socks5h://user:pass(65535_2-1-3-1-1-4_1460_8)@127.0.0.1:1080 http://example.com
# Mirror the client's own TCP fingerprint
curl -x socks5h://user:pass(mirror)@127.0.0.1:1080 http://example.comOr configure per-user profiles in conf/auth.json:
{ "username": "user", "password": "pass", "preset": "win11" }curl -x socks5h://user:pass@127.0.0.1:1080 http://example.com- Linux kernel 5.10+ with headers (
apt install linux-headers-$(uname -r)) - GCC, make
- Root (for kernel module)
7 native hooks into the kernel's TCP/IP stack. Zero netfilter.
| Hook | Function | What it controls |
|---|---|---|
| ftrace | tcp_options_write |
TCP option order + TS clock scaling (all packets) |
| kprobe | tcp_connect |
ISN (Initial Sequence Number) |
| kretprobe | tcp_connect_init |
Initial RTO, window, wscale |
| kretprobe | tcp_syn_options |
SACK/TS/WS flags + header size |
| kprobe | tcp_retransmit_timer |
RTO pattern (linear/exponential) |
| kprobe | ip_local_out |
IPv4 IP ID, RST/FIN/ACK DF |
| kprobe | ip6_local_out |
IPv6 flow label, RST behavior |
For fingerprinted sockets, tcp_options_write is replaced via ftrace - our function writes options in the correct order from scratch. The original kernel function never executes. For non-fingerprinted sockets, the original runs untouched.
ECN flags (ECE+CWR) are set on the initial SYN and cleared on retransmits, matching real Darwin behavior. Option stripping (Darwin sends a stripped SYN after 10 retransmits) is handled in the same ftrace replacement.
The window scales normally after the SYN - the kernel's own tcp_select_window() manages it based on real buffer state. We only control the initial advertised window and wscale.
SkyProxy auto-detects the format from the input:
p0f v3: ver:ttl:olen:mss:wsize,scale:olayout:quirks:pclass
4:128:0:1460:65535,8:mss,nop,ws,nop,nop,sok:df,id+:0
JA4T: window_options_mss_wscale[_rto]
65535_2-1-3-1-1-4_1460_8_1-2-4-8
Presets: win11, win10, windows, winxp, macos, mac, ios, iphone, android, linux
curl -x socks5h://user:pass(win11)@server:1080 http://targetMirror: copies the connecting client's TCP fingerprint using TCP_SAVE_SYN (kernel 4.2+, originally developed at Google). Detects OS family from the SYN and applies matching active parameters (RTO, option stripping).
curl -x socks5h://user:pass(mirror)@server:1080 http://target| Client SYN | Detected OS | Active Preset |
|---|---|---|
| TTL 128, no timestamps | Windows | RTO: 1-2-4-8 |
| TTL 64, ECN enabled | Darwin | RTO: 1x5-2-4-8-16-32, strip #11, ECN first-SYN |
| TTL 64, no ECN | Linux/Android | RTO: 1x5-2-4-8-16-32 |
Append ~ after the signature for active fingerprinting:
4:128:0:1460:65535,8:mss,nop,ws,nop,nop,sok:df,id+:0~rto=1000-2000-4000-8000,ecn=1,strip=10
| Parameter | Values | Description |
|---|---|---|
rto= |
l (Linux), w (Windows), m (macOS), 1000-2000-4000 (custom ms) |
Retransmission timeout pattern |
isn= |
r (random), t (time-based), c (constant), i (incremental) |
Initial sequence number pattern |
ts= |
250, 1000, etc. |
Timestamp clock rate in Hz |
cc= |
cubic, reno, bbr |
Congestion control algorithm |
ecn= |
1 (enable), 0 (disable) |
ECN negotiation (ECE+CWR on initial SYN only) |
strip= |
10 (strip after N retransmits) |
Option stripping on final SYN retransmit |
All profiles verified at p0f distance 0 with active fingerprint verification:
| Profile | p0f Detection | Active Verification |
|---|---|---|
| Windows 10/11 | Windows NT kernel 5.x |
RTO 1-2-4-8, IP ID non-zero with DF |
| macOS / iOS | Mac OS X |
RTO 1x5-2-4-8-16-32, ECN first-SYN-only, option strip #11 |
| Linux 3.11+ | Linux 3.11 and newer |
RTO 1x5-2-4-8-16-32 |
| Windows XP | Windows XP |
No timestamps, no wscale |
| iOS (active) | Same passive as macOS | 60ms RTO within 2ms precision, strip #11 |
For detailed fingerprint research from real devices (Windows 11, macOS Tahoe, iOS 26, Android 16, Pixel 9 XL), see docs/tcp-fingerprint-research.md.
main:
workers: 4
port: 1080
listen-address: '::'
listen-ipv6-only: false
domain-address-type: unspec
auth:
file: conf/auth.json
misc:
connect-timeout: 30000[
{ "username": "user", "password": "pass(*)" },
{ "username": "tom", "password": "pass" },
{ "username": "win10", "password": "pass",
"p0f": "4:128:0:1460:65535,8:mss,nop,ws,nop,nop,sok:df,id+:0~rto=1000-2000-4000-8000" },
{ "username": "fast", "password": "pass",
"ja4t": "65535_2-1-3-1-1-4_1460_8_1-2-4-8" },
{ "username": "stealth", "password": "pass", "preset": "macos" },
{ "username": "transparent", "password": "pass", "preset": "mirror" }
]Each user can have a fingerprint via three field names:
p0f- custom p0f v3 signatureja4t- custom JA4T signaturepreset- built-in preset name ormirror
All three auto-detect the format. password: "pass(*)" enables dynamic fingerprinting where the client sends the fingerprint inside the parentheses at connect time.
Reload auth without restarting:
killall -SIGUSR1 skyproxymake # binary + kernel module + load
make exec # binary only
make dkms # kernel module only
make ENABLE_STATIC=1 # static binary
make kmod-load # load kernel module
make kmod-unload # unload kernel moduleSee docs/tcp-fingerprint-research.md for original TCP/IP fingerprint research including:
- Passive + active fingerprint data from 6 real devices
- 2-packet OS identification flowchart (1 SYN = OS family, 1 retransmit = exact OS)
- iOS 60ms retransmit discovery
- Darwin ECN + option stripping behavior
- iCloud Private Relay fingerprint analysis
Built on hev-socks5-server by hev.
SkyProxy Non-Commercial License. See LICENSE.
Non-commercial use only. Attribution to Muno459 required. Kernel module additionally licensed under GPL-2.0.
Source outgoing connections from any address in your IPv6 range. Uses SO_FREEBIND to bind on the fly. No addresses added to the interface.
ip-pool:
ipv6-prefix: '2a0a:8dc0:1139::'
ipv6-prefix-len: 48
mode: rotate
sticky-ttl: 600| Mode | Behavior |
|---|---|
rotate |
New random IPv6 on every connection |
sticky |
Same IPv6 per session ID (deterministic hash, no state) |
sticky + TTL |
Same IPv6 for the duration, then rotates (hash + time bucket, no state) |
Everything is optional. Use what you need:
# Plain proxy (no fingerprint, no rotation)
curl -x socks5h://user:pass@server:1080 http://target
# Fingerprint only
curl -x socks5h://user:pass(win11)@server:1080 http://target
# Rotation only
curl -x socks5h://user:pass(!rotate)@server:1080 http://target
# Fingerprint + rotation
curl -x socks5h://user:pass(win11!rotate)@server:1080 http://target
# Sticky per session ID
curl -x socks5h://user:pass(win11!sticky=checkout_flow)@server:1080 http://target
# Sticky with TTL (human-readable durations)
curl -x socks5h://user:pass(macos!sticky=session1:10m)@server:1080 http://target
curl -x socks5h://user:pass(win11!sticky=sess:1h)@server:1080 http://target
curl -x socks5h://user:pass(ios!sticky=browse:300)@server:1080 http://targetDuration formats: 300 (seconds), 5m (minutes), 1h or 1hr (hours), 1d (days).
Same session ID always maps to the same IPv6 regardless of username. Different session IDs get different IPs. Adding or changing IP pools doesn't affect existing session-to-IP mappings.