diff --git a/record_detect.go b/record_detect.go index 923d179..d2399c3 100644 --- a/record_detect.go +++ b/record_detect.go @@ -5,6 +5,7 @@ import ( "encoding/binary" "io" "net" + "strconv" "sync" "time" @@ -16,36 +17,50 @@ var GlobalPostHandshakeRecordsLens sync.Map func DetectPostHandshakeRecordsLens(config *Config) { for sni := range config.ServerNames { - key := config.Dest + " " + sni - if _, loaded := GlobalPostHandshakeRecordsLens.LoadOrStore(key, false); !loaded { - go func() { - defer func() { - val, _ := GlobalPostHandshakeRecordsLens.Load(key) - if _, ok := val.(bool); ok { - GlobalPostHandshakeRecordsLens.Store(key, []int{}) - } - }() - target, err := net.Dial("tcp", config.Dest) - if err != nil { - return - } - if config.Xver == 1 || config.Xver == 2 { - if _, err = proxyproto.HeaderProxyFromAddrs(config.Xver, target.LocalAddr(), target.RemoteAddr()).WriteTo(target); err != nil { + for alpn := range 3 { // 0, 1, 2 + key := config.Dest + " " + sni + " " + strconv.Itoa(alpn) + if _, loaded := GlobalPostHandshakeRecordsLens.LoadOrStore(key, false); !loaded { + go func() { + defer func() { + val, _ := GlobalPostHandshakeRecordsLens.Load(key) + if _, ok := val.(bool); ok { + GlobalPostHandshakeRecordsLens.Store(key, []int{}) + } + }() + target, err := net.Dial("tcp", config.Dest) + if err != nil { return } - } - detectConn := &DetectConn{ - Conn: target, - Key: key, - } - uConn := utls.UClient(detectConn, &utls.Config{ - ServerName: sni, // needs new loopvar behaviour - }, utls.HelloChrome_Auto) - if err = uConn.Handshake(); err != nil { - return - } - io.Copy(io.Discard, uConn) - }() + if config.Xver == 1 || config.Xver == 2 { + if _, err = proxyproto.HeaderProxyFromAddrs(config.Xver, target.LocalAddr(), target.RemoteAddr()).WriteTo(target); err != nil { + return + } + } + detectConn := &DetectConn{ + Conn: target, + Key: key, + } + fingerprint := utls.HelloChrome_Auto + nextProtos := []string{"h2", "http/1.1"} + if alpn != 2 { + fingerprint = utls.HelloGolang + } + if alpn == 1 { + nextProtos = []string{"http/1.1"} + } + if alpn == 0 { + nextProtos = nil + } + uConn := utls.UClient(detectConn, &utls.Config{ + ServerName: sni, // needs new loopvar behaviour + NextProtos: nextProtos, + }, fingerprint) + if err = uConn.Handshake(); err != nil { + return + } + io.Copy(io.Discard, uConn) + }() + } } } } diff --git a/tls.go b/tls.go index adcb037..182736a 100644 --- a/tls.go +++ b/tls.go @@ -371,7 +371,15 @@ func Server(ctx context.Context, conn net.Conn, config *Config) (*Conn, error) { break } for { - if val, ok := GlobalPostHandshakeRecordsLens.Load(config.Dest + " " + hs.clientHello.serverName); ok { + key := config.Dest + " " + hs.clientHello.serverName + if len(hs.clientHello.alpnProtocols) == 0 { + key += " 0" + } else if hs.clientHello.alpnProtocols[0] == "h2" { + key += " 2" + } else { + key += " 1" + } + if val, ok := GlobalPostHandshakeRecordsLens.Load(key); ok { if postHandshakeRecordsLens, ok := val.([]int); ok { for _, length := range postHandshakeRecordsLens { plainText := make([]byte, length-16)