2024-07-15 10:40:57 +02:00
|
|
|
package notifier
|
2023-05-31 18:25:24 +02:00
|
|
|
|
|
|
|
import (
|
2024-07-15 10:40:57 +02:00
|
|
|
"net/netip"
|
2024-05-10 10:47:16 +02:00
|
|
|
"runtime"
|
2023-05-31 18:25:24 +02:00
|
|
|
"sort"
|
2023-12-18 11:46:58 +01:00
|
|
|
"strings"
|
2023-05-31 18:25:24 +02:00
|
|
|
"sync"
|
|
|
|
|
2023-11-02 19:04:33 +01:00
|
|
|
"github.com/netbirdio/netbird/client/internal/listener"
|
2023-05-31 18:25:24 +02:00
|
|
|
"github.com/netbirdio/netbird/route"
|
|
|
|
)
|
|
|
|
|
2024-07-15 10:40:57 +02:00
|
|
|
type Notifier struct {
|
2024-05-07 12:28:30 +02:00
|
|
|
initialRouteRanges []string
|
|
|
|
routeRanges []string
|
2023-05-31 18:25:24 +02:00
|
|
|
|
2023-11-02 19:04:33 +01:00
|
|
|
listener listener.NetworkChangeListener
|
|
|
|
listenerMux sync.Mutex
|
2023-05-31 18:25:24 +02:00
|
|
|
}
|
|
|
|
|
2024-07-15 10:40:57 +02:00
|
|
|
func NewNotifier() *Notifier {
|
|
|
|
return &Notifier{}
|
2023-05-31 18:25:24 +02:00
|
|
|
}
|
|
|
|
|
2024-07-15 10:40:57 +02:00
|
|
|
func (n *Notifier) SetListener(listener listener.NetworkChangeListener) {
|
2023-11-02 19:04:33 +01:00
|
|
|
n.listenerMux.Lock()
|
|
|
|
defer n.listenerMux.Unlock()
|
|
|
|
n.listener = listener
|
2023-05-31 18:25:24 +02:00
|
|
|
}
|
|
|
|
|
2024-07-15 10:40:57 +02:00
|
|
|
func (n *Notifier) SetInitialClientRoutes(clientRoutes []*route.Route) {
|
2023-05-31 18:25:24 +02:00
|
|
|
nets := make([]string, 0)
|
|
|
|
for _, r := range clientRoutes {
|
|
|
|
nets = append(nets, r.Network.String())
|
|
|
|
}
|
|
|
|
sort.Strings(nets)
|
2024-05-07 12:28:30 +02:00
|
|
|
n.initialRouteRanges = nets
|
2023-05-31 18:25:24 +02:00
|
|
|
}
|
|
|
|
|
2024-07-15 10:40:57 +02:00
|
|
|
func (n *Notifier) OnNewRoutes(idMap route.HAMap) {
|
|
|
|
if runtime.GOOS != "android" {
|
|
|
|
return
|
|
|
|
}
|
2023-05-31 18:25:24 +02:00
|
|
|
newNets := make([]string, 0)
|
|
|
|
for _, routes := range idMap {
|
|
|
|
for _, r := range routes {
|
|
|
|
newNets = append(newNets, r.Network.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Strings(newNets)
|
2024-05-10 10:47:16 +02:00
|
|
|
switch runtime.GOOS {
|
|
|
|
case "android":
|
|
|
|
if !n.hasDiff(n.initialRouteRanges, newNets) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
if !n.hasDiff(n.routeRanges, newNets) {
|
|
|
|
return
|
|
|
|
}
|
2023-05-31 18:25:24 +02:00
|
|
|
}
|
|
|
|
|
2024-05-07 12:28:30 +02:00
|
|
|
n.routeRanges = newNets
|
2023-05-31 18:25:24 +02:00
|
|
|
|
|
|
|
n.notify()
|
|
|
|
}
|
|
|
|
|
2024-07-15 10:40:57 +02:00
|
|
|
func (n *Notifier) OnNewPrefixes(prefixes []netip.Prefix) {
|
|
|
|
newNets := make([]string, 0)
|
|
|
|
for _, prefix := range prefixes {
|
|
|
|
newNets = append(newNets, prefix.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Strings(newNets)
|
|
|
|
switch runtime.GOOS {
|
|
|
|
case "android":
|
|
|
|
if !n.hasDiff(n.initialRouteRanges, newNets) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
if !n.hasDiff(n.routeRanges, newNets) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
n.routeRanges = newNets
|
|
|
|
|
|
|
|
n.notify()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Notifier) notify() {
|
2023-11-02 19:04:33 +01:00
|
|
|
n.listenerMux.Lock()
|
|
|
|
defer n.listenerMux.Unlock()
|
|
|
|
if n.listener == nil {
|
2023-05-31 18:25:24 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-11-02 19:04:33 +01:00
|
|
|
go func(l listener.NetworkChangeListener) {
|
2024-05-07 12:28:30 +02:00
|
|
|
l.OnNetworkChanged(strings.Join(addIPv6RangeIfNeeded(n.routeRanges), ","))
|
2023-11-02 19:04:33 +01:00
|
|
|
}(n.listener)
|
2023-05-31 18:25:24 +02:00
|
|
|
}
|
|
|
|
|
2024-07-15 10:40:57 +02:00
|
|
|
func (n *Notifier) hasDiff(a []string, b []string) bool {
|
2023-05-31 18:25:24 +02:00
|
|
|
if len(a) != len(b) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
for i, v := range a {
|
|
|
|
if v != b[i] {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2023-06-12 14:43:55 +02:00
|
|
|
|
2024-07-15 10:40:57 +02:00
|
|
|
func (n *Notifier) GetInitialRouteRanges() []string {
|
2024-05-07 12:28:30 +02:00
|
|
|
return addIPv6RangeIfNeeded(n.initialRouteRanges)
|
|
|
|
}
|
|
|
|
|
|
|
|
// addIPv6RangeIfNeeded returns the input ranges with the default IPv6 range when there is an IPv4 default route.
|
|
|
|
func addIPv6RangeIfNeeded(inputRanges []string) []string {
|
|
|
|
ranges := inputRanges
|
|
|
|
for _, r := range inputRanges {
|
|
|
|
// we are intentionally adding the ipv6 default range in case of ipv4 default range
|
|
|
|
// to ensure that all traffic is managed by the tunnel interface on android
|
|
|
|
if r == "0.0.0.0/0" {
|
|
|
|
ranges = append(ranges, "::/0")
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ranges
|
2023-06-12 14:43:55 +02:00
|
|
|
}
|