Add a new "utls" dialer type that uses the refraction-networking/utls library to mimic browser TLS fingerprints (Chrome, Firefox, Safari, etc.). - x/dialer/utls/dialer.go: Registered as "utls", mirrors the TLS dialer with Handshake() using utls.UClient() for fingerprint emulation. - x/dialer/utls/fingerprint.go: Maps string names (chrome, firefox, ios, safari, edge, randomized, golang, custom) to utls.ClientHelloID presets. - x/dialer/utls/metadata.go: Parses fingerprint from dialer metadata. - go.mod: Add github.com/refraction-networking/utls v1.8.2. The fingerprint is dialer-only metadata — the standard TLS dialer is untouched. Falls back to crypto/tls if no fingerprint is configured. Closes go-gost/gost#31
3.2 KiB
Plan: Add uTLS Fingerprint Dialer (utls)
Context
Issue: go-gost/gost#31 — Feature request to add TLS ClientHello fingerprint simulation using the uTLS library. GOST currently uses Go's crypto/tls which produces a distinctive Go TLS fingerprint that's easily blocked. Users want to mimic Chrome/Firefox/Safari/etc. fingerprints.
Approach: New "utls" dialer type (standalone, not modifying the existing "tls" dialer). The fingerprint is dialer-only metadata — not on the shared TLSConfig struct. This keeps the standard TLS dialer untouched and avoids pulling in the uTLS dependency for all users.
Files to Create
1. x/dialer/utls/fingerprint.go — String→ClientHelloID map
Maps user-facing fingerprint names to utls.ClientHelloID presets. Supported names: chrome, firefox, ios, safari, edge, randomized, randomized-alpn, randomized-noalpn, golang, custom. Empty string and "golang" both mean "fall through to standard crypto/tls" (return ok=false). Unknown names get a warning log and also fall through.
2. x/dialer/utls/metadata.go — Metadata parsing
Mirrors dialer/tls/metadata.go exactly, adding a fingerprint string field. Parsed keys:
handshakeTimeout(duration)keepalive,keepalive.idle,keepalive.interval,keepalive.count(TCP keepalive)fingerprint(string) — new
3. x/dialer/utls/dialer.go — Core dialer
Mirrors dialer/tls/dialer.go. Registered as "utls". The Dial() method is identical to the TLS dialer. The Handshake() method diverges: looks up the fingerprint; if ok, uses utls.UClient(conn, tlsConfig, clientHelloID); otherwise falls through to crypto/tls.Client().
Files to Modify
4. x/go.mod — Add uTLS dependency
Add github.com/refraction-networking/utls v1.8.2 to the require block, then run go mod tidy from x/.
5. gost/cmd/gost/register.go — Blank import
Add _ "github.com/go-gost/x/dialer/utls" in the "Register dialers" section, alphabetically between the unix and ws imports.
No Changes Needed
- Config parsing —
node/parse.goalready passesdialCfg.Metadatatod.Init(); no changes required to any parsing code. config/config.go—DialerConfig.Metadataalready supports arbitrary keys;fingerprintflows through naturally.- Metadata key constants — No new constant in
config/parsing/parse.go; localconstinparseMetadata()follows existing dialer convention.
Usage Example
services:
- name: service-0
addr: :8080
handler:
type: tcp
listener:
type: tcp
forwarder:
nodes:
- name: target-0
addr: example.com:443
dialer:
type: utls
metadata:
fingerprint: chrome
Verification
# 1. Tidy dependencies
cd x && go mod tidy
# 2. Build + vet the x module
cd x && go build ./... && go vet ./...
# 3. Build + vet the gost binary (verifies blank import)
cd gost && go build ./cmd/gost/... && go vet ./...
No unit tests needed — the existing codebase has no tests in x/dialer/.