From c412e77a9b712082ac9ebf27fa793951cb5a7d85 Mon Sep 17 00:00:00 2001 From: SVLAVR Date: Sat, 12 Sep 2026 23:09:35 +0300 Subject: [PATCH] TUN inbound: Preserve UDP packet destinations with traffic stats (#6747) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/XTLS/Xray-core/pull/6747#issuecomment-5647964551 --------- Co-authored-by: 风扇滑翔翼 --- proxy/tun/handler.go | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/proxy/tun/handler.go b/proxy/tun/handler.go index 56fe5653a..709fc1ec6 100644 --- a/proxy/tun/handler.go +++ b/proxy/tun/handler.go @@ -37,6 +37,25 @@ type Handler struct { downlinkCounter stats.Counter } +type tunUDPStatsWriter struct { + writer buf.Writer + counter stats.Counter +} + +func (w *tunUDPStatsWriter) WriteMultiBuffer(mb buf.MultiBuffer) error { + for len(mb) > 0 { + remaining, packet := buf.SplitFirst(mb) + packetSize := packet.Len() + if err := w.writer.WriteMultiBuffer(buf.MultiBuffer{packet}); err != nil { + buf.ReleaseMulti(remaining) + return err + } + w.counter.Add(int64(packetSize)) + mb = remaining + } + return nil +} + // ConnectionHandler interface with the only method that stack is going to push new connections to type ConnectionHandler interface { HandleConnection(conn net.Conn, destination net.Destination) @@ -171,7 +190,8 @@ func (t *Handler) HandleConnection(conn net.Conn, destination net.Destination) { return } source := net.DestinationFromAddr(remote) - if t.uplinkCounter != nil || t.downlinkCounter != nil { + isUDP := destination.Network == net.Network_UDP + if !isUDP && (t.uplinkCounter != nil || t.downlinkCounter != nil) { conn = &stat.CounterConnection{ Connection: conn, ReadCounter: t.uplinkCounter, @@ -203,9 +223,18 @@ func (t *Handler) HandleConnection(conn net.Conn, destination net.Destination) { }) errors.LogInfo(ctx, "processing from ", source, " to ", destination) + reader := &buf.TimeoutWrapperReader{Reader: buf.NewReader(conn)} + writer := buf.NewWriter(conn) + if isUDP { + reader.Counter = t.uplinkCounter + if t.downlinkCounter != nil { + writer = &tunUDPStatsWriter{writer: writer, counter: t.downlinkCounter} + } + } + link := &transport.Link{ - Reader: &buf.TimeoutWrapperReader{Reader: buf.NewReader(conn)}, - Writer: buf.NewWriter(conn), + Reader: reader, + Writer: writer, } if err := t.dispatcher.DispatchLink(ctx, destination, link); err != nil { errors.LogError(ctx, errors.New("connection closed").Base(err))