130 lines
3.3 KiB
Go
130 lines
3.3 KiB
Go
package navigator
|
|
|
|
import (
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/safing/portbase/config"
|
|
"github.com/safing/portbase/log"
|
|
"github.com/safing/portbase/modules"
|
|
"github.com/safing/portmaster/service/intel/geoip"
|
|
"github.com/safing/portmaster/spn/conf"
|
|
)
|
|
|
|
const (
|
|
// cfgOptionRoutingAlgorithmKey is copied from profile/config.go to avoid import loop.
|
|
cfgOptionRoutingAlgorithmKey = "spn/routingAlgorithm"
|
|
|
|
// cfgOptionRoutingAlgorithmKey is copied from captain/config.go to avoid import loop.
|
|
cfgOptionTrustNodeNodesKey = "spn/trustNodes"
|
|
)
|
|
|
|
var (
|
|
// ErrHomeHubUnset is returned when the Home Hub is required and not set.
|
|
ErrHomeHubUnset = errors.New("map has no Home Hub set")
|
|
|
|
// ErrEmptyMap is returned when the Map is empty.
|
|
ErrEmptyMap = errors.New("map is empty")
|
|
|
|
// ErrHubNotFound is returned when the Hub was not found on the Map.
|
|
ErrHubNotFound = errors.New("hub not found")
|
|
|
|
// ErrAllPinsDisregarded is returned when all pins have been disregarded.
|
|
ErrAllPinsDisregarded = errors.New("all pins have been disregarded")
|
|
)
|
|
|
|
var (
|
|
module *modules.Module
|
|
|
|
// Main is the primary map used.
|
|
Main *Map
|
|
|
|
devMode config.BoolOption
|
|
cfgOptionRoutingAlgorithm config.StringOption
|
|
cfgOptionTrustNodeNodes config.StringArrayOption
|
|
)
|
|
|
|
func init() {
|
|
module = modules.Register("navigator", prep, start, stop, "terminal", "geoip", "netenv")
|
|
}
|
|
|
|
func prep() error {
|
|
return registerAPIEndpoints()
|
|
}
|
|
|
|
func start() error {
|
|
Main = NewMap(conf.MainMapName, true)
|
|
devMode = config.Concurrent.GetAsBool(config.CfgDevModeKey, false)
|
|
cfgOptionRoutingAlgorithm = config.Concurrent.GetAsString(cfgOptionRoutingAlgorithmKey, DefaultRoutingProfileID)
|
|
cfgOptionTrustNodeNodes = config.Concurrent.GetAsStringArray(cfgOptionTrustNodeNodesKey, []string{})
|
|
|
|
err := registerMapDatabase()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Wait for geoip databases to be ready.
|
|
// Try again if not yet ready, as this is critical.
|
|
// The "wait" parameter times out after 1 second.
|
|
// Allow 30 seconds for both databases to load.
|
|
geoInitCheck:
|
|
for i := 0; i < 30; i++ {
|
|
switch {
|
|
case !geoip.IsInitialized(false, true): // First, IPv4.
|
|
case !geoip.IsInitialized(true, true): // Then, IPv6.
|
|
default:
|
|
break geoInitCheck
|
|
}
|
|
}
|
|
|
|
err = Main.InitializeFromDatabase()
|
|
if err != nil {
|
|
// Wait for three seconds, then try again.
|
|
time.Sleep(3 * time.Second)
|
|
err = Main.InitializeFromDatabase()
|
|
if err != nil {
|
|
// Even if the init fails, we can try to start without it and get data along the way.
|
|
log.Warningf("spn/navigator: %s", err)
|
|
}
|
|
}
|
|
err = Main.RegisterHubUpdateHook()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// TODO: delete superseded hubs after x amount of time
|
|
|
|
module.NewTask("update states", Main.updateStates).
|
|
Repeat(1 * time.Hour).
|
|
Schedule(time.Now().Add(3 * time.Minute))
|
|
|
|
module.NewTask("update failing states", Main.updateFailingStates).
|
|
Repeat(1 * time.Minute).
|
|
Schedule(time.Now().Add(3 * time.Minute))
|
|
|
|
if conf.PublicHub() {
|
|
// Only measure Hubs on public Hubs.
|
|
module.NewTask("measure hubs", Main.measureHubs).
|
|
Repeat(5 * time.Minute).
|
|
Schedule(time.Now().Add(1 * time.Minute))
|
|
|
|
// Only register metrics on Hubs, as they only make sense there.
|
|
err := registerMetrics()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func stop() error {
|
|
withdrawMapDatabase()
|
|
|
|
Main.CancelHubUpdateHook()
|
|
Main.SaveMeasuredHubs()
|
|
Main.Close()
|
|
|
|
return nil
|
|
}
|