2024-05-07 18:50:34 +02:00
|
|
|
//go:build !ios && !android
|
|
|
|
|
|
|
|
package networkmonitor
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
2024-05-17 09:43:18 +02:00
|
|
|
"fmt"
|
2024-05-07 18:50:34 +02:00
|
|
|
"net"
|
|
|
|
"net/netip"
|
|
|
|
"runtime/debug"
|
|
|
|
|
|
|
|
"github.com/cenkalti/backoff/v4"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
|
|
|
|
"github.com/netbirdio/netbird/client/internal/routemanager"
|
|
|
|
)
|
|
|
|
|
2024-05-17 09:43:18 +02:00
|
|
|
// Start begins monitoring network changes. When a change is detected, it calls the callback asynchronously and returns.
|
|
|
|
func (nw *NetworkMonitor) Start(ctx context.Context, callback func()) (err error) {
|
2024-05-07 18:50:34 +02:00
|
|
|
if ctx.Err() != nil {
|
2024-05-17 09:43:18 +02:00
|
|
|
return ctx.Err()
|
2024-05-07 18:50:34 +02:00
|
|
|
}
|
|
|
|
|
2024-05-17 09:43:18 +02:00
|
|
|
nw.mu.Lock()
|
2024-05-07 18:50:34 +02:00
|
|
|
ctx, nw.cancel = context.WithCancel(ctx)
|
2024-05-17 09:43:18 +02:00
|
|
|
nw.mu.Unlock()
|
|
|
|
|
|
|
|
nw.wg.Add(1)
|
|
|
|
defer nw.wg.Done()
|
2024-05-07 18:50:34 +02:00
|
|
|
|
|
|
|
var nexthop4, nexthop6 netip.Addr
|
|
|
|
var intf4, intf6 *net.Interface
|
|
|
|
|
|
|
|
operation := func() error {
|
|
|
|
var errv4, errv6 error
|
|
|
|
nexthop4, intf4, errv4 = routemanager.GetNextHop(netip.IPv4Unspecified())
|
|
|
|
nexthop6, intf6, errv6 = routemanager.GetNextHop(netip.IPv6Unspecified())
|
|
|
|
|
|
|
|
if errv4 != nil && errv6 != nil {
|
|
|
|
return errors.New("failed to get default next hops")
|
|
|
|
}
|
|
|
|
|
|
|
|
if errv4 == nil {
|
|
|
|
log.Debugf("Network monitor: IPv4 default route: %s, interface: %s", nexthop4, intf4.Name)
|
|
|
|
}
|
|
|
|
if errv6 == nil {
|
|
|
|
log.Debugf("Network monitor: IPv6 default route: %s, interface: %s", nexthop6, intf6.Name)
|
|
|
|
}
|
|
|
|
|
|
|
|
// continue if either route was found
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
expBackOff := backoff.WithContext(backoff.NewExponentialBackOff(), ctx)
|
|
|
|
|
|
|
|
if err := backoff.Retry(operation, expBackOff); err != nil {
|
2024-05-17 09:43:18 +02:00
|
|
|
return fmt.Errorf("failed to get default next hops: %w", err)
|
2024-05-07 18:50:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// recover in case sys ops panic
|
|
|
|
defer func() {
|
|
|
|
if r := recover(); r != nil {
|
2024-05-17 09:43:18 +02:00
|
|
|
err = fmt.Errorf("panic occurred: %v, stack trace: %s", r, string(debug.Stack()))
|
2024-05-07 18:50:34 +02:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2024-05-17 09:43:18 +02:00
|
|
|
if err := checkChange(ctx, nexthop4, intf4, nexthop6, intf6, callback); err != nil {
|
|
|
|
return fmt.Errorf("check change: %w", err)
|
2024-05-07 18:50:34 +02:00
|
|
|
}
|
2024-05-17 09:43:18 +02:00
|
|
|
|
|
|
|
return nil
|
2024-05-07 18:50:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Stop stops the network monitor.
|
2024-05-17 09:43:18 +02:00
|
|
|
func (nw *NetworkMonitor) Stop() {
|
|
|
|
nw.mu.Lock()
|
|
|
|
defer nw.mu.Unlock()
|
|
|
|
|
2024-05-07 18:50:34 +02:00
|
|
|
if nw.cancel != nil {
|
|
|
|
nw.cancel()
|
2024-05-17 09:43:18 +02:00
|
|
|
nw.wg.Wait()
|
2024-05-07 18:50:34 +02:00
|
|
|
}
|
|
|
|
}
|