safing-portmaster/spn/navigator/routing-profiles.go
Daniel Hååvi 80664d1a27
Restructure modules ()
* 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>
2024-08-09 18:15:48 +03:00

162 lines
4.8 KiB
Go

package navigator
import (
"github.com/safing/portmaster/base/log"
"github.com/safing/portmaster/service/profile"
)
// RoutingProfile defines a routing algorithm with some options.
type RoutingProfile struct {
ID string
// Name is the human readable name of the profile.
Name string
// MinHops defines how many hops a route must have at minimum. In order to
// reduce confusion, the Home Hub is also counted.
MinHops int
// MaxHops defines the limit on how many hops a route may have. In order to
// reduce confusion, the Home Hub is also counted.
MaxHops int
// MaxExtraHops sets a limit on how many extra hops are allowed in addition
// to the amount of Hops in the currently best route. This is an optimization
// option and should not interfere with finding the best route, but might
// reduce the amount of routes found.
MaxExtraHops int
// MaxExtraCost sets a limit on the extra cost allowed in addition to the
// cost of the currently best route. This is an optimization option and
// should not interfere with finding the best route, but might reduce the
// amount of routes found.
MaxExtraCost float32
}
// Routing Profile Names.
const (
RoutingProfileHomeID = "home"
RoutingProfileSingleHopID = "single-hop"
RoutingProfileDoubleHopID = "double-hop"
RoutingProfileTripleHopID = "triple-hop"
)
// Routing Profiles.
var (
DefaultRoutingProfileID = profile.DefaultRoutingProfileID
RoutingProfileHome = &RoutingProfile{
ID: "home",
Name: "Plain VPN Mode",
MinHops: 1,
MaxHops: 1,
}
RoutingProfileSingleHop = &RoutingProfile{
ID: "single-hop",
Name: "Speed Focused",
MinHops: 1,
MaxHops: 3,
MaxExtraHops: 1,
MaxExtraCost: 10000,
}
RoutingProfileDoubleHop = &RoutingProfile{
ID: "double-hop",
Name: "Balanced",
MinHops: 2,
MaxHops: 4,
MaxExtraHops: 2,
MaxExtraCost: 10000,
}
RoutingProfileTripleHop = &RoutingProfile{
ID: "triple-hop",
Name: "Privacy Focused",
MinHops: 3,
MaxHops: 5,
MaxExtraHops: 3,
MaxExtraCost: 10000,
}
)
// GetRoutingProfile returns the routing profile with the given ID.
func GetRoutingProfile(id string) *RoutingProfile {
switch id {
case RoutingProfileHomeID:
return RoutingProfileHome
case RoutingProfileSingleHopID:
return RoutingProfileSingleHop
case RoutingProfileDoubleHopID:
return RoutingProfileDoubleHop
case RoutingProfileTripleHopID:
return RoutingProfileTripleHop
default:
return RoutingProfileDoubleHop
}
}
type routeCompliance uint8
const (
routeOk routeCompliance = iota // Route is fully compliant and can be used.
routeNonCompliant // Route is not compliant, but this might change if more hops are added.
routeDisqualified // Route is disqualified and won't be able to become compliant.
)
func (rp *RoutingProfile) checkRouteCompliance(route *Route, foundRoutes *Routes) routeCompliance {
switch {
case len(route.Path) < rp.MinHops:
// Route is shorter than the defined minimum.
return routeNonCompliant
case len(route.Path) > rp.MaxHops:
// Route is longer than the defined maximum.
return routeDisqualified
}
// Check for hub re-use.
if len(route.Path) >= 2 {
lastHop := route.Path[len(route.Path)-1]
for _, hop := range route.Path[:len(route.Path)-1] {
if lastHop.pin.Hub.ID == hop.pin.Hub.ID {
return routeDisqualified
}
}
}
// Check if hub is already in use, if so check if the route matches.
if len(route.Path) >= 2 {
// Get active connection to the last pin of the current path.
lastPinConnection := route.Path[len(route.Path)-1].pin.Connection
switch {
case lastPinConnection == nil:
// Last pin is not yet connected.
case len(lastPinConnection.Route.Path) < 2:
// Path of last pin does not have enough hops.
// This is unexpected and should not happen.
log.Errorf(
"navigator: expected active connection to %s to have 2 hops or more on path, but it had %d",
route.Path[len(route.Path)-1].pin.Hub.StringWithoutLocking(),
len(lastPinConnection.Route.Path),
)
case lastPinConnection.Route.Path[len(lastPinConnection.Route.Path)-2].pin.Hub.ID != route.Path[len(route.Path)-2].pin.Hub.ID:
// The previous hop of the existing route and the one we are evaluating don't match.
// Currently, we only allow one session per Hub.
return routeDisqualified
}
}
// Abort route exploration when we are outside the optimization boundaries.
if len(foundRoutes.All) > 0 {
// Get the best found route.
best := foundRoutes.All[0]
// Abort if current route exceeds max extra costs.
if route.TotalCost > best.TotalCost+rp.MaxExtraCost {
return routeDisqualified
}
// Abort if current route exceeds max extra hops.
if len(route.Path) > len(best.Path)+rp.MaxExtraHops {
return routeDisqualified
}
}
return routeOk
}