254 lines
9.6 KiB
Go
254 lines
9.6 KiB
Go
package captain
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/safing/portbase/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 {
|
|
// 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.
|
|
cfgOptionRoutingAlgorithm = config.Concurrent.GetAsString(profile.CfgOptionRoutingAlgorithmKey, 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
|
|
}
|