I Hate This Country
  • Go 57.8%
  • Nim 21.9%
  • Nix 19.6%
  • Makefile 0.7%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
kreato cd149254a2
Some checks failed
Nix build / build (ubuntu-latest, x86_64-linux) (push) Failing after 1m10s
Nix build / build (macos-13, x86_64-darwin) (push) Has been cancelled
Nix build / build (macos-latest, aarch64-darwin) (push) Has been cancelled
Nix build / build (ubuntu-24.04-arm, aarch64-linux) (push) Has been cancelled
fix: support older Nim bootstrap compilers
2026-09-06 20:15:52 +03:00
.github/workflows fix: make TestBadGateway correct on all platforms 2026-06-01 21:50:17 +03:00
bpf fix: build TC object in Nix 2026-09-05 20:31:07 +03:00
cmd/ihtc feat: add Linux TC eBPF backend 2026-09-05 20:08:35 +03:00
docs/superpowers fix: correct module path to github.com/kreatoo/ihtc 2026-06-01 00:10:46 +03:00
internal feat: add Linux TC eBPF backend 2026-09-05 20:08:35 +03:00
modules fix: build TC object in Nix 2026-09-05 20:31:07 +03:00
.gitignore fix: build TC object in Nix 2026-09-05 20:31:07 +03:00
flake.lock fix: build TC ELF with nlvm in Nix 2026-09-05 20:46:10 +03:00
flake.nix fix: support older Nim bootstrap compilers 2026-09-06 20:15:52 +03:00
go.mod feat: add Linux TC eBPF backend 2026-09-05 20:08:35 +03:00
go.sum feat: add Linux TC eBPF backend 2026-09-05 20:08:35 +03:00
LICENSE docs: add README and MIT license 2026-06-01 01:22:27 +03:00
README.md feat: add Linux TC eBPF backend 2026-09-05 20:08:35 +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
  --backend string   Backend to use: proxy or tc (default "proxy")
  --tc-interface str Network interface for the Linux TC backend
  --tc-object string nlvm-generated TC eBPF object (default "bpf/tc_egress.o")

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

Linux TC eBPF backend

The optional tc backend is independent of the HTTP proxy. Build its TC program with the sibling nlvm checkout, then attach it to a network interface:

make -C bpf NLVM=../../nlvm/nlvm/nlvm
sudo ./ihtc --backend tc --tc-interface eth0 --tc-object bpf/tc_egress.o

It requires Linux 6.6+ (TCX), CAP_NET_ADMIN, and CAP_BPF. The program currently handles IPv4 TCP flows whose complete first ClientHello is in one packet; unsupported traffic is passed unchanged. Use --backend proxy for the userspace implementation.

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.