Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions client/android/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ type DnsReadyListener interface {
dns.ReadyListener
}

// TunSettings is a snapshot of the settings the TUN device is rebuilt with
type TunSettings struct {
Routes string
SearchDomains string
}

func init() {
formatter.SetLogcatFormatter(log.StandardLogger())
}
Expand Down Expand Up @@ -240,6 +246,24 @@ func (c *Client) RenewTun(fd int) error {
return e.RenewTun(fd)
}

func (c *Client) GetTunSettings() (*TunSettings, error) {
cc := c.getConnectClient()
if cc == nil {
return nil, fmt.Errorf("engine not running")
}

e := cc.Engine()
if e == nil {
return nil, fmt.Errorf("engine not initialized")
}

routes, searchDomains := e.TunSettings()
return &TunSettings{
Routes: strings.Join(routes, ";"),
SearchDomains: strings.Join(searchDomains, ";"),
}, nil
}

// DebugBundle generates a debug bundle, uploads it, and returns the upload key.
// It works both with and without a running engine.
func (c *Client) DebugBundle(platformFiles PlatformFiles, anonymize bool) (string, error) {
Expand Down
10 changes: 8 additions & 2 deletions client/internal/dns/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ func NewDefaultServerPermanentUpstream(
ds.hostsDNSHolder.set(hostsDnsList)
ds.permanent = true
ds.currentConfig = dnsConfigToHostDNSConfig(config, ds.service.RuntimeIP(), ds.service.RuntimePort())
ds.searchDomainNotifier = newNotifier(ds.SearchDomains())
ds.searchDomainNotifier = newNotifier(ds.searchDomains())
ds.searchDomainNotifier.setListener(listener)
setServerDns(ds)
return ds
Expand Down Expand Up @@ -602,6 +602,12 @@ func (s *DefaultServer) UpdateDNSServer(serial uint64, update nbdns.Config) erro
}

func (s *DefaultServer) SearchDomains() []string {
s.mux.Lock()
defer s.mux.Unlock()
return s.searchDomains()
}

func (s *DefaultServer) searchDomains() []string {
var searchDomains []string

for _, dConf := range s.currentConfig.Domains {
Expand Down Expand Up @@ -686,7 +692,7 @@ func (s *DefaultServer) applyConfiguration(update nbdns.Config) error {
}()

if s.searchDomainNotifier != nil {
s.searchDomainNotifier.onNewSearchDomains(s.SearchDomains())
s.searchDomainNotifier.onNewSearchDomains(s.searchDomains())
}

s.updateNSGroupStates(update.NameServerGroups)
Expand Down
20 changes: 20 additions & 0 deletions client/internal/engine_tunsettings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package internal

func (e *Engine) TunSettings() ([]string, []string) {
e.syncMsgMux.Lock()
routeManager := e.routeManager
dnsServer := e.dnsServer
e.syncMsgMux.Unlock()

var routes []string
if routeManager != nil {
routes = routeManager.CurrentRouteRange()
}

var searchDomains []string
if dnsServer != nil {
searchDomains = dnsServer.SearchDomains()
}

return routes, searchDomains
}
32 changes: 31 additions & 1 deletion client/internal/routemanager/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"net/url"
"runtime"
"slices"
"sort"
"strings"
"sync"
"sync/atomic"
Expand Down Expand Up @@ -63,6 +64,7 @@ type Manager interface {
GetClientRoutesWithNetID() map[route.NetID][]*route.Route
SetRouteChangeListener(listener listener.NetworkChangeListener)
InitialRouteRange() []string
CurrentRouteRange() []string
SetFirewall(firewall.Manager) error
SetDNSForwarderPort(port uint16)
ReconcilePeerAllowedIPs(peerKey string) error
Expand Down Expand Up @@ -191,7 +193,7 @@ func (m *DefaultManager) enableFakeIPRoutes() []*route.Route {
NetworkType: route.IPv6Network,
}
fakeRoutes := []*route.Route{fakeIPRoute, fakeIPv6Route}
m.notifier.SetFakeIPRoutes(fakeRoutes)
m.notifier.NotifyRouteChange()
return fakeRoutes
}

Expand Down Expand Up @@ -513,6 +515,34 @@ func (m *DefaultManager) InitialRouteRange() []string {
return m.notifier.GetInitialRouteRanges()
}

// CurrentRouteRange returns the current TUN route list. It is used by mobile systems
func (m *DefaultManager) CurrentRouteRange() []string {
m.mux.Lock()
defer m.mux.Unlock()

if m.disableClientRoutes {
return nil
}

filtered := m.routeSelector.FilterSelectedExitNodes(m.clientRoutes)
var nets []string
for _, routes := range filtered {
for _, r := range routes {
if r.IsDynamic() {
continue
}
nets = append(nets, r.NetString())
}
}

if m.fakeIPManager != nil {
nets = append(nets, m.fakeIPManager.GetFakeIPBlock().String(), m.fakeIPManager.GetFakeIPv6Block().String())
}

sort.Strings(nets)
return nets
}

// GetRouteSelector returns the route selector
func (m *DefaultManager) GetRouteSelector() *routeselector.RouteSelector {
return m.routeSelector
Expand Down
5 changes: 5 additions & 0 deletions client/internal/routemanager/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ func (m *MockManager) InitialRouteRange() []string {
return nil
}

// CurrentRouteRange mock implementation of CurrentRouteRange from Manager interface
func (m *MockManager) CurrentRouteRange() []string {
return nil
}

// UpdateRoutes mock implementation of UpdateRoutes from Manager interface
func (m *MockManager) UpdateRoutes(updateSerial uint64, newRoutes map[route.ID]*route.Route, clientRoutes route.HAMap, useNewDNSRoute bool) error {
if m.UpdateRoutesFunc != nil {
Expand Down
69 changes: 35 additions & 34 deletions client/internal/routemanager/notifier/notifier_android.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,47 @@ import (
"net/netip"
"slices"
"sort"
"strings"
"sync"

"github.com/netbirdio/netbird/client/internal/listener"
"github.com/netbirdio/netbird/route"
)

type Notifier struct {
mu sync.Mutex

initialRoutes []*route.Route
// currentRoutes is the last announced route set. It exists only to
// suppress noise: without it every network map sync would trigger the
// Java side, even when the routes did not change. The actual TUN route
// state is owned by the route manager and pulled from there.
currentRoutes []*route.Route
fakeIPRoutes []*route.Route

listener listener.NetworkChangeListener
listenerMux sync.Mutex
listener listener.NetworkChangeListener
}

func NewNotifier() *Notifier {
return &Notifier{}
}

func (n *Notifier) SetListener(listener listener.NetworkChangeListener) {
n.listenerMux.Lock()
defer n.listenerMux.Unlock()
n.mu.Lock()
defer n.mu.Unlock()
n.listener = listener
}

// SetInitialClientRoutes stores the initial route sets for TUN configuration.
func (n *Notifier) SetInitialClientRoutes(initialRoutes []*route.Route, routesForComparison []*route.Route) {
n.mu.Lock()
defer n.mu.Unlock()
n.initialRoutes = filterStatic(initialRoutes)
n.currentRoutes = filterStatic(routesForComparison)
}

// SetFakeIPRoutes stores the fake IP routes to be included in every TUN rebuild.
func (n *Notifier) SetFakeIPRoutes(routes []*route.Route) {
n.fakeIPRoutes = routes
n.notify()
func (n *Notifier) NotifyRouteChange() {
n.mu.Lock()
defer n.mu.Unlock()
n.notifyLocked()
}

func (n *Notifier) OnNewRoutes(idMap route.HAMap) {
Expand All @@ -55,31 +60,37 @@ func (n *Notifier) OnNewRoutes(idMap route.HAMap) {
}
}

if !n.hasRouteDiff(n.currentRoutes, newRoutes) {
n.mu.Lock()
defer n.mu.Unlock()
if !hasRouteDiff(n.currentRoutes, newRoutes) {
return
}

n.currentRoutes = newRoutes
n.notify()
n.notifyLocked()
}

func (n *Notifier) OnNewPrefixes([]netip.Prefix) {
// Not used on Android
}

func (n *Notifier) notify() {
n.listenerMux.Lock()
defer n.listenerMux.Unlock()
func (n *Notifier) notifyLocked() {
if n.listener == nil {
return
}
n.listener.OnNetworkChanged("")
}

allRoutes := slices.Clone(n.currentRoutes)
allRoutes = append(allRoutes, n.fakeIPRoutes...)
func (n *Notifier) GetInitialRouteRanges() []string {
n.mu.Lock()
defer n.mu.Unlock()
initialStrings := routesToStrings(n.initialRoutes)
sort.Strings(initialStrings)
return initialStrings
}

routeStrings := n.routesToStrings(allRoutes)
sort.Strings(routeStrings)
n.listener.OnNetworkChanged(strings.Join(routeStrings, ","))
func (n *Notifier) Close() {
// unused
}

func filterStatic(routes []*route.Route) []*route.Route {
Expand All @@ -92,28 +103,18 @@ func filterStatic(routes []*route.Route) []*route.Route {
return out
}

func (n *Notifier) routesToStrings(routes []*route.Route) []string {
func routesToStrings(routes []*route.Route) []string {
nets := make([]string, 0, len(routes))
for _, r := range routes {
nets = append(nets, r.NetString())
}
return nets
}

func (n *Notifier) hasRouteDiff(a []*route.Route, b []*route.Route) bool {
as := n.routesToStrings(a)
bs := n.routesToStrings(b)
func hasRouteDiff(a []*route.Route, b []*route.Route) bool {
as := routesToStrings(a)
bs := routesToStrings(b)
sort.Strings(as)
sort.Strings(bs)
return !slices.Equal(as, bs)
}

func (n *Notifier) GetInitialRouteRanges() []string {
initialStrings := n.routesToStrings(n.initialRoutes)
sort.Strings(initialStrings)
return initialStrings
}

func (n *Notifier) Close() {
// unused
}
2 changes: 1 addition & 1 deletion client/internal/routemanager/notifier/notifier_ios.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (n *Notifier) SetInitialClientRoutes([]*route.Route, []*route.Route) {
// iOS doesn't care about initial routes
}

func (n *Notifier) SetFakeIPRoutes([]*route.Route) {
func (n *Notifier) NotifyRouteChange() {
// Not used on iOS
}

Expand Down
2 changes: 1 addition & 1 deletion client/internal/routemanager/notifier/notifier_other.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func (n *Notifier) SetInitialClientRoutes([]*route.Route, []*route.Route) {
// Not used on non-mobile platforms
}

func (n *Notifier) SetFakeIPRoutes([]*route.Route) {
func (n *Notifier) NotifyRouteChange() {
// Not used on non-mobile platforms
}

Expand Down
Loading