From d8df9755f2e8c41ee21110f77bc0b0b662f59414 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 28 Jul 2021 22:11:20 +0100 Subject: [PATCH 1/4] Allow specifying TLS SNI with ?sni= in peering URI --- src/core/link.go | 1 + src/core/tcp.go | 1 + src/core/tls.go | 13 ++++++++----- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/core/link.go b/src/core/link.go index ccab921..f753156 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -98,6 +98,7 @@ func (l *links) call(u *url.URL, sintf string) error { l.tcp.call(pathtokens[0], tcpOpts, sintf) case "tls": tcpOpts.upgrade = l.tcp.tls.forDialer + tcpOpts.tlsSNI = u.Query().Get("sni") l.tcp.call(u.Host, tcpOpts, sintf) default: return errors.New("unknown call scheme: " + u.Scheme) diff --git a/src/core/tcp.go b/src/core/tcp.go index 572fd65..7b1773b 100644 --- a/src/core/tcp.go +++ b/src/core/tcp.go @@ -64,6 +64,7 @@ type tcpOptions struct { socksProxyAddr string socksProxyAuth *proxy.Auth socksPeerAddr string + tlsSNI string } func (l *TcpListener) Stop() { diff --git a/src/core/tls.go b/src/core/tls.go index 4c25225..eb21fcb 100644 --- a/src/core/tls.go +++ b/src/core/tls.go @@ -77,8 +77,8 @@ func (t *tcptls) init(tcp *tcp) { } } -func (t *tcptls) configForOptions(options *tcpOptions) *tls.Config { - config := *t.config +func (t *tcptls) configForOptions(options *tcpOptions, serverName string) *tls.Config { + config := t.config.Clone() config.VerifyPeerCertificate = func(rawCerts [][]byte, _ [][]*x509.Certificate) error { if len(rawCerts) != 1 { return errors.New("tls not exactly 1 cert") @@ -103,11 +103,14 @@ func (t *tcptls) configForOptions(options *tcpOptions) *tls.Config { } return nil } - return &config + if serverName != "" { + config.ServerName = serverName + } + return config } func (t *tcptls) upgradeListener(c net.Conn, options *tcpOptions) (net.Conn, error) { - config := t.configForOptions(options) + config := t.configForOptions(options, "") conn := tls.Server(c, config) if err := conn.Handshake(); err != nil { return c, err @@ -116,7 +119,7 @@ func (t *tcptls) upgradeListener(c net.Conn, options *tcpOptions) (net.Conn, err } func (t *tcptls) upgradeDialer(c net.Conn, options *tcpOptions) (net.Conn, error) { - config := t.configForOptions(options) + config := t.configForOptions(options, options.tlsSNI) conn := tls.Client(c, config) if err := conn.Handshake(); err != nil { return c, err From f094cf34bf23bde6d6c8515c79f1ad14ea3a230c Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 28 Jul 2021 22:23:33 +0100 Subject: [PATCH 2/4] Set SNI by default if the peering URI contains a DNS name --- src/core/link.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/core/link.go b/src/core/link.go index f753156..98a7ab3 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -99,6 +99,13 @@ func (l *links) call(u *url.URL, sintf string) error { case "tls": tcpOpts.upgrade = l.tcp.tls.forDialer tcpOpts.tlsSNI = u.Query().Get("sni") + if tcpOpts.tlsSNI == "" { + // SNI headers must contain hostnames and not IP addresses, so we must make sure + // that we do not populate the SNI with an IP literal. + if host, _, err := net.SplitHostPort(u.Host); err == nil && net.ParseIP(host) == nil { + tcpOpts.tlsSNI = host + } + } l.tcp.call(u.Host, tcpOpts, sintf) default: return errors.New("unknown call scheme: " + u.Scheme) From bbdff033ce29d657c099f73f7946c1d5061a1b9c Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 1 Aug 2021 21:36:51 +0100 Subject: [PATCH 3/4] Update SNI code --- src/core/link.go | 14 +++++++++++--- src/core/tls.go | 10 ++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/core/link.go b/src/core/link.go index 98a7ab3..755d38a 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -98,10 +98,18 @@ func (l *links) call(u *url.URL, sintf string) error { l.tcp.call(pathtokens[0], tcpOpts, sintf) case "tls": tcpOpts.upgrade = l.tcp.tls.forDialer - tcpOpts.tlsSNI = u.Query().Get("sni") + // SNI headers must contain hostnames and not IP addresses, so we must make sure + // that we do not populate the SNI with an IP literal. We do this by splitting + // the host-port combo from the query option and then seeing if it parses to an + // IP address successfully or not. + if sni := u.Query().Get("sni"); sni != "" { + if host, _, err := net.SplitHostPort(sni); err == nil && net.ParseIP(host) == nil { + tcpOpts.tlsSNI = host + } + } + // If the SNI is not configured still because the above failed then we'll try + // again but this time we'll use the host part of the peering URI instead. if tcpOpts.tlsSNI == "" { - // SNI headers must contain hostnames and not IP addresses, so we must make sure - // that we do not populate the SNI with an IP literal. if host, _, err := net.SplitHostPort(u.Host); err == nil && net.ParseIP(host) == nil { tcpOpts.tlsSNI = host } diff --git a/src/core/tls.go b/src/core/tls.go index eb21fcb..9e340ac 100644 --- a/src/core/tls.go +++ b/src/core/tls.go @@ -77,7 +77,7 @@ func (t *tcptls) init(tcp *tcp) { } } -func (t *tcptls) configForOptions(options *tcpOptions, serverName string) *tls.Config { +func (t *tcptls) configForOptions(options *tcpOptions) *tls.Config { config := t.config.Clone() config.VerifyPeerCertificate = func(rawCerts [][]byte, _ [][]*x509.Certificate) error { if len(rawCerts) != 1 { @@ -103,14 +103,11 @@ func (t *tcptls) configForOptions(options *tcpOptions, serverName string) *tls.C } return nil } - if serverName != "" { - config.ServerName = serverName - } return config } func (t *tcptls) upgradeListener(c net.Conn, options *tcpOptions) (net.Conn, error) { - config := t.configForOptions(options, "") + config := t.configForOptions(options) conn := tls.Server(c, config) if err := conn.Handshake(); err != nil { return c, err @@ -119,7 +116,8 @@ func (t *tcptls) upgradeListener(c net.Conn, options *tcpOptions) (net.Conn, err } func (t *tcptls) upgradeDialer(c net.Conn, options *tcpOptions) (net.Conn, error) { - config := t.configForOptions(options, options.tlsSNI) + config := t.configForOptions(options) + config.ServerName = options.tlsSNI conn := tls.Client(c, config) if err := conn.Handshake(); err != nil { return c, err From d1cd671bece1c69942f069d059174f01d5565406 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 1 Aug 2021 21:39:49 +0100 Subject: [PATCH 4/4] Fix bug --- src/core/link.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/link.go b/src/core/link.go index 755d38a..8797b88 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -103,8 +103,8 @@ func (l *links) call(u *url.URL, sintf string) error { // the host-port combo from the query option and then seeing if it parses to an // IP address successfully or not. if sni := u.Query().Get("sni"); sni != "" { - if host, _, err := net.SplitHostPort(sni); err == nil && net.ParseIP(host) == nil { - tcpOpts.tlsSNI = host + if net.ParseIP(sni) == nil { + tcpOpts.tlsSNI = sni } } // If the SNI is not configured still because the above failed then we'll try