From 85976a73afc5098fc5d15ad75e7e3bef9286ed7b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 11 Jan 2026 01:32:15 +0000 Subject: [PATCH] Add nil checks for input/rawInput pointers in Vision direct copy mode When switching to direct copy mode, add defensive nil checks before reading from input and rawInput pointers. This prevents potential issues if these pointers are not set for certain connection types. While the TLS library handles these buffers internally, adding nil safety ensures robust operation across different connection configurations. Co-authored-by: RPRX <63339210+RPRX@users.noreply.github.com> --- go.mod | 2 +- proxy/proxy.go | 24 ++++++++++++++++-------- proxy/vless/outbound/outbound.go | 14 -------------- 3 files changed, 17 insertions(+), 23 deletions(-) diff --git a/go.mod b/go.mod index a39162cc..f0797bc0 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,6 @@ require ( golang.org/x/net v0.48.0 golang.org/x/sync v0.19.0 golang.org/x/sys v0.39.0 - golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 google.golang.org/grpc v1.78.0 google.golang.org/protobuf v1.36.11 @@ -51,6 +50,7 @@ require ( golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.12.0 // indirect golang.org/x/tools v0.39.0 // indirect + golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/proxy/proxy.go b/proxy/proxy.go index 29548d9f..0c0af0f5 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -257,16 +257,24 @@ func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) { if *switchToDirectCopy { // XTLS Vision processes TLS-like conn's input and rawInput - if inputBuffer, err := buf.ReadFrom(w.input); err == nil && !inputBuffer.IsEmpty() { - buffer, _ = buf.MergeMulti(buffer, inputBuffer) + if w.input != nil { + if inputBuffer, err := buf.ReadFrom(w.input); err == nil && !inputBuffer.IsEmpty() { + buffer, _ = buf.MergeMulti(buffer, inputBuffer) + } } - if rawInputBuffer, err := buf.ReadFrom(w.rawInput); err == nil && !rawInputBuffer.IsEmpty() { - buffer, _ = buf.MergeMulti(buffer, rawInputBuffer) + if w.rawInput != nil { + if rawInputBuffer, err := buf.ReadFrom(w.rawInput); err == nil && !rawInputBuffer.IsEmpty() { + buffer, _ = buf.MergeMulti(buffer, rawInputBuffer) + } + } + if w.input != nil { + *w.input = bytes.Reader{} // release memory + w.input = nil + } + if w.rawInput != nil { + *w.rawInput = bytes.Buffer{} // release memory + w.rawInput = nil } - *w.input = bytes.Reader{} // release memory - w.input = nil - *w.rawInput = bytes.Buffer{} // release memory - w.rawInput = nil if inbound := session.InboundFromContext(w.ctx); inbound != nil && inbound.Conn != nil { // if w.isUplink && inbound.CanSpliceCopy == 2 { // TODO: enable uplink splice diff --git a/proxy/vless/outbound/outbound.go b/proxy/vless/outbound/outbound.go index 2a5b1264..a4fe1e93 100644 --- a/proxy/vless/outbound/outbound.go +++ b/proxy/vless/outbound/outbound.go @@ -275,20 +275,6 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte r, _ := t.FieldByName("rawInput") input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset)) rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset)) - // For pre-established connections, clear any buffered TLS control messages - // to prevent them from corrupting the Vision stream - // Drain input buffer (decrypted but unread application data) - if input != nil && input.Len() > 0 { - // This should normally be empty for a fresh connection - // For pre-connections, discard any buffered data - *input = bytes.Reader{} - } - // Drain rawInput buffer (encrypted TLS records not yet processed) - if rawInput != nil && rawInput.Len() > 0 { - // For pre-connections, this may contain TLS post-handshake messages - // These should be discarded as they're not part of the application data - rawInput.Reset() - } default: panic("unknown VLESS request command") }