safing-portmaster/spn/captain/config.go
Daniel Hååvi 80664d1a27
Restructure modules (#1572)
* 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

273 lines
10 KiB
Go

package captain
import (
"sync"
"github.com/safing/portmaster/base/config"
"github.com/safing/portmaster/service/profile"
"github.com/safing/portmaster/service/profile/endpoints"
"github.com/safing/portmaster/spn/conf"
"github.com/safing/portmaster/spn/navigator"
)
var (
// CfgOptionEnableSPNKey is the configuration key for the SPN module.
CfgOptionEnableSPNKey = "spn/enable"
cfgOptionEnableSPNOrder = 128
// CfgOptionHomeHubPolicyKey is the configuration key for the SPN home policy.
CfgOptionHomeHubPolicyKey = "spn/homePolicy"
cfgOptionHomeHubPolicy config.StringArrayOption
cfgOptionHomeHubPolicyOrder = 145
// CfgOptionDNSExitHubPolicyKey is the configuration key for the SPN DNS exit policy.
CfgOptionDNSExitHubPolicyKey = "spn/dnsExitPolicy"
cfgOptionDNSExitHubPolicy config.StringArrayOption
cfgOptionDNSExitHubPolicyOrder = 148
// CfgOptionUseCommunityNodesKey is the configuration key for whether to use community nodes.
CfgOptionUseCommunityNodesKey = "spn/useCommunityNodes"
cfgOptionUseCommunityNodes config.BoolOption
cfgOptionUseCommunityNodesOrder = 149
// NonCommunityVerifiedOwners holds a list of verified owners that are not
// considered "community".
NonCommunityVerifiedOwners = []string{"Safing"}
// CfgOptionTrustNodeNodesKey is the configuration key for whether additional trusted nodes.
CfgOptionTrustNodeNodesKey = "spn/trustNodes"
cfgOptionTrustNodeNodes config.StringArrayOption
cfgOptionTrustNodeNodesOrder = 150
// Special Access Code.
cfgOptionSpecialAccessCodeKey = "spn/specialAccessCode"
cfgOptionSpecialAccessCodeDefault = "none"
cfgOptionSpecialAccessCode config.StringOption //nolint:unused // Linter, you drunk?
cfgOptionSpecialAccessCodeOrder = 160
// IPv6 must be global and accessible.
cfgOptionBindToAdvertisedKey = "spn/publicHub/bindToAdvertised"
cfgOptionBindToAdvertised config.BoolOption
cfgOptionBindToAdvertisedDefault = false
cfgOptionBindToAdvertisedOrder = 161
// Config options for use.
cfgOptionRoutingAlgorithm config.StringOption
)
func prepConfig() error {
// Register spn module setting.
err := config.Register(&config.Option{
Name: "SPN Module",
Key: CfgOptionEnableSPNKey,
Description: "Start the Safing Privacy Network module. If turned off, the SPN is fully disabled on this device.",
OptType: config.OptTypeBool,
DefaultValue: false,
Annotations: config.Annotations{
config.DisplayOrderAnnotation: cfgOptionEnableSPNOrder,
config.CategoryAnnotation: "General",
},
})
if err != nil {
return err
}
// Home Node Rules
err = config.Register(&config.Option{
Name: "Home Node Rules",
Key: CfgOptionHomeHubPolicyKey,
Description: `Customize which countries should or should not be used for your Home Node. The Home Node is your entry into the SPN. You connect directly to it and all your connections are routed through it.
By default, the Portmaster tries to choose the nearest node as your Home Node in order to reduce your exposure to the open Internet.
Reconnect to the SPN in order to apply new rules.`,
Help: profile.SPNRulesHelp,
Sensitive: true,
OptType: config.OptTypeStringArray,
RequiresRestart: true,
ExpertiseLevel: config.ExpertiseLevelExpert,
DefaultValue: []string{},
Annotations: config.Annotations{
config.CategoryAnnotation: "Routing",
config.DisplayOrderAnnotation: cfgOptionHomeHubPolicyOrder,
config.DisplayHintAnnotation: endpoints.DisplayHintEndpointList,
config.QuickSettingsAnnotation: profile.SPNRulesQuickSettings,
endpoints.EndpointListVerdictNamesAnnotation: profile.SPNRulesVerdictNames,
},
ValidationRegex: endpoints.ListEntryValidationRegex,
ValidationFunc: endpoints.ValidateEndpointListConfigOption,
})
if err != nil {
return err
}
cfgOptionHomeHubPolicy = config.Concurrent.GetAsStringArray(CfgOptionHomeHubPolicyKey, []string{})
// DNS Exit Node Rules
err = config.Register(&config.Option{
Name: "DNS Exit Node Rules",
Key: CfgOptionDNSExitHubPolicyKey,
Description: `Customize which countries should or should not be used as DNS Exit Nodes.
By default, the Portmaster will exit DNS requests directly at your Home Node in order to keep them fast and close to your location. This is important, as DNS resolution often takes your approximate location into account when deciding which optimized DNS records are returned to you. As the Portmaster encrypts your DNS requests by default, you effectively gain a two-hop security level for your DNS requests in order to protect your privacy.
This setting mainly exists for when you need to simulate your presence in another location on a lower level too. This might be necessary to defeat more intelligent geo-blocking systems.`,
Help: profile.SPNRulesHelp,
Sensitive: true,
OptType: config.OptTypeStringArray,
RequiresRestart: true,
ExpertiseLevel: config.ExpertiseLevelExpert,
DefaultValue: []string{},
Annotations: config.Annotations{
config.CategoryAnnotation: "Routing",
config.DisplayOrderAnnotation: cfgOptionDNSExitHubPolicyOrder,
config.DisplayHintAnnotation: endpoints.DisplayHintEndpointList,
config.QuickSettingsAnnotation: profile.SPNRulesQuickSettings,
endpoints.EndpointListVerdictNamesAnnotation: profile.SPNRulesVerdictNames,
},
ValidationRegex: endpoints.ListEntryValidationRegex,
ValidationFunc: endpoints.ValidateEndpointListConfigOption,
})
if err != nil {
return err
}
cfgOptionDNSExitHubPolicy = config.Concurrent.GetAsStringArray(CfgOptionDNSExitHubPolicyKey, []string{})
err = config.Register(&config.Option{
Name: "Use Community Nodes",
Key: CfgOptionUseCommunityNodesKey,
Description: "Use nodes (servers) not operated by Safing themselves. The use of community nodes is recommended as it diversifies the ownership of the nodes you use for your connections and further strengthens your privacy. Plain connections (eg. http, smtp, ...) will never exit via community nodes, making this setting safe to use.",
Sensitive: true,
OptType: config.OptTypeBool,
RequiresRestart: true,
DefaultValue: true,
Annotations: config.Annotations{
config.DisplayOrderAnnotation: cfgOptionUseCommunityNodesOrder,
config.CategoryAnnotation: "Routing",
},
})
if err != nil {
return err
}
cfgOptionUseCommunityNodes = config.Concurrent.GetAsBool(CfgOptionUseCommunityNodesKey, true)
err = config.Register(&config.Option{
Name: "Trust Nodes",
Key: CfgOptionTrustNodeNodesKey,
Description: "Specify which community nodes to additionally trust. These nodes may then also be used as a Home Node, as well as an Exit Node for unencrypted connections.",
Help: "You can specify nodes by their ID or their verified operator.",
Sensitive: true,
OptType: config.OptTypeStringArray,
ExpertiseLevel: config.ExpertiseLevelExpert,
DefaultValue: []string{},
Annotations: config.Annotations{
config.DisplayOrderAnnotation: cfgOptionTrustNodeNodesOrder,
config.CategoryAnnotation: "Routing",
},
})
if err != nil {
return err
}
cfgOptionTrustNodeNodes = config.Concurrent.GetAsStringArray(CfgOptionTrustNodeNodesKey, []string{})
err = config.Register(&config.Option{
Name: "Special Access Code",
Key: cfgOptionSpecialAccessCodeKey,
Description: "Special Access Codes grant access to the SPN for testing or evaluation purposes.",
Sensitive: true,
OptType: config.OptTypeString,
DefaultValue: cfgOptionSpecialAccessCodeDefault,
Annotations: config.Annotations{
config.DisplayOrderAnnotation: cfgOptionSpecialAccessCodeOrder,
config.CategoryAnnotation: "Advanced",
},
})
if err != nil {
return err
}
cfgOptionSpecialAccessCode = config.Concurrent.GetAsString(cfgOptionSpecialAccessCodeKey, "")
if conf.PublicHub() {
err = config.Register(&config.Option{
Name: "Connect From Advertised IPs Only",
Key: cfgOptionBindToAdvertisedKey,
Description: "Only connect from (bind to) the advertised IP addresses.",
OptType: config.OptTypeBool,
ExpertiseLevel: config.ExpertiseLevelExpert,
DefaultValue: cfgOptionBindToAdvertisedDefault,
RequiresRestart: true,
Annotations: config.Annotations{
config.DisplayOrderAnnotation: cfgOptionBindToAdvertisedOrder,
},
})
if err != nil {
return err
}
cfgOptionBindToAdvertised = config.GetAsBool(cfgOptionBindToAdvertisedKey, cfgOptionBindToAdvertisedDefault)
}
// Config options for use.
if conf.Integrated() {
cfgOptionRoutingAlgorithm = config.Concurrent.GetAsString(profile.CfgOptionRoutingAlgorithmKey, navigator.DefaultRoutingProfileID)
} else {
cfgOptionRoutingAlgorithm = func() string { return navigator.DefaultRoutingProfileID }
}
return nil
}
var (
homeHubPolicy endpoints.Endpoints
homeHubPolicyLock sync.Mutex
homeHubPolicyConfigFlag = config.NewValidityFlag()
)
func getHomeHubPolicy() (endpoints.Endpoints, error) {
homeHubPolicyLock.Lock()
defer homeHubPolicyLock.Unlock()
// Return cached value if config is still valid.
if homeHubPolicyConfigFlag.IsValid() {
return homeHubPolicy, nil
}
homeHubPolicyConfigFlag.Refresh()
// Parse new policy.
policy, err := endpoints.ParseEndpoints(cfgOptionHomeHubPolicy())
if err != nil {
homeHubPolicy = nil
return nil, err
}
// Save and return the new policy.
homeHubPolicy = policy
return homeHubPolicy, nil
}
var (
dnsExitHubPolicy endpoints.Endpoints
dnsExitHubPolicyLock sync.Mutex
dnsExitHubPolicyConfigFlag = config.NewValidityFlag()
)
// GetDNSExitHubPolicy return the current DNS exit policy.
func GetDNSExitHubPolicy() (endpoints.Endpoints, error) {
dnsExitHubPolicyLock.Lock()
defer dnsExitHubPolicyLock.Unlock()
// Return cached value if config is still valid.
if dnsExitHubPolicyConfigFlag.IsValid() {
return dnsExitHubPolicy, nil
}
dnsExitHubPolicyConfigFlag.Refresh()
// Parse new policy.
policy, err := endpoints.ParseEndpoints(cfgOptionDNSExitHubPolicy())
if err != nil {
dnsExitHubPolicy = nil
return nil, err
}
// Save and return the new policy.
dnsExitHubPolicy = policy
return dnsExitHubPolicy, nil
}