diff --git a/transport/internet/http/dialer.go b/transport/internet/http/dialer.go index 30947103..5c4cbdfd 100644 --- a/transport/internet/http/dialer.go +++ b/transport/internet/http/dialer.go @@ -39,8 +39,8 @@ func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *in } httpSettings := streamSettings.ProtocolSettings.(*Config) - tlsConfig := tls.ConfigFromStreamSettings(streamSettings) - if tlsConfig == nil { + tlsConfigs := tls.ConfigFromStreamSettings(streamSettings) + if tlsConfigs == nil { return nil, newError("TLS must be enabled for http transport.").AtWarning() } sockopt := streamSettings.SocketSettings @@ -74,7 +74,12 @@ func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *in return nil, err } - cn := gotls.Client(pconn, tlsConfig) + var cn tls.Interface + if fingerprint, ok := tls.Fingerprints[tlsConfigs.Fingerprint]; ok { + cn = tls.UClient(pconn, tlsConfig, fingerprint).(*tls.UConn) + } else { + cn = tls.Client(pconn, tlsConfig).(*tls.Conn) + } if err := cn.Handshake(); err != nil { newError("failed to dial to " + addr).Base(err).AtError().WriteToLog() return nil, err @@ -85,16 +90,16 @@ func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *in return nil, err } } - state := cn.ConnectionState() - if p := state.NegotiatedProtocol; p != http2.NextProtoTLS { - return nil, newError("http2: unexpected ALPN protocol " + p + "; want q" + http2.NextProtoTLS).AtError() + negotiatedProtocol, negotiatedProtocolIsMutual := cn.NegotiatedProtocol() + if negotiatedProtocol != http2.NextProtoTLS { + return nil, newError("http2: unexpected ALPN protocol " + negotiatedProtocol + "; want q" + http2.NextProtoTLS).AtError() } - if !state.NegotiatedProtocolIsMutual { + if !negotiatedProtocolIsMutual { return nil, newError("http2: could not negotiate protocol mutually").AtError() } return cn, nil }, - TLSClientConfig: tlsConfig.GetTLSConfig(tls.WithDestination(dest)), + TLSClientConfig: tlsConfigs.GetTLSConfig(tls.WithDestination(dest)), } if httpSettings.IdleTimeout > 0 || httpSettings.HealthCheckTimeout > 0 { diff --git a/transport/internet/tls/tls.go b/transport/internet/tls/tls.go index 48ae8d72..ea86c0ce 100644 --- a/transport/internet/tls/tls.go +++ b/transport/internet/tls/tls.go @@ -34,6 +34,11 @@ func (c *Conn) HandshakeAddress() net.Address { return net.ParseAddress(state.ServerName) } +func (c *Conn) NegotiatedProtocol() (name string, mutual bool) { + state := c.ConnectionState() + return state.NegotiatedProtocol, state.NegotiatedProtocolIsMutual +} + // Client initiates a TLS client handshake on the given connection. func Client(c net.Conn, config *tls.Config) net.Conn { tlsConn := tls.Client(c, config) @@ -61,6 +66,11 @@ func (c *UConn) HandshakeAddress() net.Address { return net.ParseAddress(state.ServerName) } +func (c *UConn) NegotiatedProtocol() (name string, mutual bool) { + state := c.ConnectionState() + return state.NegotiatedProtocol, state.NegotiatedProtocolIsMutual +} + func UClient(c net.Conn, config *tls.Config, fingerprint *utls.ClientHelloID) net.Conn { utlsConn := utls.UClient(c, copyConfig(config), *fingerprint) return &UConn{UConn: utlsConn} @@ -80,3 +90,10 @@ var Fingerprints = map[string]*utls.ClientHelloID{ "safari": &utls.HelloIOS_Auto, "randomized": &utls.HelloRandomized, } + +type Interface interface { + net.Conn + Handshake() error + VerifyHostname(host string) error + NegotiatedProtocol() (name string, mutual bool) +}