mirror of
https://github.com/safing/portmaster
synced 2025-04-23 12: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>
162 lines
4.8 KiB
Go
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
|
|
}
|