Add h2Alpn option for TLS ClientHello
This commit is contained in:
parent
ce15e23ce2
commit
85171b62b3
16
client.go
16
client.go
@ -85,6 +85,7 @@ type DialOptions struct {
|
||||
Chain *Chain
|
||||
Host string
|
||||
HeaderConfig map[string]string
|
||||
H2Alpn bool
|
||||
}
|
||||
|
||||
// DialOption allows a common way to set DialOptions.
|
||||
@ -118,6 +119,13 @@ func HeaderConfigDialOption(HeaderConfig map[string]string) DialOption {
|
||||
}
|
||||
}
|
||||
|
||||
// H2AlpnDialOption specifies is use HTTP2 in ALPN for TLS ClientHello
|
||||
func H2AlpnDialOption(useH2Alpn bool) DialOption {
|
||||
return func(opts *DialOptions) {
|
||||
opts.H2Alpn = useH2Alpn
|
||||
}
|
||||
}
|
||||
|
||||
// HandshakeOptions describes the options for handshake.
|
||||
type HandshakeOptions struct {
|
||||
Addr string
|
||||
@ -131,6 +139,7 @@ type HandshakeOptions struct {
|
||||
KCPConfig *KCPConfig
|
||||
QUICConfig *QUICConfig
|
||||
SSHConfig *SSHConfig
|
||||
H2Alpn bool
|
||||
}
|
||||
|
||||
// HandshakeOption allows a common way to set HandshakeOptions.
|
||||
@ -213,6 +222,13 @@ func SSHConfigHandshakeOption(config *SSHConfig) HandshakeOption {
|
||||
}
|
||||
}
|
||||
|
||||
// H2AlpnHandshakeOption specifies is use HTTP2 in ALPN for TLS ClientHello.
|
||||
func H2AlpnHandshakeOption(useH2Alpn bool) HandshakeOption {
|
||||
return func(opts *HandshakeOptions) {
|
||||
opts.H2Alpn = useH2Alpn
|
||||
}
|
||||
}
|
||||
|
||||
// ConnectOptions describes the options for Connector.Connect.
|
||||
type ConnectOptions struct {
|
||||
Addr string
|
||||
|
@ -291,10 +291,17 @@ func parseChainNode(ns string) (nodes []gost.Node, err error) {
|
||||
|
||||
}
|
||||
|
||||
h2AlpnStr := node.Get("h2Alpn")
|
||||
h2Alpn := true
|
||||
if h2AlpnStr != "" {
|
||||
h2Alpn = node.GetBool("h2Alpn")
|
||||
}
|
||||
|
||||
node.DialOptions = append(node.DialOptions,
|
||||
gost.TimeoutDialOption(timeout),
|
||||
gost.HostDialOption(host),
|
||||
gost.HeaderConfigDialOption(headerCfg),
|
||||
gost.H2AlpnDialOption(h2Alpn),
|
||||
)
|
||||
|
||||
node.ConnectOptions = []gost.ConnectOption{
|
||||
@ -322,6 +329,7 @@ func parseChainNode(ns string) (nodes []gost.Node, err error) {
|
||||
gost.TimeoutHandshakeOption(timeout),
|
||||
gost.RetryHandshakeOption(node.GetInt("retry")),
|
||||
gost.SSHConfigHandshakeOption(sshConfig),
|
||||
gost.H2AlpnHandshakeOption(h2Alpn),
|
||||
}
|
||||
|
||||
node.Client = &gost.Client{
|
||||
|
4
http2.go
4
http2.go
@ -161,7 +161,7 @@ func (tr *http2Transporter) Dial(addr string, options ...DialOption) (net.Conn,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return wrapTLSClient(conn, cfg, timeout)
|
||||
return wrapTLSClient(conn, cfg, timeout, opts.H2Alpn)
|
||||
},
|
||||
}
|
||||
client = &http.Client{
|
||||
@ -242,7 +242,7 @@ func (tr *h2Transporter) Dial(addr string, options ...DialOption) (net.Conn, err
|
||||
if tr.tlsConfig == nil {
|
||||
return conn, nil
|
||||
}
|
||||
return wrapTLSClient(conn, cfg, timeout)
|
||||
return wrapTLSClient(conn, cfg, timeout, opts.H2Alpn)
|
||||
},
|
||||
}
|
||||
client = &http.Client{
|
||||
|
14
tls.go
14
tls.go
@ -36,7 +36,7 @@ func (tr *tlsTransporter) Handshake(conn net.Conn, options ...HandshakeOption) (
|
||||
timeout = HandshakeTimeout
|
||||
}
|
||||
|
||||
return wrapTLSClient(conn, opts.TLSConfig, timeout)
|
||||
return wrapTLSClient(conn, opts.TLSConfig, timeout, opts.H2Alpn)
|
||||
}
|
||||
|
||||
type mtlsTransporter struct {
|
||||
@ -131,7 +131,7 @@ func (tr *mtlsTransporter) initSession(addr string, conn net.Conn, opts *Handsha
|
||||
if opts.TLSConfig == nil {
|
||||
opts.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
}
|
||||
conn, err := wrapTLSClient(conn, opts.TLSConfig, opts.Timeout)
|
||||
conn, err := wrapTLSClient(conn, opts.TLSConfig, opts.Timeout, opts.H2Alpn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -268,7 +268,7 @@ func (l *mtlsListener) Close() error {
|
||||
//
|
||||
// This code is taken from consul:
|
||||
// https://github.com/hashicorp/consul/blob/master/tlsutil/config.go
|
||||
func wrapTLSClient(conn net.Conn, tlsConfig *tls.Config, timeout time.Duration) (net.Conn, error) {
|
||||
func wrapTLSClient(conn net.Conn, tlsConfig *tls.Config, timeout time.Duration, h2Alpn bool) (net.Conn, error) {
|
||||
var err error
|
||||
|
||||
if timeout <= 0 {
|
||||
@ -279,7 +279,13 @@ func wrapTLSClient(conn net.Conn, tlsConfig *tls.Config, timeout time.Duration)
|
||||
defer conn.SetDeadline(time.Time{})
|
||||
|
||||
//tlsConn := tls.Client(conn, tlsConfig)
|
||||
tlsConn := utls.UClient(conn, &utls.Config{InsecureSkipVerify: tlsConfig.InsecureSkipVerify, ServerName: tlsConfig.ServerName}, utls.HelloChrome_Auto)
|
||||
var tlsConn *utls.UConn
|
||||
if h2Alpn {
|
||||
tlsConn = utls.UClient(conn, &utls.Config{InsecureSkipVerify: tlsConfig.InsecureSkipVerify, ServerName: tlsConfig.ServerName}, utls.HelloChrome_Auto)
|
||||
} else {
|
||||
tlsConn = utls.UClient(conn, &utls.Config{InsecureSkipVerify: tlsConfig.InsecureSkipVerify, ServerName: tlsConfig.ServerName}, utls.HelloCustom)
|
||||
tlsConn.ApplyPreset(newWsSpec())
|
||||
}
|
||||
|
||||
// Otherwise perform handshake, but don't verify the domain
|
||||
//
|
||||
|
144
ws.go
144
ws.go
@ -744,6 +744,79 @@ type websocketConn struct {
|
||||
rb []byte
|
||||
}
|
||||
|
||||
func newWsSpec() *utls.ClientHelloSpec {
|
||||
return &utls.ClientHelloSpec{
|
||||
CipherSuites: []uint16{
|
||||
utls.GREASE_PLACEHOLDER,
|
||||
utls.TLS_AES_128_GCM_SHA256,
|
||||
utls.TLS_AES_256_GCM_SHA384,
|
||||
utls.TLS_CHACHA20_POLY1305_SHA256,
|
||||
utls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
utls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
utls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
utls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
utls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
|
||||
utls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
utls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
utls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
||||
utls.TLS_RSA_WITH_AES_128_GCM_SHA256,
|
||||
utls.TLS_RSA_WITH_AES_256_GCM_SHA384,
|
||||
utls.TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
utls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
},
|
||||
CompressionMethods: []byte{
|
||||
0x00, // compressionNone
|
||||
},
|
||||
Extensions: []utls.TLSExtension{
|
||||
&utls.UtlsGREASEExtension{},
|
||||
&utls.SNIExtension{},
|
||||
&utls.UtlsExtendedMasterSecretExtension{},
|
||||
&utls.RenegotiationInfoExtension{Renegotiation: utls.RenegotiateOnceAsClient},
|
||||
&utls.SupportedCurvesExtension{[]utls.CurveID{
|
||||
utls.GREASE_PLACEHOLDER,
|
||||
utls.X25519,
|
||||
utls.CurveP256,
|
||||
utls.CurveP384,
|
||||
}},
|
||||
&utls.SupportedPointsExtension{SupportedPoints: []byte{
|
||||
0x00, // pointFormatUncompressed
|
||||
}},
|
||||
&utls.SessionTicketExtension{},
|
||||
&utls.ALPNExtension{AlpnProtocols: []string{"http/1.1"}},
|
||||
&utls.StatusRequestExtension{},
|
||||
&utls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []utls.SignatureScheme{
|
||||
utls.ECDSAWithP256AndSHA256,
|
||||
utls.PSSWithSHA256,
|
||||
utls.PKCS1WithSHA256,
|
||||
utls.ECDSAWithP384AndSHA384,
|
||||
utls.PSSWithSHA384,
|
||||
utls.PKCS1WithSHA384,
|
||||
utls.PSSWithSHA512,
|
||||
utls.PKCS1WithSHA512,
|
||||
}},
|
||||
&utls.SCTExtension{},
|
||||
&utls.KeyShareExtension{[]utls.KeyShare{
|
||||
{Group: utls.CurveID(utls.GREASE_PLACEHOLDER), Data: []byte{0}},
|
||||
{Group: utls.X25519},
|
||||
}},
|
||||
&utls.PSKKeyExchangeModesExtension{[]uint8{
|
||||
utls.PskModeDHE,
|
||||
}},
|
||||
&utls.SupportedVersionsExtension{[]uint16{
|
||||
utls.GREASE_PLACEHOLDER,
|
||||
utls.VersionTLS13,
|
||||
utls.VersionTLS12,
|
||||
}},
|
||||
&utls.UtlsCompressCertExtension{[]utls.CertCompressionAlgo{
|
||||
utls.CertCompressionBrotli,
|
||||
}},
|
||||
&utls.ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
|
||||
&utls.UtlsGREASEExtension{},
|
||||
&utls.UtlsPaddingExtension{GetPaddingLen: utls.BoringPaddingStyle},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func websocketClientConn(url string, conn net.Conn, tlsConfig *tls.Config, options *WSOptions) (net.Conn, error) {
|
||||
if options == nil {
|
||||
options = &WSOptions{}
|
||||
@ -765,76 +838,7 @@ func websocketClientConn(url string, conn net.Conn, tlsConfig *tls.Config, optio
|
||||
},
|
||||
NetDialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
client := utls.UClient(conn, &utls.Config{InsecureSkipVerify: tlsConfig.InsecureSkipVerify, ServerName: tlsConfig.ServerName}, utls.HelloCustom)
|
||||
client.ApplyPreset(&utls.ClientHelloSpec{
|
||||
CipherSuites: []uint16{
|
||||
utls.GREASE_PLACEHOLDER,
|
||||
utls.TLS_AES_128_GCM_SHA256,
|
||||
utls.TLS_AES_256_GCM_SHA384,
|
||||
utls.TLS_CHACHA20_POLY1305_SHA256,
|
||||
utls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
utls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
utls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
utls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
utls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
|
||||
utls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
utls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
utls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
||||
utls.TLS_RSA_WITH_AES_128_GCM_SHA256,
|
||||
utls.TLS_RSA_WITH_AES_256_GCM_SHA384,
|
||||
utls.TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
utls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
},
|
||||
CompressionMethods: []byte{
|
||||
0x00, // compressionNone
|
||||
},
|
||||
Extensions: []utls.TLSExtension{
|
||||
&utls.UtlsGREASEExtension{},
|
||||
&utls.SNIExtension{},
|
||||
&utls.UtlsExtendedMasterSecretExtension{},
|
||||
&utls.RenegotiationInfoExtension{Renegotiation: utls.RenegotiateOnceAsClient},
|
||||
&utls.SupportedCurvesExtension{[]utls.CurveID{
|
||||
utls.GREASE_PLACEHOLDER,
|
||||
utls.X25519,
|
||||
utls.CurveP256,
|
||||
utls.CurveP384,
|
||||
}},
|
||||
&utls.SupportedPointsExtension{SupportedPoints: []byte{
|
||||
0x00, // pointFormatUncompressed
|
||||
}},
|
||||
&utls.SessionTicketExtension{},
|
||||
&utls.ALPNExtension{AlpnProtocols: []string{"http/1.1"}},
|
||||
&utls.StatusRequestExtension{},
|
||||
&utls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []utls.SignatureScheme{
|
||||
utls.ECDSAWithP256AndSHA256,
|
||||
utls.PSSWithSHA256,
|
||||
utls.PKCS1WithSHA256,
|
||||
utls.ECDSAWithP384AndSHA384,
|
||||
utls.PSSWithSHA384,
|
||||
utls.PKCS1WithSHA384,
|
||||
utls.PSSWithSHA512,
|
||||
utls.PKCS1WithSHA512,
|
||||
}},
|
||||
&utls.SCTExtension{},
|
||||
&utls.KeyShareExtension{[]utls.KeyShare{
|
||||
{Group: utls.CurveID(utls.GREASE_PLACEHOLDER), Data: []byte{0}},
|
||||
{Group: utls.X25519},
|
||||
}},
|
||||
&utls.PSKKeyExchangeModesExtension{[]uint8{
|
||||
utls.PskModeDHE,
|
||||
}},
|
||||
&utls.SupportedVersionsExtension{[]uint16{
|
||||
utls.GREASE_PLACEHOLDER,
|
||||
utls.VersionTLS13,
|
||||
utls.VersionTLS12,
|
||||
}},
|
||||
&utls.UtlsCompressCertExtension{[]utls.CertCompressionAlgo{
|
||||
utls.CertCompressionBrotli,
|
||||
}},
|
||||
&utls.ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
|
||||
&utls.UtlsGREASEExtension{},
|
||||
&utls.UtlsPaddingExtension{GetPaddingLen: utls.BoringPaddingStyle},
|
||||
},
|
||||
})
|
||||
client.ApplyPreset(newWsSpec())
|
||||
err := client.Handshake()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
Loading…
Reference in New Issue
Block a user