Terminal-first DPI bypass core for Go. Runs headless as a stable local TCP forwarder between your client and an upstream endpoint.
Implements @patterniha's SNI-Spoofing technique. All credit for the original method goes to @patterniha.
Persian guide: README_fa.md
Your client → SNISPF (127.0.0.1:LISTEN_PORT) → Upstream endpoint (CONNECT_IP:CONNECT_PORT)
SNISPF intercepts the outbound TLS ClientHello and applies a bypass strategy before forwarding. Your client config stays unchanged — all bypass logic lives in SNISPF.
go build -o snispf.exe ./cmd/snispf.\snispf.exe --generate-config .\config.json
.\snispf.exe --config .\config.json --config-doctorFix any errors the doctor reports before continuing.
wrong_seqrequires a privileged terminal. On Windows, run as Administrator. On Linux, run as root or grantCAP_NET_RAWfirst. See Bypass strategies for details.
.\snispf.exe --config .\config.jsonAddress: 127.0.0.1
Port: 40443 (or your configured LISTEN_PORT)
Keep all other client protocol settings unchanged.
wrong_seq default config should be minimal and single-endpoint. Do not enable multi-endpoint load balancing fields for wrong_seq.
{
"LISTEN_HOST": "127.0.0.1",
"LISTEN_PORT": 40443,
"LOG_LEVEL": "info",
"CONNECT_IP": "203.0.113.10",
"CONNECT_PORT": 443,
"FAKE_SNI": "edge-a.example.com",
"BYPASS_METHOD": "wrong_seq",
"FRAGMENT_STRATEGY": "sni_split",
"FRAGMENT_DELAY": 0.05,
"USE_TTL_TRICK": false,
"FAKE_SNI_METHOD": "raw_inject",
"WRONG_SEQ_CONFIRM_TIMEOUT_MS": 2000,
"INTERFACE": ""
}| Field | Description |
|---|---|
LISTEN_HOST:LISTEN_PORT |
Local address your client connects to |
CONNECT_IP:CONNECT_PORT |
Upstream destination SNISPF dials |
FAKE_SNI |
SNI used by fake_sni and combined strategies |
BYPASS_METHOD |
Strategy: fragment, fake_sni, combined, or wrong_seq |
FRAGMENT_STRATEGY |
How to split the ClientHello (e.g. sni_split) |
FRAGMENT_DELAY |
Inter-fragment delay in seconds |
USE_TTL_TRICK |
Send fake ClientHello with low TTL before the real one |
FAKE_SNI_METHOD |
Fake SNI method: raw_inject, prefix_fake, etc. |
WRONG_SEQ_CONFIRM_TIMEOUT_MS |
Confirmation window for wrong_seq mode (default 2000) |
INTERFACE |
Network interface name to bind raw injection to (e.g. eth1, pppoe-wan). Empty for auto-detection. |
LOAD_BALANCE |
Endpoint selection: round_robin, random, failover |
ENDPOINT_PROBE |
Remove unreachable endpoints at startup |
AUTO_FAILOVER |
Retry on dial failure |
FAILOVER_RETRIES |
Number of failover attempts |
PROBE_TIMEOUT_MS |
Endpoint probe timeout in milliseconds |
LOG_LEVEL |
Verbosity: error, warn, info, debug |
Config precedence: If ENDPOINTS is defined, runtime dial values come from there. Top-level CONNECT_IP, CONNECT_PORT, and FAKE_SNI remain as backward-compatible defaults. A startup warning is logged when ENDPOINTS[0] overrides top-level values.
wrong_seq is the recommended default. It produces the most effective bypass when platform prerequisites are met. Fall back to simpler strategies only if they are not.
| Strategy | Privilege required | Recommended when |
|---|---|---|
wrong_seq |
Yes — see table below | Default choice when prerequisites are met |
combined |
No (degrades gracefully) | Raw injection unavailable but aggressive bypass needed |
fake_sni |
No (degrades gracefully) | Lighter alternative to combined |
fragment |
No | Diagnosis, constrained environments, or as a last resort |
| Platform | fragment, fake_sni, combined |
wrong_seq |
|---|---|---|
| Linux | Unprivileged | Privileged terminal — root or CAP_NET_RAW |
| Windows | Normal | Administrator terminal + WinDivert.dll + WinDivert64.sys in the same directory as the binary |
| OpenWrt | Normal | Privileged — CAP_NET_RAW or root + AF_PACKET support |
Windows: The Windows release bundle includes
WinDivert.dllandWinDivert64.sys. Place them in the same directory assnispf.exeand run from an Administrator terminal. Without both files,wrong_seqwill fail to initialize and--infowill report the reason.
Linux: Either run as root, or grant the capability once:
sudo setcap cap_net_raw+ep ./snispf
wrong_seq additional constraints:
- Exactly one enabled endpoint
- SNI length ≤ 219 bytes
- Generated fake ClientHello ≤ 1460 bytes (both validated by
--config-doctor)
If you need multi-endpoint balancing/failover, use combined, fake_sni, or fragment instead of wrong_seq.
- Universal WAN support (Linux / OpenWrt): SNISPF uses an L3 raw IP socket (
AF_INET SOCK_RAW IPPROTO_RAWwithIP_HDRINCL=1) for fake packet injection. This operates at the IP layer, letting the kernel handle routing, ARP/neighbor resolution, and link-layer encapsulation. It works out-of-the-box with all WAN technologies—including PPPoE, USB RNDIS (phone tethering), USB modems, VLANs, and Ethernet.- Startup logs will show
send_method=ip_rawwhen active, orsend_method=af_packet_fallbackas the original L2 fallback. - In complex routing environments (e.g. multi-WAN, mwan3), you can explicitly bind raw injection to a specific WAN interface using the
"INTERFACE"configuration field (e.g."eth1","pppoe-wan").
- Startup logs will show
- Dynamic IP & VPN Resiliency (Windows): On Windows, SNISPF periodically re-resolves the active source IP toward the remote endpoint and uses userspace filtering. This allows the raw injector to dynamically adapt to dynamic DHCP changes, interface switches, and VPN toggles without dropping existing connections.
- Troubleshooting Router/Firewall Drops: Routers or firewalls running strict connection tracking (conntrack) might classify the fake sequence packets as
INVALIDand drop them.- To prevent netfilter conntrack from dropping out-of-order window frames, enable the liberal mode:
sysctl -w net.netfilter.nf_conntrack_tcp_be_liberal=1
- Ensure that firewall
OUTPUTpolicies do not dropINVALIDTCP packets without considering local raw injector injections.
- To prevent netfilter conntrack from dropping out-of-order window frames, enable the liberal mode:
Run .\snispf.exe --info to inspect runtime capability flags. This flag is config-independent.
.\snispf.exe --config .\config.jsonOne-off flag overrides (do not persist to config):
.\snispf.exe --config .\config.json --listen 0.0.0.0:40443 --connect 188.114.98.0:443 --sni auth.vercel.com --method combinedExposes an HTTP control API for desktop apps, launchers, and automation.
.\snispf.exe --service --service-addr 127.0.0.1:8797
.\snispf.exe --service --service-addr 127.0.0.1:8797 --service-token your-tokenAPI base URL: http://127.0.0.1:8797
| Endpoint | Method | Description |
|---|---|---|
/v1/status |
GET | Worker state, PID, start time |
/v1/start |
POST | Validate config and start worker |
/v1/stop |
POST | Stop worker |
/v1/health |
GET | Endpoint TCP probe + wrong_seq counters |
/v1/validate |
GET | Config doctor results |
/v1/logs |
GET | Log tail (?limit=300&level=ALL) |
When a token is configured, send X-SNISPF-Token: <token> with every request.
Recommended troubleshooting order: /v1/status → /v1/validate → /v1/health → /v1/logs
Full request/response schema: docs/api-contract.md
Run multiple local listeners in one process:
{
"BYPASS_METHOD": "wrong_seq",
"LISTENERS": [
{
"NAME": "edge-a",
"LISTEN_HOST": "127.0.0.1",
"LISTEN_PORT": 40443,
"CONNECT_IP": "104.19.229.21",
"CONNECT_PORT": 443,
"FAKE_SNI": "hcaptcha.com"
},
{
"NAME": "edge-b",
"LISTEN_HOST": "127.0.0.1",
"LISTEN_PORT": 40444,
"CONNECT_IP": "104.19.229.22",
"CONNECT_PORT": 443,
"FAKE_SNI": "hcaptcha.com",
"BYPASS_METHOD": "fragment"
}
]
}Each listener runs independently. When LISTENERS is present, per-listener values override any top-level defaults.
Linux bundles include a systemd template and installer:
sudo bash ./install_linux_service.sh install --binary ./snispf_linux_amd64 --config ./config.json
sudo bash ./install_linux_service.sh status
sudo bash ./install_linux_service.sh restart
sudo bash ./install_linux_service.sh logs --lines 120The default unit sets Restart=always and LimitNOFILE=65535.
Core recovery behavior (all platforms):
- With multiple enabled
ENDPOINTSand load balancing configured, the core now chains fallback attempts across endpoints when dial or strategy confirmation fails. - If critical failures repeat in a short window (for example repeated
upstream_unreachableor confirmation failures), the core can trigger an internal runtime rebuild as a final recovery step.
Build and copy an architecture bundle to the router:
powershell -ExecutionPolicy Bypass -File .\scripts\build_openwrt_matrix.ps1
scp ./release/openwrt/snispf_openwrt_x86_64_bundle.tar.gz root@192.168.1.1:/tmp/Install on the router:
ssh root@192.168.1.1
cd /tmp && tar -xzf snispf_openwrt_x86_64_bundle.tar.gz && cd snispf_openwrt_bundle
ash ./openwrt_snispf.sh install --binary ./snispf --config ./config.jsonThe bundle includes the binary, openwrt_snispf.sh, and a generated default config.
Watchdog: Installed interactively by default (every 1 minute). Restarts on down process, missing listen port, or degraded raw-injector log patterns. Force-install or tune:
ash ./openwrt_snispf.sh watchdog-install
ash ./openwrt_snispf.sh install --binary ./snispf --config ./config.json --watchdog auto --post-restart-delay 20Watchdog/core recovery coordination:
- The deployment watchdog now detects core internal recovery signals and applies a short hold window before external restart escalation.
- This prevents overlapping restart loops when core is already performing internal runtime rebuild recovery.
Useful operations:
ash ./openwrt_snispf.sh status
ash ./openwrt_snispf.sh logs --follow
ash ./openwrt_snispf.sh monitor --watch 30 --interval 2
ash ./openwrt_snispf.sh doctorFor wrong_seq on OpenWrt:
setcap cap_net_raw+ep /path/to/snispfNote: If logs show
socket: too many open files, reinstall with the latestopenwrt_snispf.shto get the procdnofilelimit fix.
go build -o snispf.exe ./cmd/snispf| Target | Command |
|---|---|
| Windows amd64 | powershell -ExecutionPolicy Bypass -File .\scripts\build_windows_amd64.ps1 |
| Linux amd64 (PowerShell) | powershell -ExecutionPolicy Bypass -File .\scripts\build_linux_amd64.ps1 |
| Linux amd64 (bash) | bash ./scripts/build_linux_amd64.sh |
| Full release matrix | powershell -ExecutionPolicy Bypass -File .\scripts\build_release_matrix.ps1 |
| OpenWrt matrix (PowerShell) | powershell -ExecutionPolicy Bypass -File .\scripts\build_openwrt_matrix.ps1 |
| OpenWrt matrix (bash) | bash ./scripts/build_openwrt_matrix.sh |
Verification:
powershell -ExecutionPolicy Bypass -File .\scripts\verify_release.ps1
bash ./scripts/verify_release.sh- Core binaries:
release/snispf_windows_amd64.exe,release/snispf_linux_amd64,release/snispf_linux_arm64 - Bundles:
release/snispf_*_bundle.{zip,tar.gz} - OpenWrt:
release/openwrt/— per-arch binaries, per-arch bundles,openwrt_snispf.sh,openwrt_default_config.json - Metadata:
release/checksums.txt,release/release_manifest.json
OpenWrt matrix architectures: armv7, armv6, mipsle_softfloat, mips_softfloat, arm64, x86_64
Workflow: .github/workflows/release.yml
workflow_dispatch— draft/test builds- Push tag (e.g.
v1.2.3) — full release with checksums and manifest
--config <path> Load config file
--generate-config <path> Write default config to path
--config-doctor Validate config and exit
--info Show platform capability flags (no config required)
--listen <host:port> Override listen address
--connect <ip:port> Override upstream address
--sni <hostname> Override SNI
--method <strategy> Override bypass strategy
--service Start in service API mode
--service-addr <host:port>
--service-token <token>
--build-info / --version
Backward-compatible subcommand aliases: snispf run, snispf service, snispf doctor, snispf build-info
go test ./...
go vet ./...
go build -o snispf.exe ./cmd/snispf
powershell -ExecutionPolicy Bypass -File .\scripts\build_linux_amd64.ps1
powershell -ExecutionPolicy Bypass -File .\scripts\build_release_matrix.ps1
powershell -ExecutionPolicy Bypass -File .\scripts\verify_release.ps1
powershell -ExecutionPolicy Bypass -File .\scripts\integration_service_lifecycle.ps1- Run
--config-doctorand fix all reported errors. - Confirm your client is pointing to the local SNISPF listener address and port.
- Confirm upstream reachability via
/v1/healthor startup logs. - For
wrong_seq: verify platform privilege and single-endpoint constraint. - Check
/v1/logsfortimeout,failed, andnot_registeredoutcomes.
| Doc | Audience |
|---|---|
docs/beginner-guide.md |
First-time setup and troubleshooting |
docs/api-contract.md |
Service API schema and compatibility |
docs/internals.md |
Architecture, code paths, contributing |
docs/examples.md |
Annotated config profiles |
docs/roadmap.md |
Planned direction and non-goals |
This project is licensed under the GNU General Public License v3.0. See the LICENSE file for details.