From 518098ac2b27401c63a6b54bf3f2983b44bdf8ff Mon Sep 17 00:00:00 2001 From: Vladislav Yarmak Date: Fri, 28 Jul 2023 01:15:48 +0300 Subject: [PATCH] option to disable SNI hide --- holaapi.go | 2 +- main.go | 6 ++++-- plaintext.go | 10 ++++++++-- upstream.go | 12 +++++++++--- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/holaapi.go b/holaapi.go index 5a19a3d..00e5333 100644 --- a/holaapi.go +++ b/holaapi.go @@ -398,7 +398,7 @@ func httpClientWithProxy(agent *FallbackAgent) *http.Client { rootCAs = tlsConfig.RootCAs } if agent != nil { - dialer = NewProxyDialer(agent.NetAddr(), agent.Hostname(), rootCAs, nil, dialer) + dialer = NewProxyDialer(agent.NetAddr(), agent.Hostname(), rootCAs, nil, true, dialer) } t.DialContext = dialer.DialContext return &http.Client{ diff --git a/main.go b/main.go index fafc3a6..e97e164 100644 --- a/main.go +++ b/main.go @@ -64,6 +64,7 @@ type CLIArgs struct { maxPause time.Duration backoffInitial time.Duration backoffDeadline time.Duration + hideSNI bool } func parse_args() CLIArgs { @@ -93,6 +94,7 @@ func parse_args() CLIArgs { "Format: ://[login:password@]host[:port] "+ "Examples: http://user:password@192.168.1.1:3128, socks5://10.0.0.1:1080") flag.StringVar(&args.caFile, "cafile", "", "use custom CA certificate bundle file") + flag.BoolVar(&args.hideSNI, "hide-SNI", true, "hide SNI in TLS sessions with proxy server") flag.Parse() if args.country == "" { arg_fail("Country can't be empty string.") @@ -215,8 +217,8 @@ func run() int { mainLogger.Critical("Unable to determine proxy endpoint: %v", err) return 5 } - handlerDialer := NewProxyDialer(endpoint.NetAddr(), endpoint.TLSName, caPool, auth, dialer) - requestDialer := NewPlaintextDialer(endpoint.NetAddr(), endpoint.TLSName, caPool, dialer) + handlerDialer := NewProxyDialer(endpoint.NetAddr(), endpoint.TLSName, caPool, auth, args.hideSNI, dialer) + requestDialer := NewPlaintextDialer(endpoint.NetAddr(), endpoint.TLSName, caPool, args.hideSNI, dialer) mainLogger.Info("Endpoint: %s", endpoint.URL().String()) mainLogger.Info("Starting proxy server...") handler := NewProxyHandler(handlerDialer, requestDialer, auth, resolver, proxyLogger) diff --git a/plaintext.go b/plaintext.go index 2296322..c186d6c 100644 --- a/plaintext.go +++ b/plaintext.go @@ -13,14 +13,16 @@ type PlaintextDialer struct { tlsServerName string next ContextDialer caPool *x509.CertPool + hideSNI bool } -func NewPlaintextDialer(address, tlsServerName string, caPool *x509.CertPool, next ContextDialer) *PlaintextDialer { +func NewPlaintextDialer(address, tlsServerName string, caPool *x509.CertPool, hideSNI bool, next ContextDialer) *PlaintextDialer { return &PlaintextDialer{ fixedAddress: address, tlsServerName: tlsServerName, next: next, caPool: caPool, + hideSNI: hideSNI, } } @@ -40,8 +42,12 @@ func (d *PlaintextDialer) DialContext(ctx context.Context, network, address stri // Custom cert verification logic: // DO NOT send SNI extension of TLS ClientHello // DO peer certificate verification against specified servername + sni := d.tlsServerName + if d.hideSNI { + sni = "" + } conn = tls.Client(conn, &tls.Config{ - ServerName: "", + ServerName: sni, InsecureSkipVerify: true, VerifyConnection: func(cs tls.ConnectionState) error { opts := x509.VerifyOptions{ diff --git a/upstream.go b/upstream.go index ca7bebe..eb3b6f2 100644 --- a/upstream.go +++ b/upstream.go @@ -39,15 +39,17 @@ type ProxyDialer struct { auth AuthProvider next ContextDialer caPool *x509.CertPool + hideSNI bool } -func NewProxyDialer(address, tlsServerName string, caPool *x509.CertPool, auth AuthProvider, nextDialer ContextDialer) *ProxyDialer { +func NewProxyDialer(address, tlsServerName string, caPool *x509.CertPool, auth AuthProvider, hideSNI bool, nextDialer ContextDialer) *ProxyDialer { return &ProxyDialer{ address: address, tlsServerName: tlsServerName, auth: auth, next: nextDialer, caPool: caPool, + hideSNI: hideSNI, } } @@ -81,7 +83,7 @@ func ProxyDialerFromURL(u *url.URL, caPool *x509.CertPool, next ContextDialer) ( return authHeader } } - return NewProxyDialer(address, tlsServerName, caPool, auth, next), nil + return NewProxyDialer(address, tlsServerName, caPool, auth, false, next), nil } func (d *ProxyDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { @@ -100,8 +102,12 @@ func (d *ProxyDialer) DialContext(ctx context.Context, network, address string) // Custom cert verification logic: // DO NOT send SNI extension of TLS ClientHello // DO peer certificate verification against specified servername + sni := d.tlsServerName + if d.hideSNI { + sni = "" + } conn = tls.Client(conn, &tls.Config{ - ServerName: "", + ServerName: sni, InsecureSkipVerify: true, VerifyConnection: func(cs tls.ConnectionState) error { opts := x509.VerifyOptions{