mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-16 15:26:40 +00:00
- Connect on daemon start only if the file existed before - fixed a bug that happened when the default profile config was removed, which would recreate it and reset the active profile to the default.
149 lines
3.0 KiB
Go
149 lines
3.0 KiB
Go
//go:build darwin && !ios
|
|
|
|
package networkmonitor
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"hash/fnv"
|
|
"os/exec"
|
|
"time"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
"golang.org/x/sys/unix"
|
|
|
|
"github.com/netbirdio/netbird/client/internal/routemanager/systemops"
|
|
)
|
|
|
|
// todo: refactor to not use static functions
|
|
|
|
func checkChange(ctx context.Context, nexthopv4, nexthopv6 systemops.Nexthop) error {
|
|
fd, err := prepareFd()
|
|
if err != nil {
|
|
return fmt.Errorf("open routing socket: %v", err)
|
|
}
|
|
|
|
defer func() {
|
|
if err := unix.Close(fd); err != nil {
|
|
if !errors.Is(err, unix.EBADF) {
|
|
log.Warnf("Network monitor: failed to close routing socket: %v", err)
|
|
}
|
|
}
|
|
}()
|
|
|
|
routeChanged := make(chan struct{})
|
|
go func() {
|
|
_ = routeCheck(ctx, fd, nexthopv4, nexthopv6)
|
|
close(routeChanged)
|
|
}()
|
|
|
|
wakeUp := make(chan struct{})
|
|
go func() {
|
|
wakeUpListen(ctx)
|
|
close(wakeUp)
|
|
}()
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
case <-routeChanged:
|
|
if ctx.Err() != nil {
|
|
return ctx.Err()
|
|
}
|
|
log.Infof("route change detected")
|
|
return nil
|
|
case <-wakeUp:
|
|
if ctx.Err() != nil {
|
|
return ctx.Err()
|
|
}
|
|
log.Infof("wakeup detected")
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func wakeUpListen(ctx context.Context) {
|
|
log.Infof("start to watch for system wakeups")
|
|
var (
|
|
initialHash uint32
|
|
err error
|
|
)
|
|
|
|
// Keep retrying until initial sysctl succeeds or context is canceled
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
log.Info("exit from wakeUpListen initial hash detection due to context cancellation")
|
|
return
|
|
default:
|
|
initialHash, err = readSleepTimeHash()
|
|
if err != nil {
|
|
log.Errorf("failed to detect initial sleep time: %v", err)
|
|
select {
|
|
case <-ctx.Done():
|
|
log.Info("exit from wakeUpListen initial hash detection due to context cancellation")
|
|
return
|
|
case <-time.After(3 * time.Second):
|
|
continue
|
|
}
|
|
}
|
|
log.Debugf("initial wakeup hash: %d", initialHash)
|
|
break
|
|
}
|
|
break
|
|
}
|
|
|
|
ticker := time.NewTicker(5 * time.Second)
|
|
defer ticker.Stop()
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
log.Info("context canceled, stopping wakeUpListen")
|
|
return
|
|
|
|
case <-ticker.C:
|
|
newHash, err := readSleepTimeHash()
|
|
if err != nil {
|
|
log.Errorf("failed to read sleep time hash: %v", err)
|
|
continue
|
|
}
|
|
|
|
if newHash == initialHash {
|
|
continue
|
|
}
|
|
|
|
upOut, err := exec.Command("uptime").Output()
|
|
if err != nil {
|
|
log.Errorf("failed to run uptime command: %v", err)
|
|
upOut = []byte("unknown")
|
|
}
|
|
log.Infof("Wakeup detected: %d -> %d, uptime: %s", initialHash, newHash, upOut)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func readSleepTimeHash() (uint32, error) {
|
|
cmd := exec.Command("sysctl", "kern.sleeptime")
|
|
out, err := cmd.Output()
|
|
if err != nil {
|
|
return 0, fmt.Errorf("failed to run sysctl: %w", err)
|
|
}
|
|
|
|
h, err := hash(out)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("failed to compute hash: %w", err)
|
|
}
|
|
|
|
return h, nil
|
|
}
|
|
|
|
func hash(data []byte) (uint32, error) {
|
|
hasher := fnv.New32a() // Create a new 32-bit FNV-1a hasher
|
|
if _, err := hasher.Write(data); err != nil {
|
|
return 0, err
|
|
}
|
|
return hasher.Sum32(), nil
|
|
}
|