I Hate This Country
  • Go 84.2%
  • Nix 15.8%
Find a file
Kreato 94c0ae955a
refactor: change --refrag from dummy records to min-chunk-count approach
Replace the dummy TLS record injection mechanism with a minimum chunk count
approach. Instead of prepending fake TLS records before the ClientHello, the
new approach ensures the ClientHello itself is split into at least --refrag
chunks, which is more effective and idiomatic.

- Default --refrag changed from 1 to 0 (disabled)
- Removed buildDummyRecords() and the associated dummy record injection
- Added splitRange() helper function
- Split() now enforces a minimum chunk count via re-splitting when needed
2026-06-01 02:00:45 +03:00
cmd/ihtc refactor: change --refrag from dummy records to min-chunk-count approach 2026-06-01 02:00:45 +03:00
docs/superpowers
internal refactor: change --refrag from dummy records to min-chunk-count approach 2026-06-01 02:00:45 +03:00
modules feat: add darwin/nixos module options 2026-06-01 01:59:00 +03:00
.gitignore fix: --regex non-matching hosts passthrough instead of reject 2026-06-01 01:30:35 +03:00
flake.lock feat: add nix flake package 2026-06-01 01:24:52 +03:00
flake.nix feat: add darwin/nixos module options 2026-06-01 01:59:00 +03:00
go.mod fix: use valid go version format (1.24) 2026-06-01 00:14:00 +03:00
LICENSE docs: add README and MIT license 2026-06-01 01:22:27 +03:00
README.md feat: add --refrag for dummy TLS record injection 2026-06-01 01:36:22 +03:00

ihtc

Local HTTP forward proxy for bypassing SNI-based DPI censorship. Splits the TLS ClientHello across multiple TCP packets to evade deep packet inspection.

Quick Start

go build -o ihtc ./cmd/ihtc/
./ihtc --auto-proxy

This binds 127.0.0.1:8080, serves a PAC file, and configures macOS auto proxy for all network services. Browsers route traffic through ihtc automatically.

On Ctrl+C, the proxy is disabled and browsers fall back to direct connections.

Usage

ihtc [flags]

  --listen string    Address to bind (default "127.0.0.1:8080")
  --min-chunk int    Minimum bytes per fragment (default 3)
  --max-chunk int    Maximum bytes per fragment (default 8)
  --delay-us int     Max microsecond delay between fragments (default 500)
  --refrag int       Dummy TLS records before ClientHello (default 1, disabled)
  --regex string     Only fragment hosts matching this regex
  --verbose          Enable debug logging
  --auto-proxy       Set macOS auto proxy configuration

Without --auto-proxy, point your browser/app at 127.0.0.1:8080 as an HTTP proxy manually.

How It Works

When a browser opens an HTTPS connection through the proxy:

  1. The browser sends a TLS ClientHello containing the target hostname (SNI)
  2. ihtc reads the complete ClientHello, then writes it in small random chunks (2-8 bytes by default) with microsecond delays between each
  3. TCP sends each chunk as its own segment — simple DPIs see only fragments, not the hostname
  4. After the handshake, ihtc relays data transparently in both directions

Limitations

  • TCP only (no QUIC/HTTP3)
  • Not effective against DPIs that perform TCP stream reassembly
  • No authentication (local-only, trusted environment)

Advanced

Fragmenting only blocked domains

Use --regex to limit fragmentation to specific hosts. All other traffic passes through unfragmented:

./ihtc --auto-proxy --regex 'discord\.com|discord\.gg|twitter\.com'

Re-fragmentation

For DPIs that reassemble TCP streams, enable re-fragmentation with --refrag N:

./ihtc --refrag 3

This inserts N-1 deliberately invalid TLS records before the real ClientHello, each in its own TCP segment. A reassembling DPI must inspect multiple nearly-identical records and choose the correct one — while the TLS server ignores the invalid records and processes only the final valid one.

Set N based on DPI aggressiveness (2-5 is typical). Higher values add latency with diminishing returns.

License

MIT — see LICENSE.