From e47b8a8233cd366e00826d685e490181c8955a88 Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Sun, 7 Apr 2019 13:18:35 +0800 Subject: [PATCH 1/4] hello-mss fragmentation and DNS over TLS --- cmd/tlsrouter/main.go | 65 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/cmd/tlsrouter/main.go b/cmd/tlsrouter/main.go index ff1a816..5c62f5d 100644 --- a/cmd/tlsrouter/main.go +++ b/cmd/tlsrouter/main.go @@ -16,21 +16,36 @@ package main import ( "bytes" + "context" + "crypto/tls" "flag" "fmt" "io" "log" "net" + "strings" "sync" "time" ) var ( - cfgFile = flag.String("conf", "", "configuration file") - listen = flag.String("listen", ":443", "listening port") - helloTimeout = flag.Duration("hello-timeout", 3*time.Second, "how long to wait for the TLS ClientHello") + cfgFile = flag.String("conf", "", "configuration file") + listen = flag.String("listen", ":443", "listening port") + helloTimeout = flag.Duration("hello-timeout", 3*time.Second, "how long to wait for the TLS ClientHello") + helloMss = flag.Int64("hello-mss", 16, "how many bytes to fragment/segment the TLS ClientHello") + resolverAddress = flag.String("dns", "dns.google", "address of the dns resolver") + resolverNetwork = flag.String("dns-net", "", "protocol for the dns resolver (e.g. \"tcp-tls\" or \"tcp\" or \"udp\")") ) +// CustomDialer with timeout +var CustomDialer = &net.Dialer{ + Timeout: 15 * time.Second, + Resolver: &net.Resolver{ + PreferGo: true, + Dial: dialDNSResolver, + }, +} + func main() { flag.Parse() @@ -142,7 +157,7 @@ func (c *Conn) proxy() { } c.logf("routing %q to %q", c.hostname, c.backend) - backend, err := net.DialTimeout("tcp", c.backend, 10*time.Second) + backend, err := CustomDialer.Dial("tcp", c.backend) if err != nil { c.internalError("failed to dial backend %q for %q: %s", c.backend, c.hostname, err) return @@ -168,7 +183,20 @@ func (c *Conn) proxy() { // Replay the piece of the handshake we had to read to do the // routing, then blindly proxy any other bytes. - if _, err = io.Copy(c.backendConn, &handshakeBuf); err != nil { + if *helloMss == 0 { + _, err = io.Copy(c.backendConn, &handshakeBuf) + } else { + for { + _, err = io.CopyN(c.backendConn, &handshakeBuf, *helloMss) + if err != nil { + if err == io.EOF { + err = nil + } + break + } + } + } + if err != nil { c.internalError("failed to replay handshake to %q: %s", c.backend, err) return } @@ -189,3 +217,30 @@ func proxy(wg *sync.WaitGroup, a, b net.Conn) { btcp.CloseWrite() atcp.CloseRead() } + +func dialDNSResolver(ctx context.Context, network, address string) (net.Conn, error) { + if *resolverNetwork != "" { + network = *resolverNetwork + } + if *resolverAddress != "" { + address = *resolverAddress + } + + d := net.Dialer{ + Timeout: 10 * time.Second, + } + + useTLS := strings.HasPrefix(network, "tcp") && strings.HasSuffix(network, "-tls") + if useTLS { + network = strings.TrimSuffix(network, "-tls") + if !strings.Contains(address, ":") { + address += ":853" + } + return tls.DialWithDialer(&d, network, address, nil) + } + + if !strings.Contains(address, ":") { + address += ":53" + } + return d.DialContext(ctx, network, address) +} From 78cd0b5db282a6c098e9e329e4c2c896a94ec707 Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Sun, 7 Apr 2019 13:20:21 +0800 Subject: [PATCH 2/4] expand capture groups on regex match --- cmd/tlsrouter/config.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmd/tlsrouter/config.go b/cmd/tlsrouter/config.go index 1c8151f..acc8ac3 100644 --- a/cmd/tlsrouter/config.go +++ b/cmd/tlsrouter/config.go @@ -69,8 +69,10 @@ func (c *Config) Match(hostname string) (string, bool) { } for _, r := range c.routes { - if r.match.MatchString(hostname) { - return r.backend, r.proxyInfo + matches := r.match.FindStringSubmatchIndex(hostname) + if matches != nil { + result := r.match.ExpandString(nil, r.backend, hostname, matches) + return string(result), r.proxyInfo } } return "", false From 29adb7012949e40566b5bb7a1926cecf68359384 Mon Sep 17 00:00:00 2001 From: heri16 <527101+heri16@users.noreply.github.com> Date: Sun, 7 Apr 2019 22:09:23 +0800 Subject: [PATCH 3/4] Saner tls.Config for DNS-over-TLS --- cmd/tlsrouter/main.go | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/cmd/tlsrouter/main.go b/cmd/tlsrouter/main.go index 5c62f5d..e6c3fb6 100644 --- a/cmd/tlsrouter/main.go +++ b/cmd/tlsrouter/main.go @@ -37,8 +37,8 @@ var ( resolverNetwork = flag.String("dns-net", "", "protocol for the dns resolver (e.g. \"tcp-tls\" or \"tcp\" or \"udp\")") ) -// CustomDialer with timeout -var CustomDialer = &net.Dialer{ +// BackendDialer with timeout +var BackendDialer = &net.Dialer{ Timeout: 15 * time.Second, Resolver: &net.Resolver{ PreferGo: true, @@ -46,6 +46,25 @@ var CustomDialer = &net.Dialer{ }, } +// ResolverDialer with timeout +var ResolverDialer = &net.Dialer{ + Timeout: 10 * time.Second, +} + +// ResolverTLSConfig for DNS-over-TLS +var ResolverTLSConfig = &tls.Config{ + MinVersion: tls.VersionTLS12, + CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP521, tls.CurveP384, tls.CurveP256}, + CipherSuites: []uint16{ + // tls.TLS_CHACHA20_POLY1305_SHA256, + // tls.TLS_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + }, +} + func main() { flag.Parse() @@ -157,7 +176,7 @@ func (c *Conn) proxy() { } c.logf("routing %q to %q", c.hostname, c.backend) - backend, err := CustomDialer.Dial("tcp", c.backend) + backend, err := BackendDialer.Dial("tcp", c.backend) if err != nil { c.internalError("failed to dial backend %q for %q: %s", c.backend, c.hostname, err) return @@ -226,21 +245,17 @@ func dialDNSResolver(ctx context.Context, network, address string) (net.Conn, er address = *resolverAddress } - d := net.Dialer{ - Timeout: 10 * time.Second, - } - useTLS := strings.HasPrefix(network, "tcp") && strings.HasSuffix(network, "-tls") if useTLS { network = strings.TrimSuffix(network, "-tls") if !strings.Contains(address, ":") { address += ":853" } - return tls.DialWithDialer(&d, network, address, nil) + return tls.DialWithDialer(ResolverDialer, network, address, ResolverTLSConfig) } if !strings.Contains(address, ":") { address += ":53" } - return d.DialContext(ctx, network, address) + return ResolverDialer.DialContext(ctx, network, address) } From c1bf0699cad0a9006be682fab7fa2fa1af0d35b3 Mon Sep 17 00:00:00 2001 From: Heri Sim <527101+heri16@users.noreply.github.com> Date: Thu, 21 May 2020 13:47:50 +0000 Subject: [PATCH 4/4] Default values disables optional features --- cmd/tlsrouter/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/tlsrouter/main.go b/cmd/tlsrouter/main.go index e6c3fb6..5b85542 100644 --- a/cmd/tlsrouter/main.go +++ b/cmd/tlsrouter/main.go @@ -32,8 +32,8 @@ var ( cfgFile = flag.String("conf", "", "configuration file") listen = flag.String("listen", ":443", "listening port") helloTimeout = flag.Duration("hello-timeout", 3*time.Second, "how long to wait for the TLS ClientHello") - helloMss = flag.Int64("hello-mss", 16, "how many bytes to fragment/segment the TLS ClientHello") - resolverAddress = flag.String("dns", "dns.google", "address of the dns resolver") + helloMss = flag.Int64("hello-mss", 0, "how many bytes to fragment/segment the TLS ClientHello") + resolverAddress = flag.String("dns", "", "address of the dns resolver") resolverNetwork = flag.String("dns-net", "", "protocol for the dns resolver (e.g. \"tcp-tls\" or \"tcp\" or \"udp\")") )