0
0
mirror of https://github.com/XTLS/REALITY.git synced 2025-08-22 06:28:35 +00:00

Three types of ALPN for post-handshake records detection & imitation

https://github.com/XTLS/Xray-core/issues/4778#issuecomment-3072047745
This commit is contained in:
RPRX 2025-07-15 05:57:25 +00:00 committed by GitHub
parent e62c4aed0d
commit 05a351a645
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 52 additions and 29 deletions

View File

@ -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)
}()
}
}
}
}

10
tls.go
View File

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