From 93a5adfd189ff8ecd233693dc123b0ef7e11216f Mon Sep 17 00:00:00 2001 From: Neil Date: Sat, 4 Nov 2023 17:57:15 +0000 Subject: [PATCH] Add `sockstls://` (#1090) Closes #1087. Co-authored-by: Neil Alexander --- src/core/link.go | 34 +++++++++++++++++----------------- src/core/link_socks.go | 12 +++++++++++- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/core/link.go b/src/core/link.go index f3cb4318..0b2efc57 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -179,6 +179,22 @@ func (l *links) add(u *url.URL, sintf string, linkType linkType) error { } options.password = []byte(p) } + // 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 net.ParseIP(sni) == nil { + options.tlsSNI = sni + } + } + // 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 options.tlsSNI == "" { + if host, _, err := net.SplitHostPort(u.Host); err == nil && net.ParseIP(host) == nil { + options.tlsSNI = host + } + } // If we think we're already connected to this peer, load up // the existing peer state. Try to kick the peer if possible, @@ -497,24 +513,8 @@ func (l *links) connect(ctx context.Context, u *url.URL, info linkInfo, options case "tcp": dialer = l.tcp case "tls": - // 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 net.ParseIP(sni) == nil { - options.tlsSNI = sni - } - } - // 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 options.tlsSNI == "" { - if host, _, err := net.SplitHostPort(u.Host); err == nil && net.ParseIP(host) == nil { - options.tlsSNI = host - } - } dialer = l.tls - case "socks": + case "socks", "sockstls": dialer = l.socks case "unix": dialer = l.unix diff --git a/src/core/link_socks.go b/src/core/link_socks.go index 1a038fa6..b92374d4 100644 --- a/src/core/link_socks.go +++ b/src/core/link_socks.go @@ -2,6 +2,7 @@ package core import ( "context" + "crypto/tls" "fmt" "net" "net/url" @@ -34,7 +35,16 @@ func (l *linkSOCKS) dial(_ context.Context, url *url.URL, info linkInfo, options return nil, fmt.Errorf("failed to configure proxy") } pathtokens := strings.Split(strings.Trim(url.Path, "/"), "/") - return dialer.Dial("tcp", pathtokens[0]) + conn, err := dialer.Dial("tcp", pathtokens[0]) + if err != nil { + return nil, fmt.Errorf("failed to dial: %w", err) + } + if url.Scheme == "sockstls" { + tlsconfig := l.tls.config.Clone() + tlsconfig.ServerName = options.tlsSNI + conn = tls.Client(conn, tlsconfig) + } + return conn, nil } func (l *linkSOCKS) listen(ctx context.Context, url *url.URL, _ string) (net.Listener, error) {