From e5e275c87a90680ca9abaaf51596ac1ed0827013 Mon Sep 17 00:00:00 2001 From: Viktor Liu <17948409+lixmal@users.noreply.github.com> Date: Thu, 24 Jul 2025 13:34:36 +0200 Subject: [PATCH] [client] Fix legacy routing exclusion routes in kernel mode (#4167) --- client/iface/bind/ice_bind.go | 2 +- client/iface/bind/udp_mux_generic.go | 15 ++++++++------- client/iface/device/device_kernel_unix.go | 9 ++++++++- util/net/listener_listen.go | 21 +++++++++++---------- util/net/listener_listen_ios.go | 4 ++-- 5 files changed, 30 insertions(+), 21 deletions(-) diff --git a/client/iface/bind/ice_bind.go b/client/iface/bind/ice_bind.go index c3d5ef377..41f4aec6d 100644 --- a/client/iface/bind/ice_bind.go +++ b/client/iface/bind/ice_bind.go @@ -154,7 +154,7 @@ func (s *ICEBind) createIPv4ReceiverFn(pc *ipv4.PacketConn, conn *net.UDPConn, r s.udpMux = NewUniversalUDPMuxDefault( UniversalUDPMuxParams{ - UDPConn: nbnet.WrapUDPConn(conn), + UDPConn: nbnet.WrapPacketConn(conn), Net: s.transportNet, FilterFn: s.filterFn, WGAddress: s.address, diff --git a/client/iface/bind/udp_mux_generic.go b/client/iface/bind/udp_mux_generic.go index e42d25462..63f786d2b 100644 --- a/client/iface/bind/udp_mux_generic.go +++ b/client/iface/bind/udp_mux_generic.go @@ -7,15 +7,16 @@ import ( ) func (m *UDPMuxDefault) notifyAddressRemoval(addr string) { - wrapped, ok := m.params.UDPConn.(*UDPConn) - if !ok { + // Kernel mode: direct nbnet.PacketConn (SharedSocket wrapped with nbnet) + if conn, ok := m.params.UDPConn.(*nbnet.PacketConn); ok { + conn.RemoveAddress(addr) return } - nbnetConn, ok := wrapped.GetPacketConn().(*nbnet.UDPConn) - if !ok { - return + // Userspace mode: UDPConn wrapper around nbnet.PacketConn + if wrapped, ok := m.params.UDPConn.(*UDPConn); ok { + if conn, ok := wrapped.GetPacketConn().(*nbnet.PacketConn); ok { + conn.RemoveAddress(addr) + } } - - nbnetConn.RemoveAddress(addr) } diff --git a/client/iface/device/device_kernel_unix.go b/client/iface/device/device_kernel_unix.go index 988ed1b39..7136be0bc 100644 --- a/client/iface/device/device_kernel_unix.go +++ b/client/iface/device/device_kernel_unix.go @@ -16,6 +16,7 @@ import ( "github.com/netbirdio/netbird/client/iface/configurer" "github.com/netbirdio/netbird/client/iface/wgaddr" "github.com/netbirdio/netbird/sharedsock" + nbnet "github.com/netbirdio/netbird/util/net" ) type TunKernelDevice struct { @@ -99,8 +100,14 @@ func (t *TunKernelDevice) Up() (*bind.UniversalUDPMuxDefault, error) { if err != nil { return nil, err } + + var udpConn net.PacketConn = rawSock + if !nbnet.AdvancedRouting() { + udpConn = nbnet.WrapPacketConn(rawSock) + } + bindParams := bind.UniversalUDPMuxParams{ - UDPConn: rawSock, + UDPConn: udpConn, Net: t.transportNet, FilterFn: t.filterFn, WGAddress: t.address, diff --git a/util/net/listener_listen.go b/util/net/listener_listen.go index dc99fbd68..4060ab49a 100644 --- a/util/net/listener_listen.go +++ b/util/net/listener_listen.go @@ -120,17 +120,8 @@ func (c *UDPConn) Close() error { return closeConn(c.ID, c.UDPConn) } -// WrapUDPConn wraps an existing *net.UDPConn with nbnet functionality -func WrapUDPConn(conn *net.UDPConn) *UDPConn { - return &UDPConn{ - UDPConn: conn, - ID: GenerateConnID(), - seenAddrs: &sync.Map{}, - } -} - // RemoveAddress removes an address from the seen cache and triggers removal hooks. -func (c *UDPConn) RemoveAddress(addr string) { +func (c *PacketConn) RemoveAddress(addr string) { if _, exists := c.seenAddrs.LoadAndDelete(addr); !exists { return } @@ -159,6 +150,16 @@ func (c *UDPConn) RemoveAddress(addr string) { } } + +// WrapPacketConn wraps an existing net.PacketConn with nbnet functionality +func WrapPacketConn(conn net.PacketConn) *PacketConn { + return &PacketConn{ + PacketConn: conn, + ID: GenerateConnID(), + seenAddrs: &sync.Map{}, + } +} + func callWriteHooks(id ConnectionID, seenAddrs *sync.Map, b []byte, addr net.Addr) { // Lookup the address in the seenAddrs map to avoid calling the hooks for every write if _, loaded := seenAddrs.LoadOrStore(addr.String(), true); !loaded { diff --git a/util/net/listener_listen_ios.go b/util/net/listener_listen_ios.go index 3cbd2cd71..c52aea583 100644 --- a/util/net/listener_listen_ios.go +++ b/util/net/listener_listen_ios.go @@ -4,7 +4,7 @@ import ( "net" ) -// WrapUDPConn on iOS just returns the original connection since iOS handles its own networking -func WrapUDPConn(conn *net.UDPConn) *net.UDPConn { +// WrapPacketConn on iOS just returns the original connection since iOS handles its own networking +func WrapPacketConn(conn *net.UDPConn) *net.UDPConn { return conn }