Compare commits

...
2 Commits
Author SHA1 Message Date
RPRXandGitHub ab507b7a0d Update proxy.go 2026-10-17 03:29:08 +00:00
Fangliding 969e5b6c11 fix new tls lib issue 2026-10-16 16:03:44 +08:00
4 changed files with 43 additions and 38 deletions
+9 -6
View File
@@ -180,14 +180,14 @@ type VisionReader struct {
isUplink bool isUplink bool
conn net.Conn conn net.Conn
input *bytes.Reader input *bytes.Reader
rawInput *bytes.Buffer rawInput **bytes.Buffer
ob *session.Outbound ob *session.Outbound
// internal // internal
directReadCounter stats.Counter directReadCounter stats.Counter
} }
func NewVisionReader(reader buf.Reader, trafficState *TrafficState, isUplink bool, ctx context.Context, conn net.Conn, input *bytes.Reader, rawInput *bytes.Buffer, ob *session.Outbound) *VisionReader { func NewVisionReader(reader buf.Reader, trafficState *TrafficState, isUplink bool, ctx context.Context, conn net.Conn, input *bytes.Reader, rawInput **bytes.Buffer, ob *session.Outbound) *VisionReader {
return &VisionReader{ return &VisionReader{
Reader: reader, Reader: reader,
trafficState: trafficState, trafficState: trafficState,
@@ -261,12 +261,15 @@ func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
if inputBuffer, err := buf.ReadFrom(w.input); err == nil && !inputBuffer.IsEmpty() { if inputBuffer, err := buf.ReadFrom(w.input); err == nil && !inputBuffer.IsEmpty() {
buffer, _ = buf.MergeMulti(buffer, inputBuffer) buffer, _ = buf.MergeMulti(buffer, inputBuffer)
} }
if rawInputBuffer, err := buf.ReadFrom(w.rawInput); err == nil && !rawInputBuffer.IsEmpty() {
buffer, _ = buf.MergeMulti(buffer, rawInputBuffer)
}
*w.input = bytes.Reader{} // release memory *w.input = bytes.Reader{} // release memory
w.input = nil w.input = nil
*w.rawInput = bytes.Buffer{} // release memory
if raw := *w.rawInput; raw != nil {
if rawInputBuffer, err := buf.ReadFrom(raw); err == nil && !rawInputBuffer.IsEmpty() {
buffer, _ = buf.MergeMulti(buffer, rawInputBuffer)
}
// *raw = bytes.Buffer{} // may not be suitable for Go 1.27.3+
}
w.rawInput = nil w.rawInput = nil
if inbound := session.InboundFromContext(w.ctx); inbound != nil && inbound.Conn != nil { if inbound := session.InboundFromContext(w.ctx); inbound != nil && inbound.Conn != nil {
+6 -15
View File
@@ -6,11 +6,9 @@ import (
gotls "crypto/tls" gotls "crypto/tls"
"encoding/base64" "encoding/base64"
"io" "io"
"reflect"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"unsafe"
"github.com/xtls/xray-core/app/dispatcher" "github.com/xtls/xray-core/app/dispatcher"
"github.com/xtls/xray-core/app/reverse" "github.com/xtls/xray-core/app/reverse"
@@ -548,7 +546,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
} }
var input *bytes.Reader var input *bytes.Reader
var rawInput *bytes.Buffer var rawInput **bytes.Buffer
switch requestAddons.Flow { switch requestAddons.Flow {
case vless.XRV: case vless.XRV:
if account.Flow == requestAddons.Flow { if account.Flow == requestAddons.Flow {
@@ -560,30 +558,23 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
inbound.CanSpliceCopy = 3 inbound.CanSpliceCopy = 3
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:
var t reflect.Type var target net.Conn
var p uintptr
if commonConn, ok := connection.(*encryption.CommonConn); ok { if commonConn, ok := connection.(*encryption.CommonConn); ok {
if _, ok := commonConn.Conn.(*encryption.XorConn); ok || !proxy.IsRAWTransportWithoutSecurity(iConn) { if _, ok := commonConn.Conn.(*encryption.XorConn); ok || !proxy.IsRAWTransportWithoutSecurity(iConn) {
inbound.CanSpliceCopy = 3 // full-random xorConn / non-RAW transport / another securityConn should not be penetrated inbound.CanSpliceCopy = 3 // full-random xorConn / non-RAW transport / another securityConn should not be penetrated
} }
t = reflect.TypeOf(commonConn).Elem() target = commonConn
p = uintptr(unsafe.Pointer(commonConn))
} else if tlsConn, ok := iConn.(*tls.Conn); ok { } else if tlsConn, ok := iConn.(*tls.Conn); ok {
if tlsConn.ConnectionState().Version != gotls.VersionTLS13 { if tlsConn.ConnectionState().Version != gotls.VersionTLS13 {
return errors.New(`failed to use `+requestAddons.Flow+`, found outer tls version `, tlsConn.ConnectionState().Version) return errors.New(`failed to use `+requestAddons.Flow+`, found outer tls version `, tlsConn.ConnectionState().Version)
} }
t = reflect.TypeOf(tlsConn.Conn).Elem() target = tlsConn.Conn
p = uintptr(unsafe.Pointer(tlsConn.Conn))
} else if realityConn, ok := iConn.(*reality.Conn); ok { } else if realityConn, ok := iConn.(*reality.Conn); ok {
t = reflect.TypeOf(realityConn.Conn).Elem() target = realityConn.Conn
p = uintptr(unsafe.Pointer(realityConn.Conn))
} else { } else {
return errors.New("XTLS only supports TLS and REALITY directly for now.") return errors.New("XTLS only supports TLS and REALITY directly for now.")
} }
i, _ := t.FieldByName("input") input, rawInput = vless.AccessTLSBuffers(target)
r, _ := t.FieldByName("rawInput")
input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset))
rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset))
} }
} else { } else {
return errors.New("account " + account.ID.String() + " is not able to use the flow " + requestAddons.Flow) return errors.New("account " + account.ID.String() + " is not able to use the flow " + requestAddons.Flow)
+7 -17
View File
@@ -5,11 +5,9 @@ import (
"context" "context"
gotls "crypto/tls" gotls "crypto/tls"
"encoding/base64" "encoding/base64"
"reflect"
"strings" "strings"
"sync" "sync"
"time" "time"
"unsafe"
utls "github.com/refraction-networking/utls" utls "github.com/refraction-networking/utls"
proxymanConfig "github.com/xtls/xray-core/app/proxyman" proxymanConfig "github.com/xtls/xray-core/app/proxyman"
@@ -244,7 +242,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
} }
var input *bytes.Reader var input *bytes.Reader
var rawInput *bytes.Buffer var rawInput **bytes.Buffer
allowUDP443 := false allowUDP443 := false
switch requestAddons.Flow { switch requestAddons.Flow {
case vless.XRV + "-udp443": case vless.XRV + "-udp443":
@@ -261,30 +259,22 @@ 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, protocol.RequestCommandRvs: case protocol.RequestCommandTCP, protocol.RequestCommandRvs:
var t reflect.Type var target net.Conn
var p uintptr
if commonConn, ok := conn.(*encryption.CommonConn); ok { if commonConn, ok := conn.(*encryption.CommonConn); ok {
if _, ok := commonConn.Conn.(*encryption.XorConn); ok || !proxy.IsRAWTransportWithoutSecurity(iConn) { if _, ok := commonConn.Conn.(*encryption.XorConn); ok || !proxy.IsRAWTransportWithoutSecurity(iConn) {
ob.CanSpliceCopy = 3 // full-random xorConn / non-RAW transport / another securityConn should not be penetrated ob.CanSpliceCopy = 3 // full-random xorConn / non-RAW transport / another securityConn should not be penetrated
} }
t = reflect.TypeOf(commonConn).Elem() target = commonConn
p = uintptr(unsafe.Pointer(commonConn))
} else if tlsConn, ok := iConn.(*tls.Conn); ok { } else if tlsConn, ok := iConn.(*tls.Conn); ok {
t = reflect.TypeOf(tlsConn.Conn).Elem() target = tlsConn.Conn
p = uintptr(unsafe.Pointer(tlsConn.Conn))
} else if utlsConn, ok := iConn.(*tls.UConn); ok { } else if utlsConn, ok := iConn.(*tls.UConn); ok {
t = reflect.TypeOf(utlsConn.Conn).Elem() target = utlsConn.Conn
p = uintptr(unsafe.Pointer(utlsConn.Conn))
} else if realityConn, ok := iConn.(*reality.UConn); ok { } else if realityConn, ok := iConn.(*reality.UConn); ok {
t = reflect.TypeOf(realityConn.Conn).Elem() target = realityConn.Conn
p = uintptr(unsafe.Pointer(realityConn.Conn))
} else { } else {
return errors.New("XTLS only supports TLS and REALITY directly for now.") return errors.New("XTLS only supports TLS and REALITY directly for now.")
} }
i, _ := t.FieldByName("input") input, rawInput = vless.AccessTLSBuffers(target)
r, _ := t.FieldByName("rawInput")
input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset))
rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset))
default: default:
panic("unknown VLESS request command") panic("unknown VLESS request command")
} }
+21
View File
@@ -5,7 +5,28 @@
// clients with 'socks' for proxying. // clients with 'socks' for proxying.
package vless package vless
import (
"bytes"
"net"
"reflect"
"github.com/xtls/xray-core/common/utils"
)
const ( const (
None = "none" None = "none"
XRV = "xtls-rprx-vision" XRV = "xtls-rprx-vision"
) )
// Old TLS lib holds bytes.Buffer, but new TLS lib holds *bytes.Buffer
// Since Xray has 3 TLS libraries (std, utls, REALITY server)
// we detect the type of rawInput and return the appropriate pointer
func AccessTLSBuffers(conn net.Conn) (*bytes.Reader, **bytes.Buffer) {
input := utils.AccessField[bytes.Reader](conn, "input")
field := reflect.ValueOf(conn).Elem().FieldByName("rawInput")
if field.Kind() == reflect.Pointer {
return input, utils.AccessField[*bytes.Buffer](conn, "rawInput")
}
raw := utils.AccessField[bytes.Buffer](conn, "rawInput")
return input, &raw
}