Add hash11(nfsEKeyBytes) to client/ticket hello; Support XTLS Vision for native appearance

https://github.com/XTLS/Xray-core/pull/4952#issuecomment-3194609798
This commit is contained in:
RPRX
2025-08-17 22:39:53 +00:00
committed by GitHub
parent bfe4820f2f
commit d1fb485212
6 changed files with 90 additions and 62 deletions

View File

@@ -56,15 +56,15 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
account.Id = u.String() account.Id = u.String()
switch account.Flow { switch account.Flow {
case "": case "", vless.XRV:
case vless.XRV:
if c.Decryption != "none" {
return nil, errors.New(`VLESS clients: "decryption" doesn't support "flow" yet`)
}
default: default:
return nil, errors.New(`VLESS clients: "flow" doesn't support "` + account.Flow + `" in this version`) return nil, errors.New(`VLESS clients: "flow" doesn't support "` + account.Flow + `" in this version`)
} }
if strings.Contains(c.Decryption, "xored") && account.Flow == vless.XRV {
return nil, errors.New(`VLESS clients: "xored" doesn't support "flow" yet`)
}
if account.Encryption != "" { if account.Encryption != "" {
return nil, errors.New(`VLESS clients: "encryption" should not in inbound settings`) return nil, errors.New(`VLESS clients: "encryption" should not in inbound settings`)
} }
@@ -215,8 +215,8 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) {
switch account.Flow { switch account.Flow {
case "": case "":
case vless.XRV, vless.XRV + "-udp443": case vless.XRV, vless.XRV + "-udp443":
if account.Encryption != "none" { if strings.Contains(account.Encryption, "xored") {
return nil, errors.New(`VLESS users: "encryption" doesn't support "flow" yet`) return nil, errors.New(`VLESS users: "xored" doesn't support "flow" yet`)
} }
default: default:
return nil, errors.New(`VLESS users: "flow" doesn't support "` + account.Flow + `" in this version`) return nil, errors.New(`VLESS users: "flow" doesn't support "` + account.Flow + `" in this version`)

View File

@@ -172,7 +172,7 @@ func DecodeResponseHeader(reader io.Reader, request *protocol.RequestHeader) (*A
} }
// XtlsRead filter and read xtls protocol // XtlsRead filter and read xtls protocol
func XtlsRead(reader buf.Reader, writer buf.Writer, timer *signal.ActivityTimer, conn net.Conn, input *bytes.Reader, rawInput *bytes.Buffer, trafficState *proxy.TrafficState, ob *session.Outbound, isUplink bool, ctx context.Context) error { func XtlsRead(reader buf.Reader, writer buf.Writer, timer *signal.ActivityTimer, conn net.Conn, peerCache *[]byte, input *bytes.Reader, rawInput *bytes.Buffer, trafficState *proxy.TrafficState, ob *session.Outbound, isUplink bool, ctx context.Context) error {
err := func() error { err := func() error {
for { for {
if isUplink && trafficState.Inbound.UplinkReaderDirectCopy || !isUplink && trafficState.Outbound.DownlinkReaderDirectCopy { if isUplink && trafficState.Inbound.UplinkReaderDirectCopy || !isUplink && trafficState.Outbound.DownlinkReaderDirectCopy {
@@ -194,15 +194,21 @@ func XtlsRead(reader buf.Reader, writer buf.Writer, timer *signal.ActivityTimer,
if !buffer.IsEmpty() { if !buffer.IsEmpty() {
timer.Update() timer.Update()
if isUplink && trafficState.Inbound.UplinkReaderDirectCopy || !isUplink && trafficState.Outbound.DownlinkReaderDirectCopy { if isUplink && trafficState.Inbound.UplinkReaderDirectCopy || !isUplink && trafficState.Outbound.DownlinkReaderDirectCopy {
// XTLS Vision processes struct TLS Conn's input and rawInput // XTLS Vision processes struct Encryption Conn's peerCache or TLS Conn's input and rawInput
if inputBuffer, err := buf.ReadFrom(input); err == nil { if peerCache != nil {
if !inputBuffer.IsEmpty() { if len(*peerCache) != 0 {
buffer, _ = buf.MergeMulti(buffer, inputBuffer) buffer = buf.MergeBytes(buffer, *peerCache)
} }
} } else {
if rawInputBuffer, err := buf.ReadFrom(rawInput); err == nil { if inputBuffer, err := buf.ReadFrom(input); err == nil {
if !rawInputBuffer.IsEmpty() { if !inputBuffer.IsEmpty() {
buffer, _ = buf.MergeMulti(buffer, rawInputBuffer) buffer, _ = buf.MergeMulti(buffer, inputBuffer)
}
}
if rawInputBuffer, err := buf.ReadFrom(rawInput); err == nil {
if !rawInputBuffer.IsEmpty() {
buffer, _ = buf.MergeMulti(buffer, rawInputBuffer)
}
} }
} }
} }

View File

@@ -28,6 +28,7 @@ func init() {
type ClientInstance struct { type ClientInstance struct {
sync.RWMutex sync.RWMutex
nfsEKey *mlkem.EncapsulationKey768 nfsEKey *mlkem.EncapsulationKey768
hash11 [11]byte // no more capacity
xorKey []byte xorKey []byte
minutes time.Duration minutes time.Duration
expire time.Time expire time.Time
@@ -45,7 +46,7 @@ type ClientConn struct {
nonce []byte nonce []byte
peerAead cipher.AEAD peerAead cipher.AEAD
peerNonce []byte peerNonce []byte
peerCache []byte PeerCache []byte
} }
func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Duration) (err error) { func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Duration) (err error) {
@@ -57,6 +58,8 @@ func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Dura
if err != nil { if err != nil {
return return
} }
hash256 := sha256.Sum256(nfsEKeyBytes)
copy(i.hash11[:], hash256[:])
if xor > 0 { if xor > 0 {
xorKey := sha256.Sum256(nfsEKeyBytes) xorKey := sha256.Sum256(nfsEKeyBytes)
i.xorKey = xorKey[:] i.xorKey = xorKey[:]
@@ -93,13 +96,14 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
nfsKey, encapsulatedNfsKey := i.nfsEKey.Encapsulate() nfsKey, encapsulatedNfsKey := i.nfsEKey.Encapsulate()
paddingLen := crypto.RandBetween(100, 1000) paddingLen := crypto.RandBetween(100, 1000)
clientHello := make([]byte, 5+1+1184+1088+5+paddingLen) clientHello := make([]byte, 5+11+1+1184+1088+5+paddingLen)
EncodeHeader(clientHello, 1, 1+1184+1088) EncodeHeader(clientHello, 1, 11+1+1184+1088)
clientHello[5] = ClientCipher copy(clientHello[5:], i.hash11[:])
copy(clientHello[5+1:], pfsEKeyBytes) clientHello[5+11] = ClientCipher
copy(clientHello[5+1+1184:], encapsulatedNfsKey) copy(clientHello[5+11+1:], pfsEKeyBytes)
EncodeHeader(clientHello[5+1+1184+1088:], 23, int(paddingLen)) copy(clientHello[5+11+1+1184:], encapsulatedNfsKey)
rand.Read(clientHello[5+1+1184+1088+5:]) EncodeHeader(clientHello[5+11+1+1184+1088:], 23, int(paddingLen))
rand.Read(clientHello[5+11+1+1184+1088+5:])
if _, err := c.Conn.Write(clientHello); err != nil { if _, err := c.Conn.Write(clientHello); err != nil {
return nil, err return nil, err
@@ -122,7 +126,7 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
return nil, err return nil, err
} }
encapsulatedPfsKey := peerServerHello[:1088] encapsulatedPfsKey := peerServerHello[:1088]
c.ticket = peerServerHello[1088:] c.ticket = append(i.hash11[:], peerServerHello[1088:]...)
pfsKey, err := pfsDKey.Decapsulate(encapsulatedPfsKey) pfsKey, err := pfsDKey.Decapsulate(encapsulatedPfsKey)
if err != nil { if err != nil {
@@ -130,8 +134,7 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
} }
c.baseKey = append(pfsKey, nfsKey...) c.baseKey = append(pfsKey, nfsKey...)
nonce := [12]byte{ClientCipher} VLESS, _ := NewAead(ClientCipher, c.baseKey, encapsulatedPfsKey, encapsulatedNfsKey).Open(nil, append(i.hash11[:], ClientCipher), c.ticket[11:], pfsEKeyBytes)
VLESS, _ := NewAead(ClientCipher, c.baseKey, encapsulatedPfsKey, encapsulatedNfsKey).Open(nil, nonce[:], c.ticket, pfsEKeyBytes)
if !bytes.Equal(VLESS, []byte("VLESS")) { if !bytes.Equal(VLESS, []byte("VLESS")) {
return nil, errors.New("invalid server").AtError() return nil, errors.New("invalid server").AtError()
} }
@@ -159,16 +162,16 @@ func (c *ClientConn) Write(b []byte) (int, error) {
} }
n += len(b) n += len(b)
if c.aead == nil { if c.aead == nil {
data = make([]byte, 5+32+32+5+len(b)+16)
EncodeHeader(data, 0, 32+32)
copy(data[5:], c.ticket)
c.random = make([]byte, 32) c.random = make([]byte, 32)
rand.Read(c.random) rand.Read(c.random)
copy(data[5+32:], c.random)
EncodeHeader(data[5+32+32:], 23, len(b)+16)
c.aead = NewAead(ClientCipher, c.baseKey, c.random, c.ticket) c.aead = NewAead(ClientCipher, c.baseKey, c.random, c.ticket)
c.nonce = make([]byte, 12) c.nonce = make([]byte, 12)
data = make([]byte, 5+21+32+5+len(b)+16) c.aead.Seal(data[:5+32+32+5], c.nonce, b, data[5+32+32:5+32+32+5])
EncodeHeader(data, 0, 21+32)
copy(data[5:], c.ticket)
copy(data[5+21:], c.random)
EncodeHeader(data[5+21+32:], 23, len(b)+16)
c.aead.Seal(data[:5+21+32+5], c.nonce, b, data[5+21+32:5+21+32+5])
} else { } else {
data = make([]byte, 5+len(b)+16) data = make([]byte, 5+len(b)+16)
EncodeHeader(data, 23, len(b)+16) EncodeHeader(data, 23, len(b)+16)
@@ -218,9 +221,9 @@ func (c *ClientConn) Read(b []byte) (int, error) {
c.peerAead = NewAead(ClientCipher, c.baseKey, peerRandomHello, c.random) c.peerAead = NewAead(ClientCipher, c.baseKey, peerRandomHello, c.random)
c.peerNonce = make([]byte, 12) c.peerNonce = make([]byte, 12)
} }
if len(c.peerCache) != 0 { if len(c.PeerCache) != 0 {
n := copy(b, c.peerCache) n := copy(b, c.PeerCache)
c.peerCache = c.peerCache[n:] c.PeerCache = c.PeerCache[n:]
return n, nil return n, nil
} }
h, t, l, err := ReadAndDecodeHeader(c.Conn) // l: 17~17000 h, t, l, err := ReadAndDecodeHeader(c.Conn) // l: 17~17000
@@ -251,7 +254,7 @@ func (c *ClientConn) Read(b []byte) (int, error) {
return 0, err return 0, err
} }
if len(dst) > len(b) { if len(dst) > len(b) {
c.peerCache = dst[copy(b, dst):] c.PeerCache = dst[copy(b, dst):]
dst = b // for len(dst) dst = b // for len(dst)
} }
return len(dst), nil return len(dst), nil

View File

@@ -6,6 +6,7 @@ import (
"crypto/mlkem" "crypto/mlkem"
"crypto/rand" "crypto/rand"
"crypto/sha256" "crypto/sha256"
"fmt"
"io" "io"
"net" "net"
"sync" "sync"
@@ -25,9 +26,10 @@ type ServerSession struct {
type ServerInstance struct { type ServerInstance struct {
sync.RWMutex sync.RWMutex
nfsDKey *mlkem.DecapsulationKey768 nfsDKey *mlkem.DecapsulationKey768
hash11 [11]byte // no more capacity
xorKey []byte xorKey []byte
minutes time.Duration minutes time.Duration
sessions map[[21]byte]*ServerSession sessions map[[32]byte]*ServerSession
closed bool closed bool
} }
@@ -39,7 +41,7 @@ type ServerConn struct {
peerRandom []byte peerRandom []byte
peerAead cipher.AEAD peerAead cipher.AEAD
peerNonce []byte peerNonce []byte
peerCache []byte PeerCache []byte
aead cipher.AEAD aead cipher.AEAD
nonce []byte nonce []byte
} }
@@ -53,13 +55,15 @@ func (i *ServerInstance) Init(nfsDKeySeed []byte, xor uint32, minutes time.Durat
if err != nil { if err != nil {
return return
} }
hash256 := sha256.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
copy(i.hash11[:], hash256[:])
if xor > 0 { if xor > 0 {
xorKey := sha256.Sum256(i.nfsDKey.EncapsulationKey().Bytes()) xorKey := sha256.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
i.xorKey = xorKey[:] i.xorKey = xorKey[:]
} }
if minutes > 0 { if minutes > 0 {
i.minutes = minutes i.minutes = minutes
i.sessions = make(map[[21]byte]*ServerSession) i.sessions = make(map[[32]byte]*ServerSession)
go func() { go func() {
for { for {
time.Sleep(time.Minute) time.Sleep(time.Minute)
@@ -106,15 +110,18 @@ func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
if i.minutes == 0 { if i.minutes == 0 {
return nil, errors.New("0-RTT is not allowed") return nil, errors.New("0-RTT is not allowed")
} }
peerTicketHello := make([]byte, 21+32) peerTicketHello := make([]byte, 32+32)
if l != len(peerTicketHello) { if l != len(peerTicketHello) {
return nil, errors.New("unexpected length ", l, " for ticket hello") return nil, errors.New("unexpected length ", l, " for ticket hello")
} }
if _, err := io.ReadFull(c.Conn, peerTicketHello); err != nil { if _, err := io.ReadFull(c.Conn, peerTicketHello); err != nil {
return nil, err return nil, err
} }
if !bytes.Equal(peerTicketHello[:11], i.hash11[:]) {
return nil, errors.New("unexpected hash11: ", fmt.Sprintf("%v", peerTicketHello[:11]))
}
i.RLock() i.RLock()
s := i.sessions[[21]byte(peerTicketHello)] s := i.sessions[[32]byte(peerTicketHello)]
i.RUnlock() i.RUnlock()
if s == nil { if s == nil {
noises := make([]byte, crypto.RandBetween(100, 1000)) noises := make([]byte, crypto.RandBetween(100, 1000))
@@ -126,26 +133,29 @@ func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
c.Conn.Write(noises) // make client do new handshake c.Conn.Write(noises) // make client do new handshake
return nil, errors.New("expired ticket") return nil, errors.New("expired ticket")
} }
if _, replay := s.randoms.LoadOrStore([32]byte(peerTicketHello[21:]), true); replay { if _, replay := s.randoms.LoadOrStore([32]byte(peerTicketHello[32:]), true); replay {
return nil, errors.New("replay detected") return nil, errors.New("replay detected")
} }
c.cipher = s.cipher c.cipher = s.cipher
c.baseKey = s.baseKey c.baseKey = s.baseKey
c.ticket = peerTicketHello[:21] c.ticket = peerTicketHello[:32]
c.peerRandom = peerTicketHello[21:] c.peerRandom = peerTicketHello[32:]
return c, nil return c, nil
} }
peerClientHello := make([]byte, 1+1184+1088) peerClientHello := make([]byte, 11+1+1184+1088)
if l != len(peerClientHello) { if l != len(peerClientHello) {
return nil, errors.New("unexpected length ", l, " for client hello") return nil, errors.New("unexpected length ", l, " for client hello")
} }
if _, err := io.ReadFull(c.Conn, peerClientHello); err != nil { if _, err := io.ReadFull(c.Conn, peerClientHello); err != nil {
return nil, err return nil, err
} }
c.cipher = peerClientHello[0] if !bytes.Equal(peerClientHello[:11], i.hash11[:]) {
pfsEKeyBytes := peerClientHello[1:1185] return nil, errors.New("unexpected hash11: ", fmt.Sprintf("%v", peerClientHello[:11]))
encapsulatedNfsKey := peerClientHello[1185:2273] }
c.cipher = peerClientHello[11]
pfsEKeyBytes := peerClientHello[11+1 : 11+1+1184]
encapsulatedNfsKey := peerClientHello[11+1+1184:]
pfsEKey, err := mlkem.NewEncapsulationKey768(pfsEKeyBytes) pfsEKey, err := mlkem.NewEncapsulationKey768(pfsEKeyBytes)
if err != nil { if err != nil {
@@ -158,15 +168,14 @@ func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
pfsKey, encapsulatedPfsKey := pfsEKey.Encapsulate() pfsKey, encapsulatedPfsKey := pfsEKey.Encapsulate()
c.baseKey = append(pfsKey, nfsKey...) c.baseKey = append(pfsKey, nfsKey...)
nonce := [12]byte{c.cipher} c.ticket = append(i.hash11[:], NewAead(c.cipher, c.baseKey, encapsulatedPfsKey, encapsulatedNfsKey).Seal(nil, peerClientHello[:12], []byte("VLESS"), pfsEKeyBytes)...)
c.ticket = NewAead(c.cipher, c.baseKey, encapsulatedPfsKey, encapsulatedNfsKey).Seal(nil, nonce[:], []byte("VLESS"), pfsEKeyBytes)
paddingLen := crypto.RandBetween(100, 1000) paddingLen := crypto.RandBetween(100, 1000)
serverHello := make([]byte, 5+1088+21+5+paddingLen) serverHello := make([]byte, 5+1088+21+5+paddingLen)
EncodeHeader(serverHello, 1, 1088+21) EncodeHeader(serverHello, 1, 1088+21)
copy(serverHello[5:], encapsulatedPfsKey) copy(serverHello[5:], encapsulatedPfsKey)
copy(serverHello[5+1088:], c.ticket) copy(serverHello[5+1088:], c.ticket[11:])
EncodeHeader(serverHello[5+1088+21:], 23, int(paddingLen)) EncodeHeader(serverHello[5+1088+21:], 23, int(paddingLen))
rand.Read(serverHello[5+1088+21+5:]) rand.Read(serverHello[5+1088+21+5:])
@@ -177,7 +186,7 @@ func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
if i.minutes > 0 { if i.minutes > 0 {
i.Lock() i.Lock()
i.sessions[[21]byte(c.ticket)] = &ServerSession{ i.sessions[[32]byte(c.ticket)] = &ServerSession{
expire: time.Now().Add(i.minutes), expire: time.Now().Add(i.minutes),
cipher: c.cipher, cipher: c.cipher,
baseKey: c.baseKey, baseKey: c.baseKey,
@@ -201,24 +210,24 @@ func (c *ServerConn) Read(b []byte) (int, error) {
if t != 0 { if t != 0 {
return 0, errors.New("unexpected type ", t, ", expect ticket hello") return 0, errors.New("unexpected type ", t, ", expect ticket hello")
} }
peerTicketHello := make([]byte, 21+32) peerTicketHello := make([]byte, 32+32)
if l != len(peerTicketHello) { if l != len(peerTicketHello) {
return 0, errors.New("unexpected length ", l, " for ticket hello") return 0, errors.New("unexpected length ", l, " for ticket hello")
} }
if _, err := io.ReadFull(c.Conn, peerTicketHello); err != nil { if _, err := io.ReadFull(c.Conn, peerTicketHello); err != nil {
return 0, err return 0, err
} }
if !bytes.Equal(peerTicketHello[:21], c.ticket) { if !bytes.Equal(peerTicketHello[:32], c.ticket) {
return 0, errors.New("naughty boy") return 0, errors.New("naughty boy")
} }
c.peerRandom = peerTicketHello[21:] c.peerRandom = peerTicketHello[32:]
} }
c.peerAead = NewAead(c.cipher, c.baseKey, c.peerRandom, c.ticket) c.peerAead = NewAead(c.cipher, c.baseKey, c.peerRandom, c.ticket)
c.peerNonce = make([]byte, 12) c.peerNonce = make([]byte, 12)
} }
if len(c.peerCache) != 0 { if len(c.PeerCache) != 0 {
n := copy(b, c.peerCache) n := copy(b, c.PeerCache)
c.peerCache = c.peerCache[n:] c.PeerCache = c.PeerCache[n:]
return n, nil return n, nil
} }
h, t, l, err := ReadAndDecodeHeader(c.Conn) // l: 17~17000 h, t, l, err := ReadAndDecodeHeader(c.Conn) // l: 17~17000
@@ -249,7 +258,7 @@ func (c *ServerConn) Read(b []byte) (int, error) {
return 0, err return 0, err
} }
if len(dst) > len(b) { if len(dst) > len(b) {
c.peerCache = dst[copy(b, dst):] c.PeerCache = dst[copy(b, dst):]
dst = b // for len(dst) dst = b // for len(dst)
} }
return len(dst), nil return len(dst), nil

View File

@@ -484,6 +484,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
// Flow: requestAddons.Flow, // Flow: requestAddons.Flow,
} }
var peerCache *[]byte
var input *bytes.Reader var input *bytes.Reader
var rawInput *bytes.Buffer var rawInput *bytes.Buffer
switch requestAddons.Flow { switch requestAddons.Flow {
@@ -496,6 +497,10 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
case protocol.RequestCommandMux: case protocol.RequestCommandMux:
fallthrough // we will break Mux connections that contain TCP requests fallthrough // we will break Mux connections that contain TCP requests
case protocol.RequestCommandTCP: case protocol.RequestCommandTCP:
if serverConn, ok := connection.(*encryption.ServerConn); ok {
peerCache = &serverConn.PeerCache
break
}
var t reflect.Type var t reflect.Type
var p uintptr var p uintptr
if tlsConn, ok := iConn.(*tls.Conn); ok { if tlsConn, ok := iConn.(*tls.Conn); ok {
@@ -564,7 +569,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
if requestAddons.Flow == vless.XRV { if requestAddons.Flow == vless.XRV {
ctx1 := session.ContextWithInbound(ctx, nil) // TODO enable splice ctx1 := session.ContextWithInbound(ctx, nil) // TODO enable splice
clientReader = proxy.NewVisionReader(clientReader, trafficState, true, ctx1) clientReader = proxy.NewVisionReader(clientReader, trafficState, true, ctx1)
err = encoding.XtlsRead(clientReader, serverWriter, timer, connection, input, rawInput, trafficState, nil, true, ctx1) err = encoding.XtlsRead(clientReader, serverWriter, timer, connection, peerCache, input, rawInput, trafficState, nil, true, ctx1)
} else { } else {
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBuffer // from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBuffer
err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer)) err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))

View File

@@ -140,6 +140,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
Flow: account.Flow, Flow: account.Flow,
} }
var peerCache *[]byte
var input *bytes.Reader var input *bytes.Reader
var rawInput *bytes.Buffer var rawInput *bytes.Buffer
allowUDP443 := false allowUDP443 := false
@@ -158,6 +159,10 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
case protocol.RequestCommandMux: case protocol.RequestCommandMux:
fallthrough // let server break Mux connections that contain TCP requests fallthrough // let server break Mux connections that contain TCP requests
case protocol.RequestCommandTCP: case protocol.RequestCommandTCP:
if clientConn, ok := conn.(*encryption.ClientConn); ok {
peerCache = &clientConn.PeerCache
break
}
var t reflect.Type var t reflect.Type
var p uintptr var p uintptr
if tlsConn, ok := iConn.(*tls.Conn); ok { if tlsConn, ok := iConn.(*tls.Conn); ok {
@@ -292,7 +297,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
} }
if requestAddons.Flow == vless.XRV { if requestAddons.Flow == vless.XRV {
err = encoding.XtlsRead(serverReader, clientWriter, timer, conn, input, rawInput, trafficState, ob, false, ctx) err = encoding.XtlsRead(serverReader, clientWriter, timer, conn, peerCache, input, rawInput, trafficState, ob, false, ctx)
} else { } else {
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBuffer // from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBuffer
err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer)) err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer))