diff --git a/proxy/proxy.go b/proxy/proxy.go index 38f38b41..188cf4e9 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -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) } diff --git a/proxy/vless/encryption/client.go b/proxy/vless/encryption/client.go index 5092de5f..101d2052 100644 --- a/proxy/vless/encryption/client.go +++ b/proxy/vless/encryption/client.go @@ -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") } diff --git a/proxy/vless/encryption/server.go b/proxy/vless/encryption/server.go index c1d99611..a9ade3d4 100644 --- a/proxy/vless/encryption/server.go +++ b/proxy/vless/encryption/server.go @@ -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") } diff --git a/proxy/vless/encryption/xor.go b/proxy/vless/encryption/xor.go index 69ff1578..caad12bf 100644 --- a/proxy/vless/encryption/xor.go +++ b/proxy/vless/encryption/xor.go @@ -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 diff --git a/proxy/vless/inbound/inbound.go b/proxy/vless/inbound/inbound.go index 652dadd2..39a192b8 100644 --- a/proxy/vless/inbound/inbound.go +++ b/proxy/vless/inbound/inbound.go @@ -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 diff --git a/proxy/vless/outbound/outbound.go b/proxy/vless/outbound/outbound.go index dd777314..42b2a608 100644 --- a/proxy/vless/outbound/outbound.go +++ b/proxy/vless/outbound/outbound.go @@ -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