diff --git a/proxy/vless/encoding/encoding.go b/proxy/vless/encoding/encoding.go index 9a1ec425..dea27044 100644 --- a/proxy/vless/encoding/encoding.go +++ b/proxy/vless/encoding/encoding.go @@ -250,6 +250,7 @@ func ReadV(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, c // XtlsRead filter and read xtls protocol func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, rawConn syscall.RawConn, + input *bytes.Reader, rawInput *bytes.Buffer, counter stats.Counter, ctx context.Context, userUUID []byte, numberOfPacketToFilter *int, enableXtls *bool, isTLS12orAbove *bool, isTLS *bool, cipher *uint16, remainingServerHello *int32, ) error { @@ -301,6 +302,17 @@ func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater } else if currentCommand == 2 { filterUUID = false shouldSwitchToDirectCopy = true + // XTLS Vision processes struct TLS Conn's input and rawInput + if inputBuffer, err := buf.ReadFrom(input); err == nil { + if !inputBuffer.IsEmpty() { + buffer, _ = buf.MergeMulti(buffer, inputBuffer) + } + } + if rawInputBuffer, err := buf.ReadFrom(rawInput); err == nil { + if !rawInputBuffer.IsEmpty() { + buffer, _ = buf.MergeMulti(buffer, rawInputBuffer) + } + } } else if currentCommand != 0 { newError("XtlsRead unknown command ", currentCommand, buffer.Len()).WriteToLog(session.ExportIDToError(ctx)) } diff --git a/proxy/vless/inbound/inbound.go b/proxy/vless/inbound/inbound.go index 347f6710..aa63a95b 100644 --- a/proxy/vless/inbound/inbound.go +++ b/proxy/vless/inbound/inbound.go @@ -3,12 +3,15 @@ package inbound //go:generate go run github.com/xtls/xray-core/common/errors/errorgen import ( + "bytes" "context" "io" + "reflect" "strconv" "strings" "syscall" "time" + "unsafe" "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/buf" @@ -441,6 +444,8 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s var netConn net.Conn var rawConn syscall.RawConn + var input *bytes.Reader + var rawInput *bytes.Buffer allowNoneFlow := false accountFlow := account.Flow flows := strings.Split(account.Flow, ",") @@ -462,11 +467,15 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s return newError(requestAddons.Flow + " doesn't support UDP").AtWarning() case protocol.RequestCommandTCP: if requestAddons.Flow == vless.XRV { + var t reflect.Type + var p uintptr if tlsConn, ok := iConn.(*tls.Conn); ok { netConn = tlsConn.NetConn() if sc, ok := netConn.(syscall.Conn); ok { rawConn, _ = sc.SyscallConn() } + t = reflect.TypeOf(tlsConn.Conn).Elem() + p = uintptr(unsafe.Pointer(tlsConn.Conn)) } else if _, ok := iConn.(*tls.UConn); ok { return newError("XTLS only supports UTLS fingerprint for the outbound.").AtWarning() } else if _, ok := iConn.(*xtls.Conn); ok { @@ -474,6 +483,10 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s } else { return newError("XTLS only supports TCP, mKCP and DomainSocket for now.").AtWarning() } + i, _ := t.FieldByName("input") + r, _ := t.FieldByName("rawInput") + input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset)) + rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset)) } else if xtlsConn, ok := iConn.(*xtls.Conn); ok { xtlsConn.RPRX = true xtlsConn.SHOW = xtls_show @@ -545,7 +558,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s // TODO enable splice ctx = session.ContextWithInbound(ctx, nil) if requestAddons.Flow == vless.XRV { - err = encoding.XtlsRead(clientReader, serverWriter, timer, netConn, rawConn, counter, ctx, account.ID.Bytes(), + err = encoding.XtlsRead(clientReader, serverWriter, timer, netConn, rawConn, input, rawInput, counter, ctx, account.ID.Bytes(), &numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello) } else { err = encoding.ReadV(clientReader, serverWriter, timer, iConn.(*xtls.Conn), rawConn, counter, ctx) diff --git a/proxy/vless/outbound/outbound.go b/proxy/vless/outbound/outbound.go index d7ed63fa..c84d5b4c 100644 --- a/proxy/vless/outbound/outbound.go +++ b/proxy/vless/outbound/outbound.go @@ -3,9 +3,12 @@ package outbound //go:generate go run github.com/xtls/xray-core/common/errors/errorgen import ( + "bytes" "context" + "reflect" "syscall" "time" + "unsafe" "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/buf" @@ -130,6 +133,8 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte var netConn net.Conn var rawConn syscall.RawConn + var input *bytes.Reader + var rawInput *bytes.Buffer allowUDP443 := false switch requestAddons.Flow { case vless.XRO + "-udp443", vless.XRD + "-udp443", vless.XRS + "-udp443", vless.XRV + "-udp443": @@ -147,21 +152,31 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte requestAddons.Flow = "" case protocol.RequestCommandTCP: if requestAddons.Flow == vless.XRV { + var t reflect.Type + var p uintptr if tlsConn, ok := iConn.(*tls.Conn); ok { netConn = tlsConn.NetConn() if sc, ok := netConn.(syscall.Conn); ok { rawConn, _ = sc.SyscallConn() } + t = reflect.TypeOf(tlsConn.Conn).Elem() + p = uintptr(unsafe.Pointer(tlsConn.Conn)) } else if utlsConn, ok := iConn.(*tls.UConn); ok { netConn = utlsConn.Conn.NetConn() if sc, ok := netConn.(syscall.Conn); ok { rawConn, _ = sc.SyscallConn() } + t = reflect.TypeOf(utlsConn.Conn).Elem() + p = uintptr(unsafe.Pointer(utlsConn.Conn)) } else if _, ok := iConn.(*xtls.Conn); ok { return newError(`failed to use ` + requestAddons.Flow + `, vision "security" must be "tls"`).AtWarning() } else { return newError("XTLS only supports TCP, mKCP and DomainSocket for now.").AtWarning() } + i, _ := t.FieldByName("input") + r, _ := t.FieldByName("rawInput") + input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset)) + rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset)) } else if xtlsConn, ok := iConn.(*xtls.Conn); ok { xtlsConn.RPRX = true xtlsConn.SHOW = xtls_show @@ -287,7 +302,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte counter = statConn.ReadCounter } if requestAddons.Flow == vless.XRV { - err = encoding.XtlsRead(serverReader, clientWriter, timer, netConn, rawConn, counter, ctx, account.ID.Bytes(), + err = encoding.XtlsRead(serverReader, clientWriter, timer, netConn, rawConn, input, rawInput, counter, ctx, account.ID.Bytes(), &numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello) } else { if requestAddons.Flow != vless.XRS {