From d52f15060bffa8508a660817781ce7c911f16ef6 Mon Sep 17 00:00:00 2001 From: Meow <197331664+Meo597@users.noreply.github.com> Date: Sat, 18 Apr 2026 06:56:27 +0800 Subject: [PATCH] Direct/Freedom outbound: Block UDP responses that are come from `ipsBlocked` as well (#5952) https://github.com/XTLS/Xray-core/pull/5947#issuecomment-4258980670 https://github.com/XTLS/Xray-core/pull/5952#issuecomment-4259324234 --------- Co-authored-by: RPRX <63339210+RPRX@users.noreply.github.com> --- proxy/freedom/freedom.go | 60 +++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/proxy/freedom/freedom.go b/proxy/freedom/freedom.go index 008f700f..bc05d04a 100644 --- a/proxy/freedom/freedom.go +++ b/proxy/freedom/freedom.go @@ -290,7 +290,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte if destination.Network == net.Network_TCP { reader = buf.NewReader(conn) } else { - reader = NewPacketReader(conn, UDPOverride, destination) + reader = NewPacketReader(conn, UDPOverride, destination, blockedIPMatcher) } if err := buf.Copy(reader, output, buf.UpdateActivity(timer)); err != nil { return errors.New("failed to process response").Base(err) @@ -309,7 +309,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte return nil } -func NewPacketReader(conn net.Conn, UDPOverride net.Destination, DialDest net.Destination) buf.Reader { +func NewPacketReader(conn net.Conn, UDPOverride net.Destination, DialDest net.Destination, blockedIPMatcher geodata.IPMatcher) buf.Reader { iConn := conn statConn, ok := iConn.(*stat.CounterConnection) if ok { @@ -328,6 +328,7 @@ func NewPacketReader(conn net.Conn, UDPOverride net.Destination, DialDest net.De return &PacketReader{ PacketConnWrapper: c, Counter: counter, + BlockedIPMatcher: blockedIPMatcher, IsOverridden: isOverridden, InitUnchangedAddr: DialDest.Address, InitChangedAddr: net.DestinationFromAddr(conn.RemoteAddr()).Address, @@ -339,6 +340,7 @@ func NewPacketReader(conn net.Conn, UDPOverride net.Destination, DialDest net.De type PacketReader struct { *internet.PacketConnWrapper stats.Counter + BlockedIPMatcher geodata.IPMatcher IsOverridden bool InitUnchangedAddr net.Address InitChangedAddr net.Address @@ -346,30 +348,38 @@ type PacketReader struct { func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) { b := buf.New() - b.Resize(0, buf.Size) - n, d, err := r.PacketConnWrapper.ReadFrom(b.Bytes()) - if err != nil { - b.Release() - return nil, err - } - b.Resize(0, int32(n)) - // if udp dest addr is changed, we are unable to get the correct src addr - // so we don't attach src info to udp packet, break cone behavior, assuming the dial dest is the expected scr addr - if !r.IsOverridden { - address := net.IPAddress(d.(*net.UDPAddr).IP) - if r.InitChangedAddr == address { - address = r.InitUnchangedAddr + for { + b.Resize(0, buf.Size) + n, d, err := r.PacketConnWrapper.ReadFrom(b.Bytes()) + if err != nil { + b.Release() + return nil, err } - b.UDP = &net.Destination{ - Address: address, - Port: net.Port(d.(*net.UDPAddr).Port), - Network: net.Network_UDP, + b.Resize(0, int32(n)) + + udpAddr := d.(*net.UDPAddr) + sourceAddr := net.IPAddress(udpAddr.IP) + if isBlockedAddress(r.BlockedIPMatcher, sourceAddr) { + continue } + + // if udp dest addr is changed, we are unable to get the correct src addr + // so we don't attach src info to udp packet, break cone behavior, assuming the dial dest is the expected scr addr + if !r.IsOverridden { + if r.InitChangedAddr == sourceAddr { + sourceAddr = r.InitUnchangedAddr + } + b.UDP = &net.Destination{ + Address: sourceAddr, + Port: net.Port(udpAddr.Port), + Network: net.Network_UDP, + } + } + if r.Counter != nil { + r.Counter.Add(int64(n)) + } + return buf.MultiBuffer{b}, nil } - if r.Counter != nil { - r.Counter.Add(int64(n)) - } - return buf.MultiBuffer{b}, nil } // DialDest means the dial target used in the dialer when creating conn @@ -468,10 +478,8 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error { } } if isBlockedAddress(w.BlockedIPMatcher, b.UDP.Address) { - blockedAddr := b.UDP.Address b.Release() - buf.ReleaseMulti(mb) - return errors.New("blocked target IP: ", blockedAddr).AtDebug() + continue } destAddr := b.UDP.RawNetAddr() if destAddr == nil {