From 62628c8606a9ab05af210c9f4ce13c72650f3aff Mon Sep 17 00:00:00 2001 From: Vladislav Yarmak Date: Sat, 21 Dec 2024 20:47:28 +0200 Subject: [PATCH] SNI control --- dialer/upstream.go | 19 ++++++++++++++++--- main.go | 5 ++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/dialer/upstream.go b/dialer/upstream.go index 362c1ee..7ec045c 100644 --- a/dialer/upstream.go +++ b/dialer/upstream.go @@ -65,16 +65,18 @@ type ContextDialer interface { type ProxyDialer struct { address stringCb tlsServerName stringCb + fakeSNI stringCb auth stringCb next ContextDialer intermediateWorkaround bool caPool *x509.CertPool } -func NewProxyDialer(address, tlsServerName, auth stringCb, intermediateWorkaround bool, caPool *x509.CertPool, nextDialer ContextDialer) *ProxyDialer { +func NewProxyDialer(address, tlsServerName, fakeSNI, auth stringCb, intermediateWorkaround bool, caPool *x509.CertPool, nextDialer ContextDialer) *ProxyDialer { return &ProxyDialer{ address: address, tlsServerName: tlsServerName, + fakeSNI: fakeSNI, auth: auth, next: nextDialer, intermediateWorkaround: intermediateWorkaround, @@ -109,7 +111,14 @@ func ProxyDialerFromURL(u *url.URL, next ContextDialer) (*ProxyDialer, error) { password, _ := u.User.Password() auth = WrapStringToCb(BasicAuthHeader(username, password)) } - return NewProxyDialer(WrapStringToCb(address), WrapStringToCb(tlsServerName), auth, false, nil, next), nil + return NewProxyDialer( + WrapStringToCb(address), + WrapStringToCb(tlsServerName), + WrapStringToCb(tlsServerName), + auth, + false, + nil, + next), nil } func (d *ProxyDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { @@ -132,12 +141,16 @@ func (d *ProxyDialer) DialContext(ctx context.Context, network, address string) if err != nil { return nil, err } + fakeSNI, err := d.fakeSNI() + if err != nil { + return nil, err + } if uTLSServerName != "" { // Custom cert verification logic: // DO NOT send SNI extension of TLS ClientHello // DO peer certificate verification against specified servername conn = tls.Client(conn, &tls.Config{ - ServerName: "", + ServerName: fakeSNI, InsecureSkipVerify: true, VerifyConnection: func(cs tls.ConnectionState) error { opts := x509.VerifyOptions{ diff --git a/main.go b/main.go index 2c70c8d..fbdc0b2 100644 --- a/main.go +++ b/main.go @@ -102,6 +102,7 @@ type CLIArgs struct { initRetryInterval time.Duration certChainWorkaround bool caFile string + fakeSNI string } func parse_args() *CLIArgs { @@ -147,6 +148,7 @@ func parse_args() *CLIArgs { flag.BoolVar(&args.certChainWorkaround, "certchain-workaround", true, "add bundled cross-signed intermediate cert to certchain to make it check out on old systems") flag.StringVar(&args.caFile, "cafile", "", "use custom CA certificate bundle file") + flag.StringVar(&args.fakeSNI, "fake-SNI", "", "domain name to use as SNI in communications with servers") flag.Parse() if args.country == "" { arg_fail("Country can't be empty string.") @@ -223,7 +225,7 @@ func run() int { // Dialing w/o SNI, receiving self-signed certificate, so skip verification. // Either way we'll validate certificate of actual proxy server. tlsConfig := &tls.Config{ - ServerName: "", + ServerName: args.fakeSNI, InsecureSkipVerify: true, } seclient, err := se.NewSEClient(args.apiLogin, args.apiPassword, &http.Transport{ @@ -337,6 +339,7 @@ func run() int { handlerDialer := dialer.NewProxyDialer( dialer.WrapStringToCb(endpoint.NetAddr()), dialer.WrapStringToCb(fmt.Sprintf("%s0.%s", args.country, PROXY_SUFFIX)), + dialer.WrapStringToCb(args.fakeSNI), func() (string, error) { return dialer.BasicAuthHeader(seclient.GetProxyCredentials()), nil },