From d365a09d86908c8a24341e75bbb4b64e5abb1f65 Mon Sep 17 00:00:00 2001 From: David Fifield Date: Sun, 2 Jan 2022 16:23:05 -0700 Subject: [PATCH] Permit "-utls none" to disable uTLS. --- CHANGELOG | 9 +++++---- README | 4 +++- dnstt-client/main.go | 47 +++++++++++++++++++++++++++++++++++--------- 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 31bae40..eb8c925 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,10 +1,11 @@ -doh and -dot mode use uTLS to camouflage their TLS Client Hello fingerprint. The fingerprint to use is chosen randomly from a weighted distribution. You can control this distribution using the new -utls -option. This change means that it is no longer possible to use a proxy -in -doh mode by setting the HTTP_PROXY or HTTPS_PROXY environment -variables; this was an undocumented side effect of using the Go net/http -package with no TLS camouflage. +option. Use "-utls none" to disable uTLS if you encounter TLS errors +with your chosen server. This change means that it is no longer possible +to use a proxy in -doh mode by setting the HTTP_PROXY or HTTPS_PROXY +environment variables; this was an undocumented side effect of using the +Go net/http package with no TLS camouflage. ## v1.20210812.0 diff --git a/README b/README index 3706cae..04c3296 100644 --- a/README +++ b/README @@ -295,7 +295,9 @@ $ ./dnstt-client -utls '3*Firefox,2*Chrome,1*iOS' ... $ ./dnstt-client -utls Firefox ... ``` Run `./dnstt-client -help` to see the available fingerprint names and -the default distribution. +the default distribution. The special value `none` disables uTLS and +uses the native crypto/tls fingerprint, which is less covert but likely +to be compatible with more servers. ## Encryption and authentication diff --git a/dnstt-client/main.go b/dnstt-client/main.go index 3a36023..8eff2b9 100644 --- a/dnstt-client/main.go +++ b/dnstt-client/main.go @@ -25,21 +25,24 @@ // them over the tunnel. // // In -doh and -dot modes, the program's TLS fingerprint is camouflaged with -// uTLS. By default, the specific TLS fingerprint is selected randomly from a +// uTLS by default. The specific TLS fingerprint is selected randomly from a // weighted distribution. You can set your own distribution (or specific single -// fingerprint) using the -utls option: +// fingerprint) using the -utls option. The special value "none" disables uTLS. // -utls '3*Firefox,2*Chrome,1*iOS' // -utls Firefox +// -utls none package main import ( "context" + "crypto/tls" "errors" "flag" "fmt" "io" "log" "net" + "net/http" "os" "strings" "sync" @@ -97,9 +100,14 @@ func sampleUTLSDistribution(spec string) (*utls.ClientHelloID, error) { } ids := make([]*utls.ClientHelloID, 0, len(labels)) for _, label := range labels { - id := utlsLookup(label) - if id == nil { - return nil, fmt.Errorf("unknown TLS fingerprint %q", label) + var id *utls.ClientHelloID + if label == "none" { + id = nil + } else { + id = utlsLookup(label) + if id == nil { + return nil, fmt.Errorf("unknown TLS fingerprint %q", label) + } } ids = append(ids, id) } @@ -243,6 +251,7 @@ Examples: `, os.Args[0]) flag.PrintDefaults() labels := make([]string, 0, len(utlsClientHelloIDMap)) + labels = append(labels, "none") for _, entry := range utlsClientHelloIDMap { labels = append(labels, entry.Label) } @@ -319,7 +328,9 @@ Known TLS fingerprints for -utls are: fmt.Fprintf(os.Stderr, "parsing -utls: %v\n", err) os.Exit(1) } - log.Printf("uTLS fingerprint %s %s", utlsClientHelloID.Client, utlsClientHelloID.Version) + if utlsClientHelloID != nil { + log.Printf("uTLS fingerprint %s %s", utlsClientHelloID.Client, utlsClientHelloID.Version) + } // Iterate over the remote resolver address options and select one and // only one. @@ -332,14 +343,32 @@ Known TLS fingerprints for -utls are: // -doh {dohURL, func(s string) (net.Addr, net.PacketConn, error) { addr := turbotunnel.DummyAddr{} - pconn, err := NewHTTPPacketConn(NewUTLSRoundTripper(nil, utlsClientHelloID), dohURL, 32) + var rt http.RoundTripper + if utlsClientHelloID == nil { + transport := http.DefaultTransport.(*http.Transport).Clone() + // Disable DefaultTransport's default Proxy = + // ProxyFromEnvironment setting, for conformity + // with utlsRoundTripper and with DoT mode, + // which do not take a proxy from the + // environment. + transport.Proxy = nil + rt = transport + } else { + rt = NewUTLSRoundTripper(nil, utlsClientHelloID) + } + pconn, err := NewHTTPPacketConn(rt, dohURL, 32) return addr, pconn, err }}, // -dot {dotAddr, func(s string) (net.Addr, net.PacketConn, error) { addr := turbotunnel.DummyAddr{} - dialTLSContext := func(ctx context.Context, network, addr string) (net.Conn, error) { - return utlsDialContext(ctx, network, addr, nil, utlsClientHelloID) + var dialTLSContext func(ctx context.Context, network, addr string) (net.Conn, error) + if utlsClientHelloID == nil { + dialTLSContext = (&tls.Dialer{}).DialContext + } else { + dialTLSContext = func(ctx context.Context, network, addr string) (net.Conn, error) { + return utlsDialContext(ctx, network, addr, nil, utlsClientHelloID) + } } pconn, err := NewTLSPacketConn(dotAddr, dialTLSContext) return addr, pconn, err