Support VLESS Encryption (native/random) + XTLS Vision + Any Transport like XHTTP (UDS or not) + TLS/REALITY

https://github.com/XTLS/Xray-core/pull/4952#issuecomment-3200720109
This commit is contained in:
RPRX
2025-08-19 13:20:27 +00:00
committed by GitHub
parent 49580705f6
commit 84835bec7d
6 changed files with 64 additions and 35 deletions

View File

@@ -525,27 +525,37 @@ func XtlsFilterTls(buffer buf.MultiBuffer, trafficState *TrafficState, ctx conte
}
}
// UnwrapRawConn support unwrap stats, tls, utls, reality, proxyproto, uds-wrapper conn and get raw tcp/uds conn from it
// UnwrapRawConn support unwrap encryption, stats, tls, utls, reality, proxyproto, uds-wrapper conn and get raw tcp/uds conn from it
func UnwrapRawConn(conn net.Conn) (net.Conn, stats.Counter, stats.Counter) {
var readCounter, writerCounter stats.Counter
if conn != nil {
statConn, ok := conn.(*stat.CounterConnection)
if ok {
isEncryption := false
if clientConn, ok := conn.(*encryption.ClientConn); ok {
conn = clientConn.Conn
isEncryption = true
}
if serverConn, ok := conn.(*encryption.ServerConn); ok {
conn = serverConn.Conn
isEncryption = true
}
if xorConn, ok := conn.(*encryption.XorConn); ok {
return xorConn, nil, nil // xorConn should not be penetrated
}
if statConn, ok := conn.(*stat.CounterConnection); ok {
conn = statConn.Connection
readCounter = statConn.ReadCounter
writerCounter = statConn.WriteCounter
}
if _, ok := conn.(*encryption.XorConn); ok {
return conn, readCounter, writerCounter
}
if xc, ok := conn.(*tls.Conn); ok {
conn = xc.NetConn()
} else if utlsConn, ok := conn.(*tls.UConn); ok {
conn = utlsConn.NetConn()
} else if realityConn, ok := conn.(*reality.Conn); ok {
conn = realityConn.NetConn()
} else if realityUConn, ok := conn.(*reality.UConn); ok {
conn = realityUConn.NetConn()
if !isEncryption { // avoids double penetration
if xc, ok := conn.(*tls.Conn); ok {
conn = xc.NetConn()
} else if utlsConn, ok := conn.(*tls.UConn); ok {
conn = utlsConn.NetConn()
} else if realityConn, ok := conn.(*reality.Conn); ok {
conn = realityConn.NetConn()
} else if realityUConn, ok := conn.(*reality.UConn); ok {
conn = realityUConn.NetConn()
}
}
if pc, ok := conn.(*proxyproto.Conn); ok {
conn = pc.Raw()
@@ -636,7 +646,7 @@ func CopyRawConnIfExist(ctx context.Context, readerConn net.Conn, writerConn net
}
func readV(ctx context.Context, reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, readCounter stats.Counter) error {
errors.LogInfo(ctx, "CopyRawConn readv")
errors.LogInfo(ctx, "CopyRawConn (maybe) readv")
if err := buf.Copy(reader, writer, buf.UpdateActivity(timer), buf.AddToStatCounter(readCounter)); err != nil {
return errors.New("failed to process response").Base(err)
}

View File

@@ -58,8 +58,8 @@ func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Dura
if err != nil {
return
}
hash256 := sha3.Sum256(nfsEKeyBytes)
copy(i.hash11[:], hash256[:])
hash32 := sha3.Sum256(nfsEKeyBytes)
copy(i.hash11[:], hash32[:])
if xor > 0 {
xorKey := sha3.Sum256(nfsEKeyBytes)
i.xorKey = xorKey[:]
@@ -68,7 +68,7 @@ func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Dura
return
}
func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
func (i *ClientInstance) Handshake(conn net.Conn) (*ClientConn, error) {
if i.nfsEKey == nil {
return nil, errors.New("uninitialized")
}

View File

@@ -55,8 +55,8 @@ func (i *ServerInstance) Init(nfsDKeySeed []byte, xor uint32, minutes time.Durat
if err != nil {
return
}
hash256 := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
copy(i.hash11[:], hash256[:])
hash32 := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
copy(i.hash11[:], hash32[:])
if xor > 0 {
xorKey := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
i.xorKey = xorKey[:]
@@ -92,7 +92,7 @@ func (i *ServerInstance) Close() (err error) {
return
}
func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
func (i *ServerInstance) Handshake(conn net.Conn) (*ServerConn, error) {
if i.nfsDKey == nil {
return nil, errors.New("uninitialized")
}

View File

@@ -49,6 +49,7 @@ func (c *XorConn) Write(b []byte) (int, error) { // whole one/two records
l += 10
if t == 0 {
c.out_after0 = true
c.out_header = make([]byte, 0, 5) // important
}
}
c.ctr.XORKeyStream(b[:l], b[:l]) // caller MUST discard b
@@ -77,7 +78,7 @@ func (c *XorConn) Write(b []byte) (int, error) { // whole one/two records
break
}
_, c.out_skip, _ = DecodeHeader(append(c.out_header, p[:need]...))
c.out_header = make([]byte, 0, 5) // DO NOT CHANGE
c.out_header = c.out_header[:0]
c.ctr.XORKeyStream(p[:need], p[:need])
p = p[need:]
}
@@ -116,6 +117,7 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes...
c.isHeader = false
if t == 0 {
c.in_after0 = true
c.in_header = make([]byte, 0, 5) // important
}
}
} else {
@@ -139,7 +141,7 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes...
}
c.peerCtr.XORKeyStream(p[:need], p[:need])
_, c.in_skip, _ = DecodeHeader(append(c.in_header, p[:need]...))
c.in_header = make([]byte, 0, 5) // DO NOT CHANGE
c.in_header = c.in_header[:0]
p = p[need:]
}
return n, err

View File

@@ -12,6 +12,7 @@ import (
"time"
"unsafe"
"github.com/pires/go-proxyproto"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors"
@@ -31,6 +32,7 @@ import (
"github.com/xtls/xray-core/proxy/vless"
"github.com/xtls/xray-core/proxy/vless/encoding"
"github.com/xtls/xray-core/proxy/vless/encryption"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls"
@@ -208,6 +210,11 @@ func (*Handler) Network() []net.Network {
// Process implements proxy.Inbound.Process().
func (h *Handler) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
iConn := connection
if statConn, ok := iConn.(*stat.CounterConnection); ok {
iConn = statConn.Connection
}
if h.decryption != nil {
var err error
connection, err = h.decryption.Handshake(connection)
@@ -216,11 +223,6 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
}
}
iConn := connection
if statConn, ok := iConn.(*stat.CounterConnection); ok {
iConn = statConn.Connection
}
sessionPolicy := h.policyManager.ForLevel(0)
if err := connection.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
return errors.New("unable to set read deadline").Base(err).AtWarning()
@@ -499,6 +501,13 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
case protocol.RequestCommandTCP:
if serverConn, ok := connection.(*encryption.ServerConn); ok {
peerCache = &serverConn.PeerCache
_, ok0 := serverConn.Conn.(*encryption.XorConn)
_, ok1 := iConn.(*proxyproto.Conn)
_, ok2 := iConn.(*net.TCPConn)
_, ok3 := iConn.(*internet.UnixConnWrapper)
if ok0 || (!ok1 && !ok2 && !ok3) {
inbound.CanSpliceCopy = 3 // xorConn/non-RAW can not use Linux Splice
}
break
}
var t reflect.Type

View File

@@ -9,6 +9,7 @@ import (
"time"
"unsafe"
"github.com/pires/go-proxyproto"
utls "github.com/refraction-networking/utls"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
@@ -103,6 +104,13 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
}
defer conn.Close()
iConn := conn
if statConn, ok := iConn.(*stat.CounterConnection); ok {
iConn = statConn.Connection
}
target := ob.Target
errors.LogInfo(ctx, "tunneling request to ", target, " via ", rec.Destination().NetAddr())
if h.encryption != nil {
var err error
conn, err = h.encryption.Handshake(conn)
@@ -111,13 +119,6 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
}
}
iConn := conn
if statConn, ok := iConn.(*stat.CounterConnection); ok {
iConn = statConn.Connection
}
target := ob.Target
errors.LogInfo(ctx, "tunneling request to ", target, " via ", rec.Destination().NetAddr())
command := protocol.RequestCommandTCP
if target.Network == net.Network_UDP {
command = protocol.RequestCommandUDP
@@ -161,6 +162,13 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
case protocol.RequestCommandTCP:
if clientConn, ok := conn.(*encryption.ClientConn); ok {
peerCache = &clientConn.PeerCache
_, ok0 := clientConn.Conn.(*encryption.XorConn)
_, ok1 := iConn.(*proxyproto.Conn)
_, ok2 := iConn.(*net.TCPConn)
_, ok3 := iConn.(*internet.UnixConnWrapper)
if ok0 || (!ok1 && !ok2 && !ok3) {
ob.CanSpliceCopy = 3 // xorConn/non-RAW can not use Linux Splice
}
break
}
var t reflect.Type