Skip to content

Commit 33bd460

Browse files
authored
Support VLESS Encryption (native/random) + XTLS Vision + Any Transport like XHTTP (UDS or not) + TLS/REALITY
#4952 (comment)
1 parent 4958070 commit 33bd460

File tree

6 files changed

+64
-35
lines changed

6 files changed

+64
-35
lines changed

proxy/proxy.go

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -525,27 +525,37 @@ func XtlsFilterTls(buffer buf.MultiBuffer, trafficState *TrafficState, ctx conte
525525
}
526526
}
527527

528-
// UnwrapRawConn support unwrap stats, tls, utls, reality, proxyproto, uds-wrapper conn and get raw tcp/uds conn from it
528+
// UnwrapRawConn support unwrap stats, encryption, tls, utls, reality, proxyproto, uds-wrapper conn and get raw tcp/uds conn from it
529529
func UnwrapRawConn(conn net.Conn) (net.Conn, stats.Counter, stats.Counter) {
530530
var readCounter, writerCounter stats.Counter
531531
if conn != nil {
532-
statConn, ok := conn.(*stat.CounterConnection)
533-
if ok {
532+
isEncryption := false
533+
if clientConn, ok := conn.(*encryption.ClientConn); ok {
534+
conn = clientConn.Conn
535+
isEncryption = true
536+
}
537+
if serverConn, ok := conn.(*encryption.ServerConn); ok {
538+
conn = serverConn.Conn
539+
isEncryption = true
540+
}
541+
if xorConn, ok := conn.(*encryption.XorConn); ok {
542+
return xorConn, nil, nil // xorConn should not be penetrated
543+
}
544+
if statConn, ok := conn.(*stat.CounterConnection); ok {
534545
conn = statConn.Connection
535546
readCounter = statConn.ReadCounter
536547
writerCounter = statConn.WriteCounter
537548
}
538-
if _, ok := conn.(*encryption.XorConn); ok {
539-
return conn, readCounter, writerCounter
540-
}
541-
if xc, ok := conn.(*tls.Conn); ok {
542-
conn = xc.NetConn()
543-
} else if utlsConn, ok := conn.(*tls.UConn); ok {
544-
conn = utlsConn.NetConn()
545-
} else if realityConn, ok := conn.(*reality.Conn); ok {
546-
conn = realityConn.NetConn()
547-
} else if realityUConn, ok := conn.(*reality.UConn); ok {
548-
conn = realityUConn.NetConn()
549+
if !isEncryption { // avoids double penetration
550+
if xc, ok := conn.(*tls.Conn); ok {
551+
conn = xc.NetConn()
552+
} else if utlsConn, ok := conn.(*tls.UConn); ok {
553+
conn = utlsConn.NetConn()
554+
} else if realityConn, ok := conn.(*reality.Conn); ok {
555+
conn = realityConn.NetConn()
556+
} else if realityUConn, ok := conn.(*reality.UConn); ok {
557+
conn = realityUConn.NetConn()
558+
}
549559
}
550560
if pc, ok := conn.(*proxyproto.Conn); ok {
551561
conn = pc.Raw()
@@ -636,7 +646,7 @@ func CopyRawConnIfExist(ctx context.Context, readerConn net.Conn, writerConn net
636646
}
637647

638648
func readV(ctx context.Context, reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, readCounter stats.Counter) error {
639-
errors.LogInfo(ctx, "CopyRawConn readv")
649+
errors.LogInfo(ctx, "CopyRawConn (maybe) readv")
640650
if err := buf.Copy(reader, writer, buf.UpdateActivity(timer), buf.AddToStatCounter(readCounter)); err != nil {
641651
return errors.New("failed to process response").Base(err)
642652
}

proxy/vless/encryption/client.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Dura
5858
if err != nil {
5959
return
6060
}
61-
hash256 := sha3.Sum256(nfsEKeyBytes)
62-
copy(i.hash11[:], hash256[:])
61+
hash32 := sha3.Sum256(nfsEKeyBytes)
62+
copy(i.hash11[:], hash32[:])
6363
if xor > 0 {
6464
xorKey := sha3.Sum256(nfsEKeyBytes)
6565
i.xorKey = xorKey[:]
@@ -68,7 +68,7 @@ func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Dura
6868
return
6969
}
7070

71-
func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
71+
func (i *ClientInstance) Handshake(conn net.Conn) (*ClientConn, error) {
7272
if i.nfsEKey == nil {
7373
return nil, errors.New("uninitialized")
7474
}

proxy/vless/encryption/server.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ func (i *ServerInstance) Init(nfsDKeySeed []byte, xor uint32, minutes time.Durat
5555
if err != nil {
5656
return
5757
}
58-
hash256 := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
59-
copy(i.hash11[:], hash256[:])
58+
hash32 := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
59+
copy(i.hash11[:], hash32[:])
6060
if xor > 0 {
6161
xorKey := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
6262
i.xorKey = xorKey[:]
@@ -92,7 +92,7 @@ func (i *ServerInstance) Close() (err error) {
9292
return
9393
}
9494

95-
func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
95+
func (i *ServerInstance) Handshake(conn net.Conn) (*ServerConn, error) {
9696
if i.nfsDKey == nil {
9797
return nil, errors.New("uninitialized")
9898
}

proxy/vless/encryption/xor.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func (c *XorConn) Write(b []byte) (int, error) { // whole one/two records
4949
l += 10
5050
if t == 0 {
5151
c.out_after0 = true
52+
c.out_header = make([]byte, 0, 5) // important
5253
}
5354
}
5455
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
7778
break
7879
}
7980
_, c.out_skip, _ = DecodeHeader(append(c.out_header, p[:need]...))
80-
c.out_header = make([]byte, 0, 5) // DO NOT CHANGE
81+
c.out_header = c.out_header[:0]
8182
c.ctr.XORKeyStream(p[:need], p[:need])
8283
p = p[need:]
8384
}
@@ -116,6 +117,7 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes...
116117
c.isHeader = false
117118
if t == 0 {
118119
c.in_after0 = true
120+
c.in_header = make([]byte, 0, 5) // important
119121
}
120122
}
121123
} else {
@@ -139,7 +141,7 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes...
139141
}
140142
c.peerCtr.XORKeyStream(p[:need], p[:need])
141143
_, c.in_skip, _ = DecodeHeader(append(c.in_header, p[:need]...))
142-
c.in_header = make([]byte, 0, 5) // DO NOT CHANGE
144+
c.in_header = c.in_header[:0]
143145
p = p[need:]
144146
}
145147
return n, err

proxy/vless/inbound/inbound.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"time"
1313
"unsafe"
1414

15+
"github.com/pires/go-proxyproto"
1516
"github.com/xtls/xray-core/common"
1617
"github.com/xtls/xray-core/common/buf"
1718
"github.com/xtls/xray-core/common/errors"
@@ -31,6 +32,7 @@ import (
3132
"github.com/xtls/xray-core/proxy/vless"
3233
"github.com/xtls/xray-core/proxy/vless/encoding"
3334
"github.com/xtls/xray-core/proxy/vless/encryption"
35+
"github.com/xtls/xray-core/transport/internet"
3436
"github.com/xtls/xray-core/transport/internet/reality"
3537
"github.com/xtls/xray-core/transport/internet/stat"
3638
"github.com/xtls/xray-core/transport/internet/tls"
@@ -208,6 +210,11 @@ func (*Handler) Network() []net.Network {
208210

209211
// Process implements proxy.Inbound.Process().
210212
func (h *Handler) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
213+
iConn := connection
214+
if statConn, ok := iConn.(*stat.CounterConnection); ok {
215+
iConn = statConn.Connection
216+
}
217+
211218
if h.decryption != nil {
212219
var err error
213220
connection, err = h.decryption.Handshake(connection)
@@ -216,11 +223,6 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
216223
}
217224
}
218225

219-
iConn := connection
220-
if statConn, ok := iConn.(*stat.CounterConnection); ok {
221-
iConn = statConn.Connection
222-
}
223-
224226
sessionPolicy := h.policyManager.ForLevel(0)
225227
if err := connection.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
226228
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
499501
case protocol.RequestCommandTCP:
500502
if serverConn, ok := connection.(*encryption.ServerConn); ok {
501503
peerCache = &serverConn.PeerCache
504+
_, ok0 := serverConn.Conn.(*encryption.XorConn)
505+
_, ok1 := iConn.(*proxyproto.Conn)
506+
_, ok2 := iConn.(*net.TCPConn)
507+
_, ok3 := iConn.(*internet.UnixConnWrapper)
508+
if ok0 || (!ok1 && !ok2 && !ok3) {
509+
inbound.CanSpliceCopy = 3 // xorConn/non-RAW can not use Linux Splice
510+
}
502511
break
503512
}
504513
var t reflect.Type

proxy/vless/outbound/outbound.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"time"
1010
"unsafe"
1111

12+
"github.com/pires/go-proxyproto"
1213
utls "github.com/refraction-networking/utls"
1314
"github.com/xtls/xray-core/common"
1415
"github.com/xtls/xray-core/common/buf"
@@ -103,6 +104,13 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
103104
}
104105
defer conn.Close()
105106

107+
iConn := conn
108+
if statConn, ok := iConn.(*stat.CounterConnection); ok {
109+
iConn = statConn.Connection
110+
}
111+
target := ob.Target
112+
errors.LogInfo(ctx, "tunneling request to ", target, " via ", rec.Destination().NetAddr())
113+
106114
if h.encryption != nil {
107115
var err error
108116
conn, err = h.encryption.Handshake(conn)
@@ -111,13 +119,6 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
111119
}
112120
}
113121

114-
iConn := conn
115-
if statConn, ok := iConn.(*stat.CounterConnection); ok {
116-
iConn = statConn.Connection
117-
}
118-
target := ob.Target
119-
errors.LogInfo(ctx, "tunneling request to ", target, " via ", rec.Destination().NetAddr())
120-
121122
command := protocol.RequestCommandTCP
122123
if target.Network == net.Network_UDP {
123124
command = protocol.RequestCommandUDP
@@ -161,6 +162,13 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
161162
case protocol.RequestCommandTCP:
162163
if clientConn, ok := conn.(*encryption.ClientConn); ok {
163164
peerCache = &clientConn.PeerCache
165+
_, ok0 := clientConn.Conn.(*encryption.XorConn)
166+
_, ok1 := iConn.(*proxyproto.Conn)
167+
_, ok2 := iConn.(*net.TCPConn)
168+
_, ok3 := iConn.(*internet.UnixConnWrapper)
169+
if ok0 || (!ok1 && !ok2 && !ok3) {
170+
ob.CanSpliceCopy = 3 // xorConn/non-RAW can not use Linux Splice
171+
}
164172
break
165173
}
166174
var t reflect.Type

0 commit comments

Comments
 (0)