mirror of
https://github.com/safing/portmaster
synced 2025-04-25 13:29:10 +00:00
* Move portbase into monorepo * Add new simple module mgr * [WIP] Switch to new simple module mgr * Add StateMgr and more worker variants * [WIP] Switch more modules * [WIP] Switch more modules * [WIP] swtich more modules * [WIP] switch all SPN modules * [WIP] switch all service modules * [WIP] Convert all workers to the new module system * [WIP] add new task system to module manager * [WIP] Add second take for scheduling workers * [WIP] Add FIXME for bugs in new scheduler * [WIP] Add minor improvements to scheduler * [WIP] Add new worker scheduler * [WIP] Fix more bug related to new module system * [WIP] Fix start handing of the new module system * [WIP] Improve startup process * [WIP] Fix minor issues * [WIP] Fix missing subsystem in settings * [WIP] Initialize managers in constructor * [WIP] Move module event initialization to constrictors * [WIP] Fix setting for enabling and disabling the SPN module * [WIP] Move API registeration into module construction * [WIP] Update states mgr for all modules * [WIP] Add CmdLine operation support * Add state helper methods to module group and instance * Add notification and module status handling to status package * Fix starting issues * Remove pilot widget and update security lock to new status data * Remove debug logs * Improve http server shutdown * Add workaround for cleanly shutting down firewall+netquery * Improve logging * Add syncing states with notifications for new module system * Improve starting, stopping, shutdown; resolve FIXMEs/TODOs * [WIP] Fix most unit tests * Review new module system and fix minor issues * Push shutdown and restart events again via API * Set sleep mode via interface * Update example/template module * [WIP] Fix spn/cabin unit test * Remove deprecated UI elements * Make log output more similar for the logging transition phase * Switch spn hub and observer cmds to new module system * Fix log sources * Make worker mgr less error prone * Fix tests and minor issues * Fix observation hub * Improve shutdown and restart handling * Split up big connection.go source file * Move varint and dsd packages to structures repo * Improve expansion test * Fix linter warnings * Fix interception module on windows * Fix linter errors --------- Co-authored-by: Vladimir Stoilov <vladimir@safing.io>
231 lines
5.5 KiB
Go
231 lines
5.5 KiB
Go
package navigator
|
|
|
|
import (
|
|
"context"
|
|
"math"
|
|
|
|
"github.com/safing/portmaster/base/log"
|
|
"github.com/safing/portmaster/service/profile/endpoints"
|
|
"github.com/safing/portmaster/spn/hub"
|
|
)
|
|
|
|
const (
|
|
defaultRegionalMinLanesPerHub = 0.5
|
|
defaultRegionalMaxLanesOnHub = 2
|
|
defaultSatelliteMinLanesPerHub = 0.3
|
|
defaultInternalMinLanesOnHub = 3
|
|
defaultInternalMaxHops = 3
|
|
)
|
|
|
|
// Region specifies a group of Hubs for optimization purposes.
|
|
type Region struct {
|
|
ID string
|
|
Name string
|
|
config *hub.RegionConfig
|
|
memberPolicy endpoints.Endpoints
|
|
|
|
pins []*Pin
|
|
regardedPins []*Pin
|
|
|
|
regionalMinLanes int
|
|
regionalMaxLanesOnHub int
|
|
satelliteMinLanes int
|
|
internalMinLanesOnHub int
|
|
internalMaxHops int
|
|
}
|
|
|
|
func (region *Region) getName() string {
|
|
switch {
|
|
case region == nil:
|
|
return "-"
|
|
case region.Name != "":
|
|
return region.Name
|
|
default:
|
|
return region.ID
|
|
}
|
|
}
|
|
|
|
func (m *Map) updateRegions(config []*hub.RegionConfig) {
|
|
// Reset map and pins.
|
|
m.regions = make([]*Region, 0, len(config))
|
|
for _, pin := range m.all {
|
|
pin.region = nil
|
|
}
|
|
|
|
// Stop if not regions are defined.
|
|
if len(config) == 0 {
|
|
return
|
|
}
|
|
|
|
// Build regions from config.
|
|
for _, regionConfig := range config {
|
|
// Check if region has an ID.
|
|
if regionConfig.ID == "" {
|
|
log.Error("spn/navigator: region is missing ID")
|
|
// Abort adding this region to the map.
|
|
continue
|
|
}
|
|
|
|
// Create new region.
|
|
region := &Region{
|
|
ID: regionConfig.ID,
|
|
Name: regionConfig.Name,
|
|
config: regionConfig,
|
|
}
|
|
|
|
// Parse member policy.
|
|
if len(regionConfig.MemberPolicy) == 0 {
|
|
log.Errorf("spn/navigator: member policy of region %s is missing", region.ID)
|
|
// Abort adding this region to the map.
|
|
continue
|
|
}
|
|
memberPolicy, err := endpoints.ParseEndpoints(regionConfig.MemberPolicy)
|
|
if err != nil {
|
|
log.Errorf("spn/navigator: failed to parse member policy of region %s: %s", region.ID, err)
|
|
// Abort adding this region to the map.
|
|
continue
|
|
}
|
|
region.memberPolicy = memberPolicy
|
|
|
|
// Recalculate region properties.
|
|
region.recalculateProperties()
|
|
|
|
// Add region to map.
|
|
m.regions = append(m.regions, region)
|
|
}
|
|
|
|
// Update region in all Pins.
|
|
for _, pin := range m.all {
|
|
m.updatePinRegion(pin)
|
|
}
|
|
}
|
|
|
|
func (region *Region) addPin(pin *Pin) {
|
|
// Find pin in region.
|
|
for _, regionPin := range region.pins {
|
|
if pin.Hub.ID == regionPin.Hub.ID {
|
|
// Pin is already part of region.
|
|
return
|
|
}
|
|
}
|
|
|
|
// Check if pin is already part of this region.
|
|
if pin.region != nil && pin.region.ID == region.ID {
|
|
return
|
|
}
|
|
|
|
// Remove pin from previous region.
|
|
if pin.region != nil {
|
|
pin.region.removePin(pin)
|
|
}
|
|
|
|
// Add new pin to region.
|
|
region.pins = append(region.pins, pin)
|
|
pin.region = region
|
|
|
|
// Recalculate region properties.
|
|
region.recalculateProperties()
|
|
}
|
|
|
|
func (region *Region) removePin(pin *Pin) {
|
|
// Find pin index in region.
|
|
removeIndex := -1
|
|
for index, regionPin := range region.pins {
|
|
if pin.Hub.ID == regionPin.Hub.ID {
|
|
removeIndex = index
|
|
break
|
|
}
|
|
}
|
|
if removeIndex < 0 {
|
|
// Pin is not part of region.
|
|
return
|
|
}
|
|
|
|
// Remove pin from region.
|
|
region.pins = append(region.pins[:removeIndex], region.pins[removeIndex+1:]...)
|
|
|
|
// Recalculate region properties.
|
|
region.recalculateProperties()
|
|
}
|
|
|
|
func (region *Region) recalculateProperties() {
|
|
// Regional properties.
|
|
region.regionalMinLanes = calculateMinLanes(
|
|
len(region.pins),
|
|
region.config.RegionalMinLanes,
|
|
region.config.RegionalMinLanesPerHub,
|
|
defaultRegionalMinLanesPerHub,
|
|
)
|
|
region.regionalMaxLanesOnHub = region.config.RegionalMaxLanesOnHub
|
|
if region.regionalMaxLanesOnHub <= 0 {
|
|
region.regionalMaxLanesOnHub = defaultRegionalMaxLanesOnHub
|
|
}
|
|
|
|
// Satellite properties.
|
|
region.satelliteMinLanes = calculateMinLanes(
|
|
len(region.pins),
|
|
region.config.SatelliteMinLanes,
|
|
region.config.SatelliteMinLanesPerHub,
|
|
defaultSatelliteMinLanesPerHub,
|
|
)
|
|
|
|
// Internal properties.
|
|
region.internalMinLanesOnHub = region.config.InternalMinLanesOnHub
|
|
if region.internalMinLanesOnHub <= 0 {
|
|
region.internalMinLanesOnHub = defaultInternalMinLanesOnHub
|
|
}
|
|
region.internalMaxHops = region.config.InternalMaxHops
|
|
if region.internalMaxHops <= 0 {
|
|
region.internalMaxHops = defaultInternalMaxHops
|
|
}
|
|
// Values below 2 do not make any sense for max hops.
|
|
if region.internalMaxHops < 2 {
|
|
region.internalMaxHops = 2
|
|
}
|
|
}
|
|
|
|
func calculateMinLanes(regionHubCount, minLanes int, minLanesPerHub, defaultMinLanesPerHub float64) (minLaneCount int) {
|
|
// Validate hub count.
|
|
if regionHubCount <= 0 {
|
|
// Reset to safe value.
|
|
regionHubCount = 1
|
|
}
|
|
|
|
// Set to configured minimum lanes.
|
|
minLaneCount = minLanes
|
|
|
|
// Raise to configured minimum lanes per Hub.
|
|
if minLanesPerHub != 0 {
|
|
minLanesFromSize := int(math.Ceil(float64(regionHubCount) * minLanesPerHub))
|
|
if minLanesFromSize > minLaneCount {
|
|
minLaneCount = minLanesFromSize
|
|
}
|
|
}
|
|
|
|
// Raise to default minimum lanes per Hub, if still 0.
|
|
if minLaneCount <= 0 {
|
|
minLaneCount = int(math.Ceil(float64(regionHubCount) * defaultMinLanesPerHub))
|
|
}
|
|
|
|
return minLaneCount
|
|
}
|
|
|
|
func (m *Map) updatePinRegion(pin *Pin) {
|
|
for _, region := range m.regions {
|
|
// Check if pin matches the region's member policy.
|
|
if pin.EntityV4 != nil {
|
|
result, _ := region.memberPolicy.Match(context.TODO(), pin.EntityV4)
|
|
if result == endpoints.Permitted {
|
|
region.addPin(pin)
|
|
return
|
|
}
|
|
}
|
|
if pin.EntityV6 != nil {
|
|
result, _ := region.memberPolicy.Match(context.TODO(), pin.EntityV6)
|
|
if result == endpoints.Permitted {
|
|
region.addPin(pin)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|