mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-16 15:26:40 +00:00
extraInitialRoutes() was meant to preserve only the fake IP route (240.0.0.0/8) across TUN rebuilds, but it re-injected any initial route missing from the current set. When the management server advertised exit node routes (0.0.0.0/0) that were later filtered by the route selector, extraInitialRoutes() re-added them, causing the Android VPN to capture all traffic with no peer to handle it. Store the fake IP route explicitly and append only that in notify(), removing the overly broad initial route diffing.
133 lines
3.1 KiB
Go
133 lines
3.1 KiB
Go
//go:build android
|
|
|
|
package notifier
|
|
|
|
import (
|
|
"net/netip"
|
|
"slices"
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/netbirdio/netbird/client/internal/listener"
|
|
"github.com/netbirdio/netbird/route"
|
|
)
|
|
|
|
type Notifier struct {
|
|
initialRoutes []*route.Route
|
|
currentRoutes []*route.Route
|
|
fakeIPRoute *route.Route
|
|
|
|
listener listener.NetworkChangeListener
|
|
listenerMux sync.Mutex
|
|
}
|
|
|
|
func NewNotifier() *Notifier {
|
|
return &Notifier{}
|
|
}
|
|
|
|
func (n *Notifier) SetListener(listener listener.NetworkChangeListener) {
|
|
n.listenerMux.Lock()
|
|
defer n.listenerMux.Unlock()
|
|
n.listener = listener
|
|
}
|
|
|
|
// SetInitialClientRoutes stores the initial route sets for TUN configuration.
|
|
func (n *Notifier) SetInitialClientRoutes(initialRoutes []*route.Route, routesForComparison []*route.Route) {
|
|
n.initialRoutes = filterStatic(initialRoutes)
|
|
n.currentRoutes = filterStatic(routesForComparison)
|
|
}
|
|
|
|
// SetFakeIPRoute stores the fake IP route to be included in every TUN rebuild.
|
|
func (n *Notifier) SetFakeIPRoute(r *route.Route) {
|
|
n.fakeIPRoute = r
|
|
}
|
|
|
|
func (n *Notifier) OnNewRoutes(idMap route.HAMap) {
|
|
var newRoutes []*route.Route
|
|
for _, routes := range idMap {
|
|
for _, r := range routes {
|
|
if r.IsDynamic() {
|
|
continue
|
|
}
|
|
newRoutes = append(newRoutes, r)
|
|
}
|
|
}
|
|
|
|
if !n.hasRouteDiff(n.currentRoutes, newRoutes) {
|
|
return
|
|
}
|
|
|
|
n.currentRoutes = newRoutes
|
|
n.notify()
|
|
}
|
|
|
|
func (n *Notifier) OnNewPrefixes([]netip.Prefix) {
|
|
// Not used on Android
|
|
}
|
|
|
|
func (n *Notifier) notify() {
|
|
n.listenerMux.Lock()
|
|
defer n.listenerMux.Unlock()
|
|
if n.listener == nil {
|
|
return
|
|
}
|
|
|
|
allRoutes := slices.Clone(n.currentRoutes)
|
|
if n.fakeIPRoute != nil {
|
|
allRoutes = append(allRoutes, n.fakeIPRoute)
|
|
}
|
|
|
|
routeStrings := n.routesToStrings(allRoutes)
|
|
sort.Strings(routeStrings)
|
|
go func(l listener.NetworkChangeListener) {
|
|
l.OnNetworkChanged(strings.Join(n.addIPv6RangeIfNeeded(routeStrings, allRoutes), ","))
|
|
}(n.listener)
|
|
}
|
|
|
|
func filterStatic(routes []*route.Route) []*route.Route {
|
|
out := make([]*route.Route, 0, len(routes))
|
|
for _, r := range routes {
|
|
if !r.IsDynamic() {
|
|
out = append(out, r)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func (n *Notifier) 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 {
|
|
slices.SortFunc(a, func(x, y *route.Route) int {
|
|
return strings.Compare(x.NetString(), y.NetString())
|
|
})
|
|
slices.SortFunc(b, func(x, y *route.Route) int {
|
|
return strings.Compare(x.NetString(), y.NetString())
|
|
})
|
|
|
|
return !slices.EqualFunc(a, b, func(x, y *route.Route) bool {
|
|
return x.NetString() == y.NetString()
|
|
})
|
|
}
|
|
|
|
func (n *Notifier) GetInitialRouteRanges() []string {
|
|
initialStrings := n.routesToStrings(n.initialRoutes)
|
|
sort.Strings(initialStrings)
|
|
return n.addIPv6RangeIfNeeded(initialStrings, n.initialRoutes)
|
|
}
|
|
|
|
func (n *Notifier) addIPv6RangeIfNeeded(inputRanges []string, routes []*route.Route) []string {
|
|
for _, r := range routes {
|
|
if r.Network.Addr().Is4() && r.Network.Bits() == 0 {
|
|
return append(slices.Clone(inputRanges), "::/0")
|
|
}
|
|
}
|
|
return inputRanges
|
|
}
|