From 502bd65db8ae4e752c0c827dd9fa27024f41e067 Mon Sep 17 00:00:00 2001 From: Sleeyax Date: Thu, 12 May 2022 16:53:57 +0200 Subject: [PATCH 1/3] Add optional method ProxyTLSConnection (closes #779) Removed the call to NetDialTLSContext from the HTTP proxy CONNECT step and replaced it with a regular net.Dial in order to prevent connection issues. Custom TLS connections can now be made via the new optional ProxyTLSConnection method, after the proxy connection has been successfully established. --- client.go | 45 ++++++++++++++++++++++++++++----------------- proxy.go | 2 +- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/client.go b/client.go index 2efd835..eb3c9fa 100644 --- a/client.go +++ b/client.go @@ -65,6 +65,12 @@ type Dialer struct { // TLSClientConfig is ignored. NetDialTLSContext func(ctx context.Context, network, addr string) (net.Conn, error) + // ProxyTLSConnection specifies the dial function for creating TLS connections through a Proxy. If + // ProxyTLSConnection is nil, NetDialTLSContext is used. + // If ProxyTLSConnection is set, Dial assumes the TLS handshake is done there and + // TLSClientConfig is ignored. + ProxyTLSConnection func(ctx context.Context, proxyConn net.Conn) (net.Conn, error) + // Proxy specifies a function to return a proxy for a given // Request. If the function returns a non-nil error, the // request is aborted with the provided error. @@ -333,26 +339,31 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h } }() - if u.Scheme == "https" && d.NetDialTLSContext == nil { - // If NetDialTLSContext is set, assume that the TLS handshake has already been done + if u.Scheme == "https" { + if d.ProxyTLSConnection != nil && d.Proxy != nil { + // If we are connected to a proxy, perform the TLS handshake through the existing tunnel + netConn, err = d.ProxyTLSConnection(ctx, netConn) + } else if d.NetDialTLSContext == nil { + // If NetDialTLSContext is set, assume that the TLS handshake has already been done - cfg := cloneTLSConfig(d.TLSClientConfig) - if cfg.ServerName == "" { - cfg.ServerName = hostNoPort - } - tlsConn := tls.Client(netConn, cfg) - netConn = tlsConn + cfg := cloneTLSConfig(d.TLSClientConfig) + if cfg.ServerName == "" { + cfg.ServerName = hostNoPort + } + tlsConn := tls.Client(netConn, cfg) + netConn = tlsConn - if trace != nil && trace.TLSHandshakeStart != nil { - trace.TLSHandshakeStart() - } - err := doHandshake(ctx, tlsConn, cfg) - if trace != nil && trace.TLSHandshakeDone != nil { - trace.TLSHandshakeDone(tlsConn.ConnectionState(), err) - } + if trace != nil && trace.TLSHandshakeStart != nil { + trace.TLSHandshakeStart() + } + err := doHandshake(ctx, tlsConn, cfg) + if trace != nil && trace.TLSHandshakeDone != nil { + trace.TLSHandshakeDone(tlsConn.ConnectionState(), err) + } - if err != nil { - return nil, nil, err + if err != nil { + return nil, nil, err + } } } diff --git a/proxy.go b/proxy.go index e0f466b..07266f0 100644 --- a/proxy.go +++ b/proxy.go @@ -33,7 +33,7 @@ type httpProxyDialer struct { func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) { hostPort, _ := hostPortNoPort(hpd.proxyURL) - conn, err := hpd.forwardDial(network, hostPort) + conn, err := net.Dial(network, hostPort) if err != nil { return nil, err } From adb13885c212e041a49ae61915bd685872c8cd17 Mon Sep 17 00:00:00 2001 From: Sleeyax Date: Sat, 14 May 2022 15:47:30 +0200 Subject: [PATCH 2/3] Check error --- client.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client.go b/client.go index eb3c9fa..c626fed 100644 --- a/client.go +++ b/client.go @@ -343,6 +343,9 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h if d.ProxyTLSConnection != nil && d.Proxy != nil { // If we are connected to a proxy, perform the TLS handshake through the existing tunnel netConn, err = d.ProxyTLSConnection(ctx, netConn) + if err != nil { + return nil, nil, err + } } else if d.NetDialTLSContext == nil { // If NetDialTLSContext is set, assume that the TLS handshake has already been done From 36867e9319fc431834a7f4c111a90ee31676da64 Mon Sep 17 00:00:00 2001 From: Sleeyax Date: Wed, 26 Oct 2022 19:04:40 +0200 Subject: [PATCH 3/3] Include hostPort in function signature --- client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client.go b/client.go index c626fed..17e0810 100644 --- a/client.go +++ b/client.go @@ -69,7 +69,7 @@ type Dialer struct { // ProxyTLSConnection is nil, NetDialTLSContext is used. // If ProxyTLSConnection is set, Dial assumes the TLS handshake is done there and // TLSClientConfig is ignored. - ProxyTLSConnection func(ctx context.Context, proxyConn net.Conn) (net.Conn, error) + ProxyTLSConnection func(ctx context.Context, hostPort string, proxyConn net.Conn) (net.Conn, error) // Proxy specifies a function to return a proxy for a given // Request. If the function returns a non-nil error, the @@ -342,7 +342,7 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h if u.Scheme == "https" { if d.ProxyTLSConnection != nil && d.Proxy != nil { // If we are connected to a proxy, perform the TLS handshake through the existing tunnel - netConn, err = d.ProxyTLSConnection(ctx, netConn) + netConn, err = d.ProxyTLSConnection(ctx, hostPort, netConn) if err != nil { return nil, nil, err }