Add h2Alpn option for TLS ClientHello

This commit is contained in:
wenyifan 2022-10-19 10:06:58 +08:00
parent ce15e23ce2
commit 85171b62b3
5 changed files with 110 additions and 76 deletions

View File

@ -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

View File

@ -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{

View File

@ -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
View File

@ -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
//

50
ws.go
View File

@ -744,28 +744,8 @@ type websocketConn struct {
rb []byte
}
func websocketClientConn(url string, conn net.Conn, tlsConfig *tls.Config, options *WSOptions) (net.Conn, error) {
if options == nil {
options = &WSOptions{}
}
timeout := options.HandshakeTimeout
if timeout <= 0 {
timeout = HandshakeTimeout
}
dialer := websocket.Dialer{
ReadBufferSize: options.ReadBufferSize,
WriteBufferSize: options.WriteBufferSize,
TLSClientConfig: tlsConfig,
HandshakeTimeout: timeout,
EnableCompression: options.EnableCompression,
NetDial: func(net, addr string) (net.Conn, error) {
return conn, nil
},
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{
func newWsSpec() *utls.ClientHelloSpec {
return &utls.ClientHelloSpec{
CipherSuites: []uint16{
utls.GREASE_PLACEHOLDER,
utls.TLS_AES_128_GCM_SHA256,
@ -834,7 +814,31 @@ func websocketClientConn(url string, conn net.Conn, tlsConfig *tls.Config, optio
&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{}
}
timeout := options.HandshakeTimeout
if timeout <= 0 {
timeout = HandshakeTimeout
}
dialer := websocket.Dialer{
ReadBufferSize: options.ReadBufferSize,
WriteBufferSize: options.WriteBufferSize,
TLSClientConfig: tlsConfig,
HandshakeTimeout: timeout,
EnableCompression: options.EnableCompression,
NetDial: func(net, addr string) (net.Conn, error) {
return conn, nil
},
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(newWsSpec())
err := client.Handshake()
if err != nil {
return nil, err