Merge pull request #1295 from safing/feature/routing-improvements-and-other-stuff

Routing improvements
This commit is contained in:
Daniel Hovie
2023-08-24 09:56:03 +02:00
committed by GitHub
20 changed files with 2043 additions and 661 deletions

View File

@@ -13,6 +13,7 @@ import (
// Configuration Keys. // Configuration Keys.
var ( var (
CfgOptionEnableFilterKey = "filter/enable" CfgOptionEnableFilterKey = "filter/enable"
filterEnabled config.BoolOption
CfgOptionAskWithSystemNotificationsKey = "filter/askWithSystemNotifications" CfgOptionAskWithSystemNotificationsKey = "filter/askWithSystemNotifications"
cfgOptionAskWithSystemNotificationsOrder = 2 cfgOptionAskWithSystemNotificationsOrder = 2
@@ -33,6 +34,23 @@ var (
func registerConfig() error { func registerConfig() error {
err := config.Register(&config.Option{ err := config.Register(&config.Option{
Name: "Enable Privacy Filter",
Key: CfgOptionEnableFilterKey,
Description: "Enable the Privacy Filter. If turned off, all privacy filter protections are fully disabled on this device. Not meant to be disabled in production - only turn off for testing.",
OptType: config.OptTypeBool,
ExpertiseLevel: config.ExpertiseLevelDeveloper,
ReleaseLevel: config.ReleaseLevelExperimental,
DefaultValue: true,
Annotations: config.Annotations{
config.CategoryAnnotation: "General",
},
})
if err != nil {
return err
}
filterEnabled = config.Concurrent.GetAsBool(CfgOptionEnableFilterKey, true)
err = config.Register(&config.Option{
Name: "Permanent Verdicts", Name: "Permanent Verdicts",
Key: CfgOptionPermanentVerdictsKey, Key: CfgOptionPermanentVerdictsKey,
Description: "The Portmaster's system integration intercepts every single packet. Usually the first packet is enough for the Portmaster to set the verdict for a connection - ie. to allow or deny it. Making these verdicts permanent means that the Portmaster will tell the system integration that is does not want to see any more packets of that single connection. This brings a major performance increase.", Description: "The Portmaster's system integration intercepts every single packet. Usually the first packet is enough for the Portmaster to set the verdict for a connection - ie. to allow or deny it. Making these verdicts permanent means that the Portmaster will tell the system integration that is does not want to see any more packets of that single connection. This brings a major performance increase.",
@@ -118,7 +136,6 @@ var (
devMode config.BoolOption devMode config.BoolOption
apiListenAddress config.StringOption apiListenAddress config.StringOption
filterEnabled config.BoolOption
tunnelEnabled config.BoolOption tunnelEnabled config.BoolOption
useCommunityNodes config.BoolOption useCommunityNodes config.BoolOption
@@ -129,7 +146,6 @@ func getConfig() {
devMode = config.Concurrent.GetAsBool(core.CfgDevModeKey, false) devMode = config.Concurrent.GetAsBool(core.CfgDevModeKey, false)
apiListenAddress = config.GetAsString(api.CfgDefaultListenAddressKey, "") apiListenAddress = config.GetAsString(api.CfgDefaultListenAddressKey, "")
filterEnabled = config.Concurrent.GetAsBool(CfgOptionEnableFilterKey, true)
tunnelEnabled = config.Concurrent.GetAsBool(captain.CfgOptionEnableSPNKey, false) tunnelEnabled = config.Concurrent.GetAsBool(captain.CfgOptionEnableSPNKey, false)
useCommunityNodes = config.Concurrent.GetAsBool(captain.CfgOptionUseCommunityNodesKey, true) useCommunityNodes = config.Concurrent.GetAsBool(captain.CfgOptionUseCommunityNodesKey, true)

View File

@@ -3,7 +3,6 @@ package firewall
import ( import (
"context" "context"
"github.com/safing/portbase/config"
"github.com/safing/portbase/log" "github.com/safing/portbase/log"
"github.com/safing/portbase/modules" "github.com/safing/portbase/modules"
"github.com/safing/portbase/modules/subsystems" "github.com/safing/portbase/modules/subsystems"
@@ -22,18 +21,7 @@ func init() {
"DNS and Network Filter", "DNS and Network Filter",
module, module,
"config:filter/", "config:filter/",
&config.Option{ nil,
Name: "Privacy Filter Module",
Key: CfgOptionEnableFilterKey,
Description: "Start the Privacy Filter module. If turned off, all privacy filter protections are fully disabled on this device.",
OptType: config.OptTypeBool,
ExpertiseLevel: config.ExpertiseLevelDeveloper,
ReleaseLevel: config.ReleaseLevelStable,
DefaultValue: true,
Annotations: config.Annotations{
config.CategoryAnnotation: "General",
},
},
) )
} }

View File

@@ -5,9 +5,11 @@ import (
"errors" "errors"
"github.com/safing/portbase/log" "github.com/safing/portbase/log"
"github.com/safing/portmaster/intel"
"github.com/safing/portmaster/netenv" "github.com/safing/portmaster/netenv"
"github.com/safing/portmaster/network" "github.com/safing/portmaster/network"
"github.com/safing/portmaster/network/packet" "github.com/safing/portmaster/network/packet"
"github.com/safing/portmaster/process"
"github.com/safing/portmaster/profile" "github.com/safing/portmaster/profile"
"github.com/safing/portmaster/profile/endpoints" "github.com/safing/portmaster/profile/endpoints"
"github.com/safing/portmaster/resolver" "github.com/safing/portmaster/resolver"
@@ -124,59 +126,8 @@ func requestTunneling(ctx context.Context, conn *network.Connection) error {
return errors.New("no profile set") return errors.New("no profile set")
} }
// Set options. // Get tunnel options.
conn.TunnelOpts = &navigator.Options{ conn.TunnelOpts = DeriveTunnelOptions(layeredProfile, conn.Process(), conn.Entity, conn.Encrypted)
HubPolicies: layeredProfile.StackedExitHubPolicies(),
CheckHubExitPolicyWith: conn.Entity,
RequireTrustedDestinationHubs: !conn.Encrypted,
RoutingProfile: layeredProfile.SPNRoutingAlgorithm(),
}
// Add required verified owners if community nodes should not be used.
if !useCommunityNodes() {
conn.TunnelOpts.RequireVerifiedOwners = captain.NonCommunityVerifiedOwners
}
// Get routing profile for checking for upgrades.
routingProfile := navigator.GetRoutingProfile(conn.TunnelOpts.RoutingProfile)
// If we have any exit hub policies, we must be able to hop in order to follow the policy.
// Switch to single-hop routing to allow for routing with hub selection.
if routingProfile.MaxHops <= 1 && conn.TunnelOpts.HubPoliciesAreSet() {
conn.TunnelOpts.RoutingProfile = navigator.RoutingProfileSingleHopID
}
// If the current home node is not trusted, then upgrade at least to two hops.
if routingProfile.MinHops < 2 {
homeNode, _ := navigator.Main.GetHome()
if homeNode != nil && !homeNode.State.Has(navigator.StateTrusted) {
conn.TunnelOpts.RoutingProfile = navigator.RoutingProfileDoubleHopID
}
}
// Special handling for the internal DNS resolver.
if conn.Process().Pid == ownPID && resolver.IsResolverAddress(conn.Entity.IP, conn.Entity.Port) {
dnsExitHubPolicy, err := captain.GetDNSExitHubPolicy()
if err != nil {
log.Errorf("firewall: failed to get dns exit hub policy: %s", err)
}
if err == nil && dnsExitHubPolicy.IsSet() {
// Apply the dns exit hub policy, if set.
conn.TunnelOpts.HubPolicies = []endpoints.Endpoints{dnsExitHubPolicy}
// Use the routing algorithm from the profile, as the home profile won't work with the policy.
conn.TunnelOpts.RoutingProfile = layeredProfile.SPNRoutingAlgorithm()
// Raise the routing algorithm at least to single-hop.
if conn.TunnelOpts.RoutingProfile == navigator.RoutingProfileHomeID {
conn.TunnelOpts.RoutingProfile = navigator.RoutingProfileSingleHopID
}
} else {
// Disable any policies for the internal DNS resolver.
conn.TunnelOpts.HubPolicies = nil
// Always use the home routing profile for the internal DNS resolver.
conn.TunnelOpts.RoutingProfile = navigator.RoutingProfileHomeID
}
}
// Queue request in sluice. // Queue request in sluice.
err := sluice.AwaitRequest(conn, crew.HandleSluiceRequest) err := sluice.AwaitRequest(conn, crew.HandleSluiceRequest)
@@ -187,3 +138,76 @@ func requestTunneling(ctx context.Context, conn *network.Connection) error {
log.Tracer(ctx).Trace("filter: tunneling requested") log.Tracer(ctx).Trace("filter: tunneling requested")
return nil return nil
} }
func init() {
navigator.DeriveTunnelOptions = func(lp *profile.LayeredProfile, destination *intel.Entity, connEncrypted bool) *navigator.Options {
return DeriveTunnelOptions(lp, nil, destination, connEncrypted)
}
}
// DeriveTunnelOptions derives and returns the tunnel options from the connection and profile.
func DeriveTunnelOptions(lp *profile.LayeredProfile, proc *process.Process, destination *intel.Entity, connEncrypted bool) *navigator.Options {
// Set options.
tunnelOpts := &navigator.Options{
Transit: &navigator.TransitHubOptions{
HubPolicies: lp.StackedTransitHubPolicies(),
},
Destination: &navigator.DestinationHubOptions{
HubPolicies: lp.StackedExitHubPolicies(),
CheckHubPolicyWith: destination,
},
RoutingProfile: lp.SPNRoutingAlgorithm(),
}
if !connEncrypted {
tunnelOpts.Destination.Regard = tunnelOpts.Destination.Regard.Add(navigator.StateTrusted)
}
// Add required verified owners if community nodes should not be used.
if !useCommunityNodes() {
tunnelOpts.Transit.RequireVerifiedOwners = captain.NonCommunityVerifiedOwners
tunnelOpts.Destination.RequireVerifiedOwners = captain.NonCommunityVerifiedOwners
}
// Get routing profile for checking for upgrades.
routingProfile := navigator.GetRoutingProfile(tunnelOpts.RoutingProfile)
// If we have any exit hub policies, we must be able to hop in order to follow the policy.
// Switch to single-hop routing to allow for routing with hub selection.
if routingProfile.MaxHops <= 1 && navigator.HubPoliciesAreSet(tunnelOpts.Destination.HubPolicies) {
tunnelOpts.RoutingProfile = navigator.RoutingProfileSingleHopID
}
// If the current home node is not trusted, then upgrade at least to two hops.
if routingProfile.MinHops < 2 {
homeNode, _ := navigator.Main.GetHome()
if homeNode != nil && !homeNode.State.Has(navigator.StateTrusted) {
tunnelOpts.RoutingProfile = navigator.RoutingProfileDoubleHopID
}
}
// Special handling for the internal DNS resolver.
if proc != nil && proc.Pid == ownPID && resolver.IsResolverAddress(destination.IP, destination.Port) {
dnsExitHubPolicy, err := captain.GetDNSExitHubPolicy()
if err != nil {
log.Errorf("firewall: failed to get dns exit hub policy: %s", err)
}
if err == nil && dnsExitHubPolicy.IsSet() {
// Apply the dns exit hub policy, if set.
tunnelOpts.Destination.HubPolicies = []endpoints.Endpoints{dnsExitHubPolicy}
// Use the routing algorithm from the profile, as the home profile won't work with the policy.
tunnelOpts.RoutingProfile = lp.SPNRoutingAlgorithm()
// Raise the routing algorithm at least to single-hop.
if tunnelOpts.RoutingProfile == navigator.RoutingProfileHomeID {
tunnelOpts.RoutingProfile = navigator.RoutingProfileSingleHopID
}
} else {
// Disable any policies for the internal DNS resolver.
tunnelOpts.Destination.HubPolicies = nil
// Always use the home routing profile for the internal DNS resolver.
tunnelOpts.RoutingProfile = navigator.RoutingProfileHomeID
}
}
return tunnelOpts
}

6
go.mod
View File

@@ -18,9 +18,9 @@ require (
github.com/miekg/dns v1.1.55 github.com/miekg/dns v1.1.55
github.com/oschwald/maxminddb-golang v1.12.0 github.com/oschwald/maxminddb-golang v1.12.0
github.com/safing/jess v0.3.1 github.com/safing/jess v0.3.1
github.com/safing/portbase v0.17.1 github.com/safing/portbase v0.17.2
github.com/safing/portmaster-android/go v0.0.0-20230605085256-6abf4c495626 github.com/safing/portmaster-android/go v0.0.0-20230605085256-6abf4c495626
github.com/safing/spn v0.6.15 github.com/safing/spn v0.6.16
github.com/shirou/gopsutil v3.21.11+incompatible github.com/shirou/gopsutil v3.21.11+incompatible
github.com/spf13/cobra v1.7.0 github.com/spf13/cobra v1.7.0
github.com/spkg/zipfs v0.7.1 github.com/spkg/zipfs v0.7.1
@@ -52,7 +52,7 @@ require (
github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect
github.com/google/btree v1.1.2 // indirect github.com/google/btree v1.1.2 // indirect
github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-cmp v0.5.9 // indirect
github.com/google/uuid v1.3.0 // indirect github.com/google/uuid v1.3.1 // indirect
github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect

12
go.sum
View File

@@ -105,8 +105,8 @@ github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
@@ -208,12 +208,12 @@ github.com/safing/jess v0.3.1 h1:cMZVhi2whW/YdD98MPLeLIWJndQ7o2QVt2HefQ/ByFA=
github.com/safing/jess v0.3.1/go.mod h1:aj73Eot1zm2ETkJuw9hJlIO8bRom52uBbsCHemvlZmA= github.com/safing/jess v0.3.1/go.mod h1:aj73Eot1zm2ETkJuw9hJlIO8bRom52uBbsCHemvlZmA=
github.com/safing/portbase v0.15.2/go.mod h1:5bHi99fz7Hh/wOsZUOI631WF9ePSHk57c4fdlOMS91Y= github.com/safing/portbase v0.15.2/go.mod h1:5bHi99fz7Hh/wOsZUOI631WF9ePSHk57c4fdlOMS91Y=
github.com/safing/portbase v0.16.2/go.mod h1:mzNCWqPbO7vIYbbK5PElGbudwd2vx4YPNawymL8Aro8= github.com/safing/portbase v0.16.2/go.mod h1:mzNCWqPbO7vIYbbK5PElGbudwd2vx4YPNawymL8Aro8=
github.com/safing/portbase v0.17.1 h1:q2aNHjJw4aoqTqKOxZpxRhYCciHw1exZ7lfGuB78i1E= github.com/safing/portbase v0.17.2 h1:HzJkURMmXkv30wMHB7xJ+Z5U5aTMe+EzvlHavKoKkos=
github.com/safing/portbase v0.17.1/go.mod h1:1cVgDZIsPiqM5b+K88Kshir5PGIvsftYkx7y1x925+8= github.com/safing/portbase v0.17.2/go.mod h1:1cVgDZIsPiqM5b+K88Kshir5PGIvsftYkx7y1x925+8=
github.com/safing/portmaster-android/go v0.0.0-20230605085256-6abf4c495626 h1:olc/REnUdpJN/Gmz8B030OxLpMYxyPDTrDILNEw0eKs= github.com/safing/portmaster-android/go v0.0.0-20230605085256-6abf4c495626 h1:olc/REnUdpJN/Gmz8B030OxLpMYxyPDTrDILNEw0eKs=
github.com/safing/portmaster-android/go v0.0.0-20230605085256-6abf4c495626/go.mod h1:abwyAQrZGemWbSh/aCD9nnkp0SvFFf/mGWkAbOwPnFE= github.com/safing/portmaster-android/go v0.0.0-20230605085256-6abf4c495626/go.mod h1:abwyAQrZGemWbSh/aCD9nnkp0SvFFf/mGWkAbOwPnFE=
github.com/safing/spn v0.6.15 h1:NbjXjZNy6dgYjd36wa/teip9dHtjjzKKYWwsWaok9y4= github.com/safing/spn v0.6.16 h1:z80H3X6wjsmizjWgichqYRyw3hSVB7rJpsDUDL2EWo0=
github.com/safing/spn v0.6.15/go.mod h1:Mh9bmkqFhO/dHNi9RWXzoXjQij893I4Lj8Wn4tQ0KZA= github.com/safing/spn v0.6.16/go.mod h1:2CuZfJJazIYyMDrhiwX2eFal0urQyLiX8rXLvJiCTcw=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/seehuhn/fortuna v1.0.1 h1:lu9+CHsmR0bZnx5Ay646XvCSRJ8PJTi5UYJwDBX68H0= github.com/seehuhn/fortuna v1.0.1 h1:lu9+CHsmR0bZnx5Ay646XvCSRJ8PJTi5UYJwDBX68H0=

1776
intel/geoip/country_info.go Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,43 @@
package geoip
import (
"testing"
)
func TestCountryInfo(t *testing.T) {
t.Parallel()
for key, country := range countries {
if key != country.ID {
t.Errorf("%s has a wrong ID of %q", key, country.ID)
}
if country.Name == "" {
t.Errorf("%s is missing name", key)
}
if country.Region == "" {
t.Errorf("%s is missing region", key)
}
if country.ContinentCode == "" {
t.Errorf("%s is missing continent", key)
}
if country.Center.Latitude == 0 && country.Center.Longitude == 0 {
t.Errorf("%s is missing coords", key)
}
// Generate map source from data:
// fmt.Printf(
// `"%s": {Name:%q,Region:%q,ContinentCode:%q,Center:Coordinates{AccuracyRadius:%d,Latitude:%f,Longitude:%f},},`,
// key,
// country.Name,
// country.Region,
// country.ContinentCode,
// country.Center.AccuracyRadius,
// country.Center.Latitude,
// country.Center.Longitude,
// )
// fmt.Println()
}
if len(countries) < 247 {
t.Errorf("dataset only includes %d countries", len(countries))
}
}

View File

@@ -1,264 +0,0 @@
package geoip
const defaultCountryBasedAccuracy = 200
// FillMissingInfo tries to fill missing location information based on the
// available existing information.
func (l *Location) FillMissingInfo() {
// Get coordinates from country.
if l.Coordinates.Latitude == 0 &&
l.Coordinates.Longitude == 0 &&
l.Country.ISOCode != "" {
if c, ok := countryCoordinates[l.Country.ISOCode]; ok {
l.Coordinates = c
l.Coordinates.AccuracyRadius = defaultCountryBasedAccuracy
}
}
}
var countryCoordinates = map[string]Coordinates{
"AD": {Latitude: 42, Longitude: 1},
"AE": {Latitude: 23, Longitude: 53},
"AF": {Latitude: 33, Longitude: 67},
"AG": {Latitude: 17, Longitude: -61},
"AI": {Latitude: 18, Longitude: -63},
"AL": {Latitude: 41, Longitude: 20},
"AM": {Latitude: 40, Longitude: 45},
"AN": {Latitude: 12, Longitude: -69},
"AO": {Latitude: -11, Longitude: 17},
"AQ": {Latitude: -75, Longitude: -0},
"AR": {Latitude: -38, Longitude: -63},
"AS": {Latitude: -14, Longitude: -170},
"AT": {Latitude: 47, Longitude: 14},
"AU": {Latitude: -25, Longitude: 133},
"AW": {Latitude: 12, Longitude: -69},
"AZ": {Latitude: 40, Longitude: 47},
"BA": {Latitude: 43, Longitude: 17},
"BB": {Latitude: 13, Longitude: -59},
"BD": {Latitude: 23, Longitude: 90},
"BE": {Latitude: 50, Longitude: 4},
"BF": {Latitude: 12, Longitude: -1},
"BG": {Latitude: 42, Longitude: 25},
"BH": {Latitude: 25, Longitude: 50},
"BI": {Latitude: -3, Longitude: 29},
"BJ": {Latitude: 9, Longitude: 2},
"BM": {Latitude: 32, Longitude: -64},
"BN": {Latitude: 4, Longitude: 114},
"BO": {Latitude: -16, Longitude: -63},
"BR": {Latitude: -14, Longitude: -51},
"BS": {Latitude: 25, Longitude: -77},
"BT": {Latitude: 27, Longitude: 90},
"BV": {Latitude: -54, Longitude: 3},
"BW": {Latitude: -22, Longitude: 24},
"BY": {Latitude: 53, Longitude: 27},
"BZ": {Latitude: 17, Longitude: -88},
"CA": {Latitude: 56, Longitude: -106},
"CC": {Latitude: -12, Longitude: 96},
"CD": {Latitude: -4, Longitude: 21},
"CF": {Latitude: 6, Longitude: 20},
"CG": {Latitude: -0, Longitude: 15},
"CH": {Latitude: 46, Longitude: 8},
"CI": {Latitude: 7, Longitude: -5},
"CK": {Latitude: -21, Longitude: -159},
"CL": {Latitude: -35, Longitude: -71},
"CM": {Latitude: 7, Longitude: 12},
"CN": {Latitude: 35, Longitude: 104},
"CO": {Latitude: 4, Longitude: -74},
"CR": {Latitude: 9, Longitude: -83},
"CU": {Latitude: 21, Longitude: -77},
"CV": {Latitude: 16, Longitude: -24},
"CX": {Latitude: -10, Longitude: 105},
"CY": {Latitude: 35, Longitude: 33},
"CZ": {Latitude: 49, Longitude: 15},
"DE": {Latitude: 51, Longitude: 10},
"DJ": {Latitude: 11, Longitude: 42},
"DK": {Latitude: 56, Longitude: 9},
"DM": {Latitude: 15, Longitude: -61},
"DO": {Latitude: 18, Longitude: -70},
"DZ": {Latitude: 28, Longitude: 1},
"EC": {Latitude: -1, Longitude: -78},
"EE": {Latitude: 58, Longitude: 25},
"EG": {Latitude: 26, Longitude: 30},
"EH": {Latitude: 24, Longitude: -12},
"ER": {Latitude: 15, Longitude: 39},
"ES": {Latitude: 40, Longitude: -3},
"ET": {Latitude: 9, Longitude: 40},
"FI": {Latitude: 61, Longitude: 25},
"FJ": {Latitude: -16, Longitude: 179},
"FK": {Latitude: -51, Longitude: -59},
"FM": {Latitude: 7, Longitude: 150},
"FO": {Latitude: 61, Longitude: -6},
"FR": {Latitude: 46, Longitude: 2},
"GA": {Latitude: -0, Longitude: 11},
"GB": {Latitude: 55, Longitude: -3},
"GD": {Latitude: 12, Longitude: -61},
"GE": {Latitude: 42, Longitude: 43},
"GF": {Latitude: 3, Longitude: -53},
"GG": {Latitude: 49, Longitude: -2},
"GH": {Latitude: 7, Longitude: -1},
"GI": {Latitude: 36, Longitude: -5},
"GL": {Latitude: 71, Longitude: -42},
"GM": {Latitude: 13, Longitude: -15},
"GN": {Latitude: 9, Longitude: -9},
"GP": {Latitude: 16, Longitude: -62},
"GQ": {Latitude: 1, Longitude: 10},
"GR": {Latitude: 39, Longitude: 21},
"GS": {Latitude: -54, Longitude: -36},
"GT": {Latitude: 15, Longitude: -90},
"GU": {Latitude: 13, Longitude: 144},
"GW": {Latitude: 11, Longitude: -15},
"GY": {Latitude: 4, Longitude: -58},
"GZ": {Latitude: 31, Longitude: 34},
"HK": {Latitude: 22, Longitude: 114},
"HM": {Latitude: -53, Longitude: 73},
"HN": {Latitude: 15, Longitude: -86},
"HR": {Latitude: 45, Longitude: 15},
"HT": {Latitude: 18, Longitude: -72},
"HU": {Latitude: 47, Longitude: 19},
"ID": {Latitude: -0, Longitude: 113},
"IE": {Latitude: 53, Longitude: -8},
"IL": {Latitude: 31, Longitude: 34},
"IM": {Latitude: 54, Longitude: -4},
"IN": {Latitude: 20, Longitude: 78},
"IO": {Latitude: -6, Longitude: 71},
"IQ": {Latitude: 33, Longitude: 43},
"IR": {Latitude: 32, Longitude: 53},
"IS": {Latitude: 64, Longitude: -19},
"IT": {Latitude: 41, Longitude: 12},
"JE": {Latitude: 49, Longitude: -2},
"JM": {Latitude: 18, Longitude: -77},
"JO": {Latitude: 30, Longitude: 36},
"JP": {Latitude: 36, Longitude: 138},
"KE": {Latitude: -0, Longitude: 37},
"KG": {Latitude: 41, Longitude: 74},
"KH": {Latitude: 12, Longitude: 104},
"KI": {Latitude: -3, Longitude: -168},
"KM": {Latitude: -11, Longitude: 43},
"KN": {Latitude: 17, Longitude: -62},
"KP": {Latitude: 40, Longitude: 127},
"KR": {Latitude: 35, Longitude: 127},
"KW": {Latitude: 29, Longitude: 47},
"KY": {Latitude: 19, Longitude: -80},
"KZ": {Latitude: 48, Longitude: 66},
"LA": {Latitude: 19, Longitude: 102},
"LB": {Latitude: 33, Longitude: 35},
"LC": {Latitude: 13, Longitude: -60},
"LI": {Latitude: 47, Longitude: 9},
"LK": {Latitude: 7, Longitude: 80},
"LR": {Latitude: 6, Longitude: -9},
"LS": {Latitude: -29, Longitude: 28},
"LT": {Latitude: 55, Longitude: 23},
"LU": {Latitude: 49, Longitude: 6},
"LV": {Latitude: 56, Longitude: 24},
"LY": {Latitude: 26, Longitude: 17},
"MA": {Latitude: 31, Longitude: -7},
"MC": {Latitude: 43, Longitude: 7},
"MD": {Latitude: 47, Longitude: 28},
"ME": {Latitude: 42, Longitude: 19},
"MG": {Latitude: -18, Longitude: 46},
"MH": {Latitude: 7, Longitude: 171},
"MK": {Latitude: 41, Longitude: 21},
"ML": {Latitude: 17, Longitude: -3},
"MM": {Latitude: 21, Longitude: 95},
"MN": {Latitude: 46, Longitude: 103},
"MO": {Latitude: 22, Longitude: 113},
"MP": {Latitude: 17, Longitude: 145},
"MQ": {Latitude: 14, Longitude: -61},
"MR": {Latitude: 21, Longitude: -10},
"MS": {Latitude: 16, Longitude: -62},
"MT": {Latitude: 35, Longitude: 14},
"MU": {Latitude: -20, Longitude: 57},
"MV": {Latitude: 3, Longitude: 73},
"MW": {Latitude: -13, Longitude: 34},
"MX": {Latitude: 23, Longitude: -102},
"MY": {Latitude: 4, Longitude: 101},
"MZ": {Latitude: -18, Longitude: 35},
"NA": {Latitude: -22, Longitude: 18},
"NC": {Latitude: -20, Longitude: 165},
"NE": {Latitude: 17, Longitude: 8},
"NF": {Latitude: -29, Longitude: 167},
"NG": {Latitude: 9, Longitude: 8},
"NI": {Latitude: 12, Longitude: -85},
"NL": {Latitude: 52, Longitude: 5},
"NO": {Latitude: 60, Longitude: 8},
"NP": {Latitude: 28, Longitude: 84},
"NR": {Latitude: -0, Longitude: 166},
"NU": {Latitude: -19, Longitude: -169},
"NZ": {Latitude: -40, Longitude: 174},
"OM": {Latitude: 21, Longitude: 55},
"PA": {Latitude: 8, Longitude: -80},
"PE": {Latitude: -9, Longitude: -75},
"PF": {Latitude: -17, Longitude: -149},
"PG": {Latitude: -6, Longitude: 143},
"PH": {Latitude: 12, Longitude: 121},
"PK": {Latitude: 30, Longitude: 69},
"PL": {Latitude: 51, Longitude: 19},
"PM": {Latitude: 46, Longitude: -56},
"PN": {Latitude: -24, Longitude: -127},
"PR": {Latitude: 18, Longitude: -66},
"PS": {Latitude: 31, Longitude: 35},
"PT": {Latitude: 39, Longitude: -8},
"PW": {Latitude: 7, Longitude: 134},
"PY": {Latitude: -23, Longitude: -58},
"QA": {Latitude: 25, Longitude: 51},
"RE": {Latitude: -21, Longitude: 55},
"RO": {Latitude: 45, Longitude: 24},
"RS": {Latitude: 44, Longitude: 21},
"RU": {Latitude: 61, Longitude: 105},
"RW": {Latitude: -1, Longitude: 29},
"SA": {Latitude: 23, Longitude: 45},
"SB": {Latitude: -9, Longitude: 160},
"SC": {Latitude: -4, Longitude: 55},
"SD": {Latitude: 12, Longitude: 30},
"SE": {Latitude: 60, Longitude: 18},
"SG": {Latitude: 1, Longitude: 103},
"SH": {Latitude: -24, Longitude: -10},
"SI": {Latitude: 46, Longitude: 14},
"SJ": {Latitude: 77, Longitude: 23},
"SK": {Latitude: 48, Longitude: 19},
"SL": {Latitude: 8, Longitude: -11},
"SM": {Latitude: 43, Longitude: 12},
"SN": {Latitude: 14, Longitude: -14},
"SO": {Latitude: 5, Longitude: 46},
"SR": {Latitude: 3, Longitude: -56},
"ST": {Latitude: 0, Longitude: 6},
"SV": {Latitude: 13, Longitude: -88},
"SY": {Latitude: 34, Longitude: 38},
"SZ": {Latitude: -26, Longitude: 31},
"TC": {Latitude: 21, Longitude: -71},
"TD": {Latitude: 15, Longitude: 18},
"TF": {Latitude: -49, Longitude: 69},
"TG": {Latitude: 8, Longitude: 0},
"TH": {Latitude: 15, Longitude: 100},
"TJ": {Latitude: 38, Longitude: 71},
"TK": {Latitude: -8, Longitude: -171},
"TL": {Latitude: -8, Longitude: 125},
"TM": {Latitude: 38, Longitude: 59},
"TN": {Latitude: 33, Longitude: 9},
"TO": {Latitude: -21, Longitude: -175},
"TR": {Latitude: 38, Longitude: 35},
"TT": {Latitude: 10, Longitude: -61},
"TV": {Latitude: -7, Longitude: 177},
"TW": {Latitude: 23, Longitude: 120},
"TZ": {Latitude: -6, Longitude: 34},
"UA": {Latitude: 48, Longitude: 31},
"UG": {Latitude: 1, Longitude: 32},
"US": {Latitude: 37, Longitude: -95},
"UY": {Latitude: -32, Longitude: -55},
"UZ": {Latitude: 41, Longitude: 64},
"VA": {Latitude: 41, Longitude: 12},
"VC": {Latitude: 12, Longitude: -61},
"VE": {Latitude: 6, Longitude: -66},
"VG": {Latitude: 18, Longitude: -64},
"VI": {Latitude: 18, Longitude: -64},
"VN": {Latitude: 14, Longitude: 108},
"VU": {Latitude: -15, Longitude: 166},
"WF": {Latitude: -13, Longitude: -177},
"WS": {Latitude: -13, Longitude: -172},
"XK": {Latitude: 42, Longitude: 20},
"YE": {Latitude: 15, Longitude: 48},
"YT": {Latitude: -12, Longitude: 45},
"ZA": {Latitude: -30, Longitude: 22},
"ZM": {Latitude: -13, Longitude: 27},
"ZW": {Latitude: -19, Longitude: 29},
}

View File

@@ -22,6 +22,7 @@ type Location struct {
Code string `maxminddb:"code"` Code string `maxminddb:"code"`
} `maxminddb:"continent"` } `maxminddb:"continent"`
Country struct { Country struct {
Name string
ISOCode string `maxminddb:"iso_code"` ISOCode string `maxminddb:"iso_code"`
} `maxminddb:"country"` } `maxminddb:"country"`
Coordinates Coordinates `maxminddb:"location"` Coordinates Coordinates `maxminddb:"location"`

View File

@@ -23,8 +23,7 @@ func GetLocation(ip net.IP) (*Location, error) {
return nil, err return nil, err
} }
record.FillMissingInfo() record.AddCountryInfo()
record.AddRegion()
return record, nil return record, nil
} }

View File

@@ -16,14 +16,14 @@ func init() {
func prep() error { func prep() error {
if err := api.RegisterEndpoint(api.Endpoint{ if err := api.RegisterEndpoint(api.Endpoint{
Path: "intel/geoip/country-centers", Path: "intel/geoip/countries",
Read: api.PermitUser, Read: api.PermitUser,
// Do not attach to module, as the data is always available anyway. // Do not attach to module, as the data is always available anyway.
StructFunc: func(ar *api.Request) (i interface{}, err error) { StructFunc: func(ar *api.Request) (i interface{}, err error) {
return countryCoordinates, nil return countries, nil
}, },
Name: "Get Geographic Country Centers", Name: "Get Country Information",
Description: "Returns a map of country centers indexed by ISO-A2 country code", Description: "Returns a map of country information centers indexed by ISO-A2 country code",
}); err != nil { }); err != nil {
return err return err
} }

View File

@@ -4,13 +4,6 @@ import (
"github.com/safing/portbase/utils" "github.com/safing/portbase/utils"
) )
// AddRegion adds the region based on the country.
func (l *Location) AddRegion() {
if regionID, ok := countryRegions[l.Country.ISOCode]; ok {
l.Continent.Code = regionID
}
}
// IsRegionalNeighbor returns whether the supplied location is a regional neighbor. // IsRegionalNeighbor returns whether the supplied location is a regional neighbor.
func (l *Location) IsRegionalNeighbor(other *Location) bool { func (l *Location) IsRegionalNeighbor(other *Location) bool {
if l.Continent.Code == "" || other.Continent.Code == "" { if l.Continent.Code == "" || other.Continent.Code == "" {
@@ -250,255 +243,3 @@ var regions = map[string]*Region{
}, },
}, },
} }
var countryRegions = map[string]string{
"AF": "AS-S",
"AX": "EU-N",
"AL": "EU-S",
"DZ": "AF-N",
"AS": "OC-E",
"AD": "EU-S",
"AO": "AF-C",
"AI": "NA-E",
"AQ": "AN",
"AG": "NA-E",
"AR": "SA",
"AM": "AS-W",
"AW": "NA-E",
"AU": "OC-S",
"AT": "EU-W",
"AZ": "AS-W",
"BS": "NA-E",
"BH": "AS-W",
"BD": "AS-S",
"BB": "NA-E",
"BY": "EU-E",
"BE": "EU-W",
"BZ": "NA-S",
"BJ": "AF-W",
"BM": "NA-N",
"BT": "AS-S",
"BO": "SA",
"BQ": "NA-E",
"BA": "EU-S",
"BW": "AF-S",
"BV": "SA",
"BR": "SA",
"IO": "AF-E",
"BN": "AS-SE",
"BG": "EU-E",
"BF": "AF-W",
"BI": "AF-E",
"CV": "AF-W",
"KH": "AS-SE",
"CM": "AF-C",
"CA": "NA-N",
"KY": "NA-E",
"CF": "AF-C",
"TD": "AF-C",
"CL": "SA",
"CN": "AS-E",
"CX": "OC-S",
"CC": "OC-S",
"CO": "SA",
"KM": "AF-E",
"CG": "AF-C",
"CD": "AF-C",
"CK": "OC-E",
"CR": "NA-S",
"CI": "AF-W",
"HR": "EU-S",
"CU": "NA-E",
"CW": "NA-E",
"CY": "AS-W",
"CZ": "EU-E",
"DK": "EU-N",
"DJ": "AF-E",
"DM": "NA-E",
"DO": "NA-E",
"EC": "SA",
"EG": "AF-N",
"SV": "NA-S",
"GQ": "AF-C",
"ER": "AF-E",
"EE": "EU-N",
"SZ": "AF-S",
"ET": "AF-E",
"FK": "SA",
"FO": "EU-N",
"FJ": "OC-C",
"FI": "EU-N",
"FR": "EU-W",
"GF": "SA",
"PF": "OC-E",
"TF": "AF-E",
"GA": "AF-C",
"GM": "AF-W",
"GE": "AS-W",
"DE": "EU-W",
"GH": "AF-W",
"GI": "EU-S",
"GR": "EU-S",
"GL": "NA-N",
"GD": "NA-E",
"GP": "NA-E",
"GU": "OC-N",
"GT": "NA-S",
"GG": "EU-N",
"GN": "AF-W",
"GW": "AF-W",
"GY": "SA",
"HT": "NA-E",
"HM": "OC-S",
"VA": "EU-S",
"HN": "NA-S",
"HK": "AS-E",
"HU": "EU-E",
"IS": "EU-N",
"IN": "AS-S",
"ID": "AS-SE",
"IR": "AS-S",
"IQ": "AS-W",
"IE": "EU-N",
"IM": "EU-N",
"IL": "AS-W",
"IT": "EU-S",
"JM": "NA-E",
"JP": "AS-E",
"JE": "EU-N",
"JO": "AS-W",
"KZ": "AS-C",
"KE": "AF-E",
"KI": "OC-N",
"KP": "AS-E",
"KR": "AS-E",
"KW": "AS-W",
"KG": "AS-C",
"LA": "AS-SE",
"LV": "EU-N",
"LB": "AS-W",
"LS": "AF-S",
"LR": "AF-W",
"LY": "AF-N",
"LI": "EU-W",
"LT": "EU-N",
"LU": "EU-W",
"MO": "AS-E",
"MG": "AF-E",
"MW": "AF-E",
"MY": "AS-SE",
"MV": "AS-S",
"ML": "AF-W",
"MT": "EU-S",
"MH": "OC-N",
"MQ": "NA-E",
"MR": "AF-W",
"MU": "AF-E",
"YT": "AF-E",
"MX": "NA-S",
"FM": "OC-N",
"MD": "EU-E",
"MC": "EU-W",
"MN": "AS-E",
"ME": "EU-S",
"MS": "NA-E",
"MA": "AF-N",
"MZ": "AF-E",
"MM": "AS-SE",
"NA": "AF-S",
"NR": "OC-N",
"NP": "AS-S",
"NL": "EU-W",
"NC": "OC-C",
"NZ": "OC-S",
"NI": "NA-S",
"NE": "AF-W",
"NG": "AF-W",
"NU": "OC-E",
"NF": "OC-S",
"MK": "EU-S",
"MP": "OC-N",
"NO": "EU-N",
"OM": "AS-W",
"PK": "AS-S",
"PW": "OC-N",
"PS": "AS-W",
"PA": "NA-S",
"PG": "OC-C",
"PY": "SA",
"PE": "SA",
"PH": "AS-SE",
"PN": "OC-E",
"PL": "EU-E",
"PT": "EU-S",
"PR": "NA-E",
"QA": "AS-W",
"RE": "AF-E",
"RO": "EU-E",
"RU": "EU-E",
"RW": "AF-E",
"BL": "NA-E",
"SH": "AF-W",
"KN": "NA-E",
"LC": "NA-E",
"MF": "NA-E",
"PM": "NA-N",
"VC": "NA-E",
"WS": "OC-E",
"SM": "EU-S",
"ST": "AF-C",
"SA": "AS-W",
"SN": "AF-W",
"RS": "EU-S",
"SC": "AF-E",
"SL": "AF-W",
"SG": "AS-SE",
"SX": "NA-E",
"SK": "EU-E",
"SI": "EU-S",
"SB": "OC-C",
"SO": "AF-E",
"ZA": "AF-S",
"GS": "SA",
"SS": "AF-E",
"ES": "EU-S",
"LK": "AS-S",
"SD": "AF-N",
"SR": "SA",
"SJ": "EU-N",
"SE": "EU-N",
"CH": "EU-W",
"SY": "AS-W",
"TW": "AS-E",
"TJ": "AS-C",
"TZ": "AF-E",
"TH": "AS-SE",
"TL": "AS-SE",
"TG": "AF-W",
"TK": "OC-E",
"TO": "OC-E",
"TT": "NA-E",
"TN": "AF-N",
"TR": "AS-W",
"TM": "AS-C",
"TC": "NA-E",
"TV": "OC-E",
"UG": "AF-E",
"UA": "EU-E",
"AE": "AS-W",
"GB": "EU-N",
"US": "NA-N",
"UM": "OC-N",
"UY": "SA",
"UZ": "AS-C",
"VU": "OC-C",
"VE": "SA",
"VN": "AS-SE",
"VG": "NA-E",
"VI": "NA-E",
"WF": "OC-E",
"EH": "AF-N",
"YE": "AS-W",
"ZM": "AF-E",
"ZW": "AF-E",
}

View File

@@ -87,7 +87,7 @@ func GetDNSRequestConnection(packetInfo *packet.Info) (conn *Connection, ok bool
defer dnsRequestConnectionsLock.RUnlock() defer dnsRequestConnectionsLock.RUnlock()
conn, ok = dnsRequestConnections[key] conn, ok = dnsRequestConnections[key]
return return conn, ok
} }
// deleteDNSRequestConnection removes a connection from the dns request connections. // deleteDNSRequestConnection removes a connection from the dns request connections.

View File

@@ -112,8 +112,8 @@ func (p *Process) IsIdentified() bool {
} }
} }
// IsLocal returns whether the process has been identified as a local process. // HasValidPID returns whether the process has valid PID of an actual process.
func (p *Process) IsLocal() bool { func (p *Process) HasValidPID() bool {
// Check if process exists. // Check if process exists.
if p == nil { if p == nil {
return false return false

View File

@@ -14,12 +14,13 @@ import (
var ( var (
cfgLock sync.RWMutex cfgLock sync.RWMutex
cfgDefaultAction uint8 cfgDefaultAction uint8
cfgEndpoints endpoints.Endpoints cfgEndpoints endpoints.Endpoints
cfgServiceEndpoints endpoints.Endpoints cfgServiceEndpoints endpoints.Endpoints
cfgSPNUsagePolicy endpoints.Endpoints cfgSPNUsagePolicy endpoints.Endpoints
cfgSPNExitHubPolicy endpoints.Endpoints cfgSPNTransitHubPolicy endpoints.Endpoints
cfgFilterLists []string cfgSPNExitHubPolicy endpoints.Endpoints
cfgFilterLists []string
) )
func registerConfigUpdater() error { func registerConfigUpdater() error {
@@ -83,6 +84,13 @@ func updateGlobalConfigProfile(ctx context.Context, task *modules.Task) error {
lastErr = err lastErr = err
} }
list = cfgOptionTransitHubPolicy()
cfgSPNTransitHubPolicy, err = endpoints.ParseEndpoints(list)
if err != nil {
// TODO: module error?
lastErr = err
}
list = cfgOptionExitHubPolicy() list = cfgOptionExitHubPolicy()
cfgSPNExitHubPolicy, err = endpoints.ParseEndpoints(list) cfgSPNExitHubPolicy, err = endpoints.ParseEndpoints(list)
if err != nil { if err != nil {

View File

@@ -7,7 +7,6 @@ import (
"github.com/safing/portmaster/profile/endpoints" "github.com/safing/portmaster/profile/endpoints"
"github.com/safing/portmaster/status" "github.com/safing/portmaster/status"
"github.com/safing/spn/access/account" "github.com/safing/spn/access/account"
"github.com/safing/spn/navigator"
) )
// Configuration Keys. // Configuration Keys.
@@ -129,14 +128,19 @@ var (
CfgOptionRoutingAlgorithmKey = "spn/routingAlgorithm" CfgOptionRoutingAlgorithmKey = "spn/routingAlgorithm"
cfgOptionRoutingAlgorithm config.StringOption cfgOptionRoutingAlgorithm config.StringOption
cfgOptionRoutingAlgorithmOrder = 144 cfgOptionRoutingAlgorithmOrder = 144
DefaultRoutingProfileID = "double-hop" // Copied due to import loop.
// Setting "Home Node Rules" at order 145. // Setting "Home Node Rules" at order 145.
CfgOptionTransitHubPolicyKey = "spn/transitHubPolicy"
cfgOptionTransitHubPolicy config.StringArrayOption
cfgOptionTransitHubPolicyOrder = 146
CfgOptionExitHubPolicyKey = "spn/exitHubPolicy" CfgOptionExitHubPolicyKey = "spn/exitHubPolicy"
cfgOptionExitHubPolicy config.StringArrayOption cfgOptionExitHubPolicy config.StringArrayOption
cfgOptionExitHubPolicyOrder = 146 cfgOptionExitHubPolicyOrder = 147
// Setting "DNS Exit Node Rules" at order 147. // Setting "DNS Exit Node Rules" at order 148.
) )
// A list of all security level settings. // A list of all security level settings.
@@ -156,19 +160,9 @@ var securityLevelSettings = []string{
} }
var ( var (
// SPNRulesQuickSettings is a list of countries the SPN currently is present in // SPNRulesQuickSettings are now generated automatically shorty after start.
// as quick settings in order to help users with SPN related policy settings.
// This is a quick win to make the MVP easier to use, but will be replaced by
// a better solution in the future.
SPNRulesQuickSettings = []config.QuickSetting{ SPNRulesQuickSettings = []config.QuickSetting{
{Name: "Exclude Canada (CA)", Action: config.QuickMergeTop, Value: []string{"- CA"}}, {Name: "Loading...", Action: config.QuickMergeTop, Value: []string{""}},
{Name: "Exclude Finland (FI)", Action: config.QuickMergeTop, Value: []string{"- FI"}},
{Name: "Exclude France (FR)", Action: config.QuickMergeTop, Value: []string{"- FR"}},
{Name: "Exclude Germany (DE)", Action: config.QuickMergeTop, Value: []string{"- DE"}},
{Name: "Exclude Israel (IL)", Action: config.QuickMergeTop, Value: []string{"- IL"}},
{Name: "Exclude Poland (PL)", Action: config.QuickMergeTop, Value: []string{"- PL"}},
{Name: "Exclude United Kingdom (GB)", Action: config.QuickMergeTop, Value: []string{"- GB"}},
{Name: "Exclude United States of America (US)", Action: config.QuickMergeTop, Value: []string{"- US"}},
} }
// SPNRulesVerdictNames defines the verdicts names to be used for SPN Rules. // SPNRulesVerdictNames defines the verdicts names to be used for SPN Rules.
@@ -720,6 +714,33 @@ Please note that if you are using the system resolver, bypass attempts might be
cfgOptionSPNUsagePolicy = config.Concurrent.GetAsStringArray(CfgOptionSPNUsagePolicyKey, []string{}) cfgOptionSPNUsagePolicy = config.Concurrent.GetAsStringArray(CfgOptionSPNUsagePolicyKey, []string{})
cfgStringArrayOptions[CfgOptionSPNUsagePolicyKey] = cfgOptionSPNUsagePolicy cfgStringArrayOptions[CfgOptionSPNUsagePolicyKey] = cfgOptionSPNUsagePolicy
// Transit Node Rules
err = config.Register(&config.Option{
Name: "Transit Node Rules",
Key: CfgOptionTransitHubPolicyKey,
Description: `Customize which countries should or should not be used as Transit Nodes. Transit Nodes are used to transit the SPN from your Home to your Exit Node.`,
Help: SPNRulesHelp,
Sensitive: true,
OptType: config.OptTypeStringArray,
ExpertiseLevel: config.ExpertiseLevelExpert,
DefaultValue: []string{},
Annotations: config.Annotations{
config.StackableAnnotation: true,
config.CategoryAnnotation: "Routing",
config.DisplayOrderAnnotation: cfgOptionTransitHubPolicyOrder,
config.DisplayHintAnnotation: endpoints.DisplayHintEndpointList,
config.QuickSettingsAnnotation: SPNRulesQuickSettings,
endpoints.EndpointListVerdictNamesAnnotation: SPNRulesVerdictNames,
},
ValidationRegex: endpoints.ListEntryValidationRegex,
ValidationFunc: endpoints.ValidateEndpointListConfigOption,
})
if err != nil {
return err
}
cfgOptionTransitHubPolicy = config.Concurrent.GetAsStringArray(CfgOptionTransitHubPolicyKey, []string{})
cfgStringArrayOptions[CfgOptionTransitHubPolicyKey] = cfgOptionTransitHubPolicy
// Exit Node Rules // Exit Node Rules
err = config.Register(&config.Option{ err = config.Register(&config.Option{
Name: "Exit Node Rules", Name: "Exit Node Rules",
@@ -754,7 +775,7 @@ By default, the Portmaster tries to choose the node closest to the destination a
Key: CfgOptionRoutingAlgorithmKey, Key: CfgOptionRoutingAlgorithmKey,
Description: "Select the routing algorithm for your connections through the SPN. Configure your preferred balance between speed and privacy. Portmaster may automatically upgrade the routing algorithm if necessary to protect your privacy.", Description: "Select the routing algorithm for your connections through the SPN. Configure your preferred balance between speed and privacy. Portmaster may automatically upgrade the routing algorithm if necessary to protect your privacy.",
OptType: config.OptTypeString, OptType: config.OptTypeString,
DefaultValue: navigator.DefaultRoutingProfileID, DefaultValue: DefaultRoutingProfileID,
Annotations: config.Annotations{ Annotations: config.Annotations{
config.DisplayHintAnnotation: config.DisplayHintOneOf, config.DisplayHintAnnotation: config.DisplayHintOneOf,
config.DisplayOrderAnnotation: cfgOptionRoutingAlgorithmOrder, config.DisplayOrderAnnotation: cfgOptionRoutingAlgorithmOrder,
@@ -786,7 +807,7 @@ By default, the Portmaster tries to choose the node closest to the destination a
if err != nil { if err != nil {
return err return err
} }
cfgOptionRoutingAlgorithm = config.Concurrent.GetAsString(CfgOptionRoutingAlgorithmKey, navigator.DefaultRoutingProfileID) cfgOptionRoutingAlgorithm = config.Concurrent.GetAsString(CfgOptionRoutingAlgorithmKey, DefaultRoutingProfileID)
cfgStringOptions[CfgOptionRoutingAlgorithmKey] = cfgOptionRoutingAlgorithm cfgStringOptions[CfgOptionRoutingAlgorithmKey] = cfgOptionRoutingAlgorithm
return nil return nil

View File

@@ -382,6 +382,23 @@ func (lp *LayeredProfile) MatchSPNUsagePolicy(ctx context.Context, entity *intel
return cfgSPNUsagePolicy.Match(ctx, entity) return cfgSPNUsagePolicy.Match(ctx, entity)
} }
// StackedTransitHubPolicies returns all transit hub policies of the layered profile, including the global one.
func (lp *LayeredProfile) StackedTransitHubPolicies() []endpoints.Endpoints {
policies := make([]endpoints.Endpoints, 0, len(lp.layers)+3) // +1 for global policy, +2 for intel policies
for _, layer := range lp.layers {
if layer.spnTransitHubPolicy.IsSet() {
policies = append(policies, layer.spnTransitHubPolicy)
}
}
cfgLock.RLock()
defer cfgLock.RUnlock()
policies = append(policies, cfgSPNTransitHubPolicy)
return policies
}
// StackedExitHubPolicies returns all exit hub policies of the layered profile, including the global one. // StackedExitHubPolicies returns all exit hub policies of the layered profile, including the global one.
func (lp *LayeredProfile) StackedExitHubPolicies() []endpoints.Endpoints { func (lp *LayeredProfile) StackedExitHubPolicies() []endpoints.Endpoints {
policies := make([]endpoints.Endpoints, 0, len(lp.layers)+3) // +1 for global policy, +2 for intel policies policies := make([]endpoints.Endpoints, 0, len(lp.layers)+3) // +1 for global policy, +2 for intel policies

View File

@@ -127,15 +127,16 @@ type Profile struct { //nolint:maligned // not worth the effort
layeredProfile *LayeredProfile layeredProfile *LayeredProfile
// Interpreted Data // Interpreted Data
configPerspective *config.Perspective configPerspective *config.Perspective
dataParsed bool dataParsed bool
defaultAction uint8 defaultAction uint8
endpoints endpoints.Endpoints endpoints endpoints.Endpoints
serviceEndpoints endpoints.Endpoints serviceEndpoints endpoints.Endpoints
filterListsSet bool filterListsSet bool
filterListIDs []string filterListIDs []string
spnUsagePolicy endpoints.Endpoints spnUsagePolicy endpoints.Endpoints
spnExitHubPolicy endpoints.Endpoints spnTransitHubPolicy endpoints.Endpoints
spnExitHubPolicy endpoints.Endpoints
// Lifecycle Management // Lifecycle Management
outdated *abool.AtomicBool outdated *abool.AtomicBool
@@ -224,6 +225,15 @@ func (profile *Profile) parseConfig() error {
} }
} }
list, ok = profile.configPerspective.GetAsStringArray(CfgOptionTransitHubPolicyKey)
profile.spnTransitHubPolicy = nil
if ok {
profile.spnTransitHubPolicy, err = endpoints.ParseEndpoints(list)
if err != nil {
lastErr = err
}
}
list, ok = profile.configPerspective.GetAsStringArray(CfgOptionExitHubPolicyKey) list, ok = profile.configPerspective.GetAsStringArray(CfgOptionExitHubPolicyKey)
profile.spnExitHubPolicy = nil profile.spnExitHubPolicy = nil
if ok { if ok {
@@ -451,7 +461,7 @@ func (profile *Profile) updateMetadata(binaryPath string) (changed bool) {
changed = true changed = true
} }
// Migrato to Fingerprints. // Migrate to Fingerprints.
// TODO: Remove in v1.5 // TODO: Remove in v1.5
if len(profile.Fingerprints) == 0 && profile.LinkedPath != "" { if len(profile.Fingerprints) == 0 && profile.LinkedPath != "" {
profile.Fingerprints = []Fingerprint{ profile.Fingerprints = []Fingerprint{

View File

@@ -26,20 +26,19 @@ var (
// https://github.com/safing/portmaster/wiki/DNS-Server-Settings // https://github.com/safing/portmaster/wiki/DNS-Server-Settings
// Quad9 (encrypted DNS) // Quad9 (encrypted DNS)
// `dot://9.9.9.9:853?verify=dns.quad9.net&name=Quad9&blockedif=empty`, // "dot://dns.quad9.net?ip=9.9.9.9&name=Quad9&blockedif=empty",
// `dot://149.112.112.112:853?verify=dns.quad9.net&name=Quad9&blockedif=empty`, // "dot://dns.quad9.net?ip=149.112.112.112&name=Quad9&blockedif=empty",
// Cloudflare (encrypted DNS, with malware protection) // Cloudflare (encrypted DNS, with malware protection)
`dot://1.1.1.2:853?verify=cloudflare-dns.com&name=Cloudflare&blockedif=zeroip`, "dot://cloudflare-dns.com?ip=1.1.1.2&name=Cloudflare&blockedif=zeroip",
`dot://1.0.0.2:853?verify=cloudflare-dns.com&name=Cloudflare&blockedif=zeroip`, "dot://cloudflare-dns.com?ip=1.0.0.2&name=Cloudflare&blockedif=zeroip",
// AdGuard (encrypted DNS, default flavor) // AdGuard (encrypted DNS, default flavor)
// `dot://94.140.14.14:853?verify=dns.adguard.com&name=AdGuard&blockedif=zeroip`, // "dot://dns.adguard.com?ip=94.140.14.14&name=AdGuard&blockedif=zeroip",
// `dot://94.140.15.15:853?verify=dns.adguard.com&name=AdGuard&blockedif=zeroip`, // "dot://dns.adguard.com?ip=94.140.15.15&name=AdGuard&blockedif=zeroip",
// Foundation for Applied Privacy (encrypted DNS) // Foundation for Applied Privacy (encrypted DNS)
// `dot://94.130.106.88:853?verify=dot1.applied-privacy.net&name=AppliedPrivacy`, // "dot://dot1.applied-privacy.net?ip=146.255.56.98&name=AppliedPrivacy",
// `dot://94.130.106.88:443?verify=dot1.applied-privacy.net&name=AppliedPrivacy`,
// Quad9 (plain DNS) // Quad9 (plain DNS)
// `dns://9.9.9.9:53?name=Quad9&blockedif=empty`, // `dns://9.9.9.9:53?name=Quad9&blockedif=empty`,
@@ -88,23 +87,28 @@ func prepConfig() error {
err := config.Register(&config.Option{ err := config.Register(&config.Option{
Name: "DNS Servers", Name: "DNS Servers",
Key: CfgOptionNameServersKey, Key: CfgOptionNameServersKey,
Description: "DNS Servers to use for resolving DNS requests.", Description: "DNS servers to use for resolving DNS requests.",
Help: strings.ReplaceAll(`DNS Servers are used in the order as entered. The first one will be used as the primary DNS Server. Only if it fails, will the other servers be used as a fallback - in their respective order. If all fail, or if no DNS Server is configured here, the Portmaster will use the one configured in your system or network. Help: strings.ReplaceAll(`DNS servers are used in the order as entered. The first one will be used as the primary DNS Server. Only if it fails, will the other servers be used as a fallback - in their respective order. If all fail, or if no DNS Server is configured here, the Portmaster will use the one configured in your system or network.
Additionally, if it is more likely that the DNS Server of your system or network has a (better) answer to a request, they will be asked first. This will be the case for special local domains and domain spaces announced on the current network. Additionally, if it is more likely that the DNS server of your system or network has a (better) answer to a request, they will be asked first. This will be the case for special local domains and domain spaces announced on the current network.
DNS Servers are configured in a URL format. This allows you to specify special settings for a resolver. If you just want to use a resolver at IP 10.2.3.4, please enter: "dns://10.2.3.4" DNS servers are configured in a URL format. This allows you to specify special settings for a resolver. If you just want to use a resolver at IP 10.2.3.4, please enter: "dns://10.2.3.4"
The format is: "protocol://ip:port?parameter=value&parameter=value" The format is: "protocol://host:port?parameter=value&parameter=value"
For DoH servers, you can also just paste the URL given by the DNS provider.
When referring to the DNS server using a domain name, as with DoH, it is highly recommended to also specify the IP address using the "ip" parameter, so Portmaster does not have to resolve it.
- Protocol - Protocol
- "dot": DNS-over-TLS (recommended) - "dot": DNS-over-TLS (or "tls"; recommended)
- "doh": DNS-over-HTTPS (or "https")
- "dns": plain old DNS - "dns": plain old DNS
- "tcp": plain old DNS over TCP - "tcp": plain old DNS over TCP
- IP: always use the IP address and _not_ the domain name! - Host: specify the domain or IP of the resolver
- Port: optionally define a custom port - Port: optionally define a custom port
- Parameters: - Parameters:
- "name": give your DNS Server a name that is used for messages and logs - "name": give your DNS Server a name that is used for messages and logs
- "verify": domain name to verify for "dot", required and only valid for protocol "dot" - "verify": domain name to verify for "dot", only valid for "dot" and "doh"
- "ip": IP address (if using a domain), so Portmaster does not need to resolve it using the system resolver - this is highly recommended
- "blockedif": detect if the name server blocks a query, options: - "blockedif": detect if the name server blocks a query, options:
- "empty": server replies with NXDomain status, but without any other record in any section - "empty": server replies with NXDomain status, but without any other record in any section
- "refused": server replies with Refused status - "refused": server replies with Refused status

View File

@@ -34,7 +34,6 @@ const (
parameterBlockedIf = "blockedif" parameterBlockedIf = "blockedif"
parameterSearch = "search" parameterSearch = "search"
parameterSearchOnly = "search-only" parameterSearchOnly = "search-only"
parameterPath = "path"
) )
var ( var (
@@ -209,8 +208,7 @@ func checkAndSetResolverParamters(u *url.URL, resolver *Resolver) error {
parameterIP, parameterIP,
parameterBlockedIf, parameterBlockedIf,
parameterSearch, parameterSearch,
parameterSearchOnly, parameterSearchOnly:
parameterPath:
// Known key, continue. // Known key, continue.
default: default:
// Unknown key, abort. // Unknown key, abort.