Merge pull request #535 from safing/feature/spn-settings

Add SPN Settings
This commit is contained in:
Daniel 2022-03-02 10:08:03 +01:00 committed by GitHub
commit 4336c48927
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 412 additions and 124 deletions

View file

@ -25,9 +25,6 @@ import (
"github.com/safing/portmaster/network" "github.com/safing/portmaster/network"
"github.com/safing/portmaster/network/netutils" "github.com/safing/portmaster/network/netutils"
"github.com/safing/portmaster/network/packet" "github.com/safing/portmaster/network/packet"
"github.com/safing/spn/captain"
"github.com/safing/spn/crew"
"github.com/safing/spn/sluice"
) )
var ( var (
@ -335,9 +332,6 @@ func initialHandler(conn *network.Connection, pkt packet.Packet) {
conn.Accept("connection by Portmaster", noReasonOptionKey) conn.Accept("connection by Portmaster", noReasonOptionKey)
conn.Internal = true conn.Internal = true
// Set tunnel options.
setCustomTunnelOptionsForPortmaster(conn)
// Redirect outbound DNS packests, // Redirect outbound DNS packests,
case pkt.IsOutbound() && case pkt.IsOutbound() &&
pkt.Info().DstPort == 53 && pkt.Info().DstPort == 53 &&
@ -368,41 +362,6 @@ func initialHandler(conn *network.Connection, pkt packet.Packet) {
conn.Accept("privacy filter disabled", noReasonOptionKey) conn.Accept("privacy filter disabled", noReasonOptionKey)
} }
// Tunnel, if enabled.
if pkt.IsOutbound() && conn.Entity.IPScope.IsGlobal() &&
tunnelEnabled() && conn.Verdict == network.VerdictAccept &&
conn.Process().Profile() != nil &&
conn.Process().Profile().UseSPN() {
switch {
case captain.ClientBootstrapping() &&
conn.Process().Pid == ownPID:
// Exclude the Portmaster during SPN bootstrapping.
case captain.IsExcepted(conn.Entity.IP) &&
conn.Process().Pid == ownPID:
// Exclude requests of the SPN itself.
case captain.ClientReady():
// Queue request in sluice.
err := sluice.AwaitRequest(conn, crew.HandleSluiceRequest)
if err != nil {
log.Tracer(pkt.Ctx()).Warningf("failed to rqeuest tunneling: %s", err)
conn.Failed("failed to request tunneling", "")
} else {
log.Tracer(pkt.Ctx()).Trace("filter: tunneling requested")
conn.Verdict = network.VerdictRerouteToTunnel
conn.Tunneled = true
}
default:
// Block connection as SPN is not ready yet.
log.Tracer(pkt.Ctx()).Trace("SPN not ready for tunneling")
conn.Failed("SPN not ready for tunneling", "")
}
}
// TODO: Enable inspection framework again. // TODO: Enable inspection framework again.
conn.Inspecting = false conn.Inspecting = false
@ -419,6 +378,9 @@ func initialHandler(conn *network.Connection, pkt packet.Packet) {
conn.Encrypted = true conn.Encrypted = true
} }
// Check if connection should be tunneled.
checkTunneling(pkt.Ctx(), conn, pkt)
switch { switch {
case conn.Inspecting: case conn.Inspecting:
log.Tracer(pkt.Ctx()).Trace("filter: start inspecting") log.Tracer(pkt.Ctx()).Trace("filter: start inspecting")

View file

@ -140,10 +140,6 @@ func checkPortmasterConnection(ctx context.Context, conn *network.Connection, _
log.Tracer(ctx).Infof("filter: granting own connection %s", conn) log.Tracer(ctx).Infof("filter: granting own connection %s", conn)
conn.Accept("connection by Portmaster", noReasonOptionKey) conn.Accept("connection by Portmaster", noReasonOptionKey)
conn.Internal = true conn.Internal = true
// Set tunnel options.
setCustomTunnelOptionsForPortmaster(conn)
return true return true
} }

View file

@ -1,23 +1,140 @@
package firewall package firewall
import ( import (
"context"
"github.com/safing/portbase/log"
"github.com/safing/portmaster/network" "github.com/safing/portmaster/network"
"github.com/safing/portmaster/network/packet"
"github.com/safing/portmaster/profile"
"github.com/safing/portmaster/profile/endpoints"
"github.com/safing/portmaster/resolver" "github.com/safing/portmaster/resolver"
"github.com/safing/spn/captain"
"github.com/safing/spn/crew"
"github.com/safing/spn/navigator" "github.com/safing/spn/navigator"
"github.com/safing/spn/sluice"
) )
func setCustomTunnelOptionsForPortmaster(conn *network.Connection) { func checkTunneling(ctx context.Context, conn *network.Connection, pkt packet.Packet) {
// Check if the connection should be tunneled at all.
switch { switch {
case !tunnelEnabled(): case !tunnelEnabled():
// Ignore when tunneling is not enabled. // Tunneling is disabled.
return return
case !conn.Entity.IPScope.IsGlobal(): case !conn.Entity.IPScope.IsGlobal():
// Ignore if destination is not in global address space. // Can't tunnel Local/LAN connections.
return return
case resolver.IsResolverAddress(conn.Entity.IP, conn.Entity.Port): case conn.Inbound:
// Set custom tunnel options for DNS servers. // Can't tunnel incoming connections.
return
case conn.Verdict != network.VerdictAccept:
// Connection will be blocked.
return
case conn.Process().Pid == ownPID:
// Bypass tunneling for certain own connections.
switch {
case captain.ClientBootstrapping():
return
case captain.IsExcepted(conn.Entity.IP):
return
}
}
// Get profile.
layeredProfile := conn.Process().Profile()
if layeredProfile == nil {
conn.Failed("no profile set", "")
return
}
// Update profile.
if layeredProfile.NeedsUpdate() {
// Update revision counter in connection.
conn.ProfileRevisionCounter = layeredProfile.Update()
conn.SaveWhenFinished()
} else {
// Check if the revision counter of the connection needs updating.
revCnt := layeredProfile.RevisionCnt()
if conn.ProfileRevisionCounter != revCnt {
conn.ProfileRevisionCounter = revCnt
conn.SaveWhenFinished()
}
}
// Check if tunneling is enabeld for this app at all.
if !layeredProfile.UseSPN() {
return
}
// Check if tunneling is enabled for entity.
conn.Entity.FetchData(ctx)
result, _ := layeredProfile.MatchSPNUsagePolicy(ctx, conn.Entity)
switch result {
case endpoints.MatchError:
conn.Failed("failed to check SPN rules", profile.CfgOptionSPNUsagePolicyKey)
return
case endpoints.Denied:
return
case endpoints.Permitted, endpoints.NoMatch:
// Continue
}
// Tunnel all the things!
// Check if ready.
if !captain.ClientReady() {
// Block connection as SPN is not ready yet.
log.Tracer(pkt.Ctx()).Trace("SPN not ready for tunneling")
conn.Failed("SPN not ready for tunneling", "")
return
}
// Set options.
conn.TunnelOpts = &navigator.Options{ conn.TunnelOpts = &navigator.Options{
RoutingProfile: navigator.RoutingProfileHomeName, HubPolicies: layeredProfile.StackedExitHubPolicies(),
CheckHubExitPolicyWith: conn.Entity,
RequireTrustedDestinationHubs: !conn.Encrypted,
RoutingProfile: layeredProfile.SPNRoutingAlgorithm(),
}
// If we have any exit hub policies, we need to raise the routing algorithm at least to single-hop.
if conn.TunnelOpts.RoutingProfile == navigator.RoutingProfileHomeID &&
conn.TunnelOpts.HubPoliciesAreSet() {
conn.TunnelOpts.RoutingProfile = navigator.RoutingProfileSingleHopID
}
// 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.
err := sluice.AwaitRequest(conn, crew.HandleSluiceRequest)
if err != nil {
log.Tracer(pkt.Ctx()).Warningf("failed to request tunneling: %s", err)
conn.Failed("failed to request tunneling", "")
} else {
log.Tracer(pkt.Ctx()).Trace("filter: tunneling requested")
conn.Verdict = network.VerdictRerouteToTunnel
conn.Tunneled = true
}
} }

12
go.mod
View file

@ -7,24 +7,22 @@ require (
github.com/cookieo9/resources-go v0.0.0-20150225115733-d27c04069d0d github.com/cookieo9/resources-go v0.0.0-20150225115733-d27c04069d0d
github.com/coreos/go-iptables v0.6.0 github.com/coreos/go-iptables v0.6.0
github.com/florianl/go-nfqueue v1.3.0 github.com/florianl/go-nfqueue v1.3.0
github.com/godbus/dbus/v5 v5.0.6 github.com/godbus/dbus/v5 v5.1.0
github.com/google/gopacket v1.1.19 github.com/google/gopacket v1.1.19
github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-version v1.4.0 github.com/hashicorp/go-version v1.4.0
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect github.com/mdlayher/socket v0.2.2 // indirect
github.com/mdlayher/netlink v1.6.0 // indirect
github.com/mdlayher/socket v0.2.0 // indirect
github.com/miekg/dns v1.1.46 github.com/miekg/dns v1.1.46
github.com/oschwald/maxminddb-golang v1.8.0 github.com/oschwald/maxminddb-golang v1.8.0
github.com/safing/portbase v0.14.0 github.com/safing/portbase v0.14.0
github.com/safing/spn v0.4.2 github.com/safing/spn v0.4.3
github.com/shirou/gopsutil v3.21.11+incompatible github.com/shirou/gopsutil v3.21.11+incompatible
github.com/spf13/cobra v1.3.0 github.com/spf13/cobra v1.3.0
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
github.com/tannerryan/ring v1.1.2 github.com/tannerryan/ring v1.1.2
github.com/tevino/abool v1.2.0 github.com/tevino/abool v1.2.0
github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26 github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd golang.org/x/net v0.0.0-20220225172249-27dd8689420f
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9
) )

35
go.sum
View file

@ -68,8 +68,6 @@ contrib.go.opencensus.io/exporter/stackdriver v0.13.8/go.mod h1:huNtlWx75MwO7qMs
contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/AlecAivazis/survey/v2 v2.0.7/go.mod h1:mlizQTaPjnR4jcpwRSaSlkbsRfYFEyKgLQvYTzxxiHA= github.com/AlecAivazis/survey/v2 v2.0.7/go.mod h1:mlizQTaPjnR4jcpwRSaSlkbsRfYFEyKgLQvYTzxxiHA=
github.com/AlecAivazis/survey/v2 v2.3.2 h1:TqTB+aDDCLYhf9/bD2TwSO8u8jDSmMUd2SUVO4gCnU8=
github.com/AlecAivazis/survey/v2 v2.3.2/go.mod h1:TH2kPCDU3Kqq7pLbnCWwZXDBjnhZtmsCle5EiYDJ2fg=
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M=
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/Azure/azure-amqp-common-go/v3 v3.1.0/go.mod h1:PBIGdzcO1teYoufTKMcGibdKaYZv4avS+O6LNIp8bq0= github.com/Azure/azure-amqp-common-go/v3 v3.1.0/go.mod h1:PBIGdzcO1teYoufTKMcGibdKaYZv4avS+O6LNIp8bq0=
@ -360,8 +358,9 @@ github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68Fp
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.5/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.5/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.6 h1:mkgN1ofwASrYnJ5W6U/BxG15eXXXjirgZc7CLqkcaro=
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
@ -474,8 +473,9 @@ github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7
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.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gosimple/slug v1.10.0/go.mod h1:MICb3w495l9KNdZm+Xn5b6T2Hn831f9DMxiJ1r+bAjw= github.com/gosimple/slug v1.10.0/go.mod h1:MICb3w495l9KNdZm+Xn5b6T2Hn831f9DMxiJ1r+bAjw=
github.com/gosimple/unidecode v1.0.0/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= github.com/gosimple/unidecode v1.0.0/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
@ -670,13 +670,12 @@ github.com/mdlayher/socket v0.0.0-20211007213009-516dcbdf0267/go.mod h1:nFZ1EtZY
github.com/mdlayher/socket v0.0.0-20211102153432-57e3fa563ecb/go.mod h1:nFZ1EtZYK8Gi/k6QNu7z7CgO20i/4ExeQswwWuPmG/g= github.com/mdlayher/socket v0.0.0-20211102153432-57e3fa563ecb/go.mod h1:nFZ1EtZYK8Gi/k6QNu7z7CgO20i/4ExeQswwWuPmG/g=
github.com/mdlayher/socket v0.1.0/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= github.com/mdlayher/socket v0.1.0/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs=
github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs=
github.com/mdlayher/socket v0.2.0 h1:EY4YQd6hTAg2tcXF84p5DTHazShE50u5HeBzBaNgjkA=
github.com/mdlayher/socket v0.2.0/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E= github.com/mdlayher/socket v0.2.0/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E=
github.com/mdlayher/socket v0.2.2 h1:UOh5gQk70kRl1YMLCTRwRF4MvsAQsudjkEA+ZDXS4jo=
github.com/mdlayher/socket v0.2.2/go.mod h1:IcNFWYJJuSGgnfKie27UfpEDWytPDqy+TrDd9I5hUKQ=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
@ -806,9 +805,7 @@ github.com/safing/portbase v0.13.1/go.mod h1:5vj5IK5WJoSGareDe6yCMZfnF7txVRx7jZy
github.com/safing/portbase v0.13.2/go.mod h1:5vj5IK5WJoSGareDe6yCMZfnF7txVRx7jZyTZInISP0= github.com/safing/portbase v0.13.2/go.mod h1:5vj5IK5WJoSGareDe6yCMZfnF7txVRx7jZyTZInISP0=
github.com/safing/portbase v0.13.3/go.mod h1:5vj5IK5WJoSGareDe6yCMZfnF7txVRx7jZyTZInISP0= github.com/safing/portbase v0.13.3/go.mod h1:5vj5IK5WJoSGareDe6yCMZfnF7txVRx7jZyTZInISP0=
github.com/safing/portbase v0.13.4/go.mod h1:5vj5IK5WJoSGareDe6yCMZfnF7txVRx7jZyTZInISP0= github.com/safing/portbase v0.13.4/go.mod h1:5vj5IK5WJoSGareDe6yCMZfnF7txVRx7jZyTZInISP0=
github.com/safing/portbase v0.13.5 h1:WtDvnTh8reBMnhPiyAr62qkBeBUri0EaNlb0u2msNNM=
github.com/safing/portbase v0.13.5/go.mod h1:5vj5IK5WJoSGareDe6yCMZfnF7txVRx7jZyTZInISP0= github.com/safing/portbase v0.13.5/go.mod h1:5vj5IK5WJoSGareDe6yCMZfnF7txVRx7jZyTZInISP0=
github.com/safing/portbase v0.13.6 h1:0tAa4fyCdlZy4J+Ne9G5JshV+Cmu+Ol0m5AftPHnjvE=
github.com/safing/portbase v0.13.6/go.mod h1:G0maDSQxYDuluNhMzA1zVd/nfXawfECv5H7+fnTfVhM= github.com/safing/portbase v0.13.6/go.mod h1:G0maDSQxYDuluNhMzA1zVd/nfXawfECv5H7+fnTfVhM=
github.com/safing/portbase v0.14.0 h1:6+sdUs1tdRCKnyuzy/zHrvUsdO1GdI0l4gZaoYJmJ5Q= github.com/safing/portbase v0.14.0 h1:6+sdUs1tdRCKnyuzy/zHrvUsdO1GdI0l4gZaoYJmJ5Q=
github.com/safing/portbase v0.14.0/go.mod h1:z9sRR/vqohAGdYSSx2B+o8tND4WVvcxPL6XBBtN3bDI= github.com/safing/portbase v0.14.0/go.mod h1:z9sRR/vqohAGdYSSx2B+o8tND4WVvcxPL6XBBtN3bDI=
@ -824,6 +821,7 @@ github.com/safing/portmaster v0.7.17/go.mod h1:TCWK75oZtkWv9bPyYIAILOma5G6VSK5FD
github.com/safing/portmaster v0.7.18/go.mod h1:NXd1l1z0oKy0WfXMhv/gpAXz+pUHnlNuYPBSaMZe7uw= github.com/safing/portmaster v0.7.18/go.mod h1:NXd1l1z0oKy0WfXMhv/gpAXz+pUHnlNuYPBSaMZe7uw=
github.com/safing/portmaster v0.7.21/go.mod h1:Jy0G6x6m5dE36Mv9grXHI77cxysQ0fIQV1EYQ00WEiQ= github.com/safing/portmaster v0.7.21/go.mod h1:Jy0G6x6m5dE36Mv9grXHI77cxysQ0fIQV1EYQ00WEiQ=
github.com/safing/portmaster v0.8.0/go.mod h1:lY2/WvOlH8kl1AwkixdWCjlo+PZQv+oEOQhIaSS/+wA= github.com/safing/portmaster v0.8.0/go.mod h1:lY2/WvOlH8kl1AwkixdWCjlo+PZQv+oEOQhIaSS/+wA=
github.com/safing/portmaster v0.8.5-interdep/go.mod h1:A+zAVEKjr057ktgiMSJRdUmOF+FPW8XY/5LqGnbsKbU=
github.com/safing/spn v0.3.4/go.mod h1:TfzNsZCbnlWv0UFDILFOUSudVKJZlnBVoR1fDXrjOK0= github.com/safing/spn v0.3.4/go.mod h1:TfzNsZCbnlWv0UFDILFOUSudVKJZlnBVoR1fDXrjOK0=
github.com/safing/spn v0.3.5/go.mod h1:jHkFF2Yu1fnjFu4KXjVA+iagMr/z4eB4p3jiwikvKj8= github.com/safing/spn v0.3.5/go.mod h1:jHkFF2Yu1fnjFu4KXjVA+iagMr/z4eB4p3jiwikvKj8=
github.com/safing/spn v0.3.6/go.mod h1:RSeFb/h5Wt3yDVezXj3lhXJ/Iwd7FbtsGf5E+p5J2YQ= github.com/safing/spn v0.3.6/go.mod h1:RSeFb/h5Wt3yDVezXj3lhXJ/Iwd7FbtsGf5E+p5J2YQ=
@ -835,12 +833,10 @@ github.com/safing/spn v0.3.15/go.mod h1:SXlGMeYLgfMcpT1aXI1Iaw07iy6Dy6+9KaD2p+HU
github.com/safing/spn v0.3.16/go.mod h1:NMaHlnIHcTHMxxz6PuaBg0rJdYc8LhyF5N6v+Iie+k0= github.com/safing/spn v0.3.16/go.mod h1:NMaHlnIHcTHMxxz6PuaBg0rJdYc8LhyF5N6v+Iie+k0=
github.com/safing/spn v0.3.17/go.mod h1:Fq/70Hl0OUxtYuY5NATv5q468hvfDDEFwN3mivEecic= github.com/safing/spn v0.3.17/go.mod h1:Fq/70Hl0OUxtYuY5NATv5q468hvfDDEFwN3mivEecic=
github.com/safing/spn v0.3.19/go.mod h1:phCnWjWOgdVMXaMsmDr6izR/ROVElSZGdIm7j7PIit4= github.com/safing/spn v0.3.19/go.mod h1:phCnWjWOgdVMXaMsmDr6izR/ROVElSZGdIm7j7PIit4=
github.com/safing/spn v0.4.0 h1:7bUdeOAt65s7RCuwiuPrJU/E0kUIhS5I5dcXTZ3xtEc=
github.com/safing/spn v0.4.0/go.mod h1:0jBetnYCfxqO5PJskhPOxJ/v6VRfE+bQU98XW240BNw= github.com/safing/spn v0.4.0/go.mod h1:0jBetnYCfxqO5PJskhPOxJ/v6VRfE+bQU98XW240BNw=
github.com/safing/spn v0.4.1 h1:ikotIeXN5dX6O29mmXVbL8sYA21FL774ITq9zmzmPbQ=
github.com/safing/spn v0.4.1/go.mod h1:yZPezHDEYyhei8n13tTxjQCGq6LRr5svz9WFAAeDPec=
github.com/safing/spn v0.4.2 h1:7ETU2XsU0gT94VTrKbIEC9q8ws7XlzkCfuZR8wtVp48=
github.com/safing/spn v0.4.2/go.mod h1:yZPezHDEYyhei8n13tTxjQCGq6LRr5svz9WFAAeDPec= github.com/safing/spn v0.4.2/go.mod h1:yZPezHDEYyhei8n13tTxjQCGq6LRr5svz9WFAAeDPec=
github.com/safing/spn v0.4.3 h1:iEFmpzyrThJ8QF9Qpbxk/m4w2+ZvbVPyuqJ4EwnpfDg=
github.com/safing/spn v0.4.3/go.mod h1:YHtg3FkZviN8T7db4BdRffbYO1pO7w9SydQatLmvW2M=
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
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=
@ -945,8 +941,9 @@ github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp1
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
github.com/tklauser/go-sysconf v0.3.4/go.mod h1:Cl2c8ZRWfHD5IrfHo9VN+FX9kCFjIOyVklgXycLB6ek= github.com/tklauser/go-sysconf v0.3.4/go.mod h1:Cl2c8ZRWfHD5IrfHo9VN+FX9kCFjIOyVklgXycLB6ek=
github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo=
github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
github.com/tklauser/numcpus v0.2.1/go.mod h1:9aU+wOc6WjUIZEwWMP62PL/41d65P+iks1gBkr4QyP8= github.com/tklauser/numcpus v0.2.1/go.mod h1:9aU+wOc6WjUIZEwWMP62PL/41d65P+iks1gBkr4QyP8=
github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8= github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o= github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=
@ -1061,7 +1058,6 @@ golang.org/x/crypto v0.0.0-20211115234514-b4de73f9ece8/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220213190939-1e6e3497d506 h1:EuGTJDfeg/PGZJp3gq1K+14eSLFTsrj1eg8KQuiUyKg=
golang.org/x/crypto v0.0.0-20220213190939-1e6e3497d506/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220213190939-1e6e3497d506/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE= golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
@ -1179,8 +1175,9 @@ golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -1330,16 +1327,16 @@ golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
golang.org/x/term v0.0.0-20210916214954-140adaaadfaf/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210916214954-140adaaadfaf/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=

View file

@ -18,6 +18,8 @@ var (
cfgDefaultAction uint8 cfgDefaultAction uint8
cfgEndpoints endpoints.Endpoints cfgEndpoints endpoints.Endpoints
cfgServiceEndpoints endpoints.Endpoints cfgServiceEndpoints endpoints.Endpoints
cfgSPNUsagePolicy endpoints.Endpoints
cfgSPNExitHubPolicy endpoints.Endpoints
cfgFilterLists []string cfgFilterLists []string
) )
@ -75,6 +77,20 @@ func updateGlobalConfigProfile(ctx context.Context, task *modules.Task) error {
lastErr = err lastErr = err
} }
list = cfgOptionSPNUsagePolicy()
cfgSPNUsagePolicy, err = endpoints.ParseEndpoints(list)
if err != nil {
// TODO: module error?
lastErr = err
}
list = cfgOptionExitHubPolicy()
cfgSPNExitHubPolicy, err = endpoints.ParseEndpoints(list)
if err != nil {
// TODO: module error?
lastErr = err
}
// build global profile for reference // build global profile for reference
profile := New(SourceSpecial, "global-config", "", nil) profile := New(SourceSpecial, "global-config", "", nil)
profile.Name = "Global Configuration" profile.Name = "Global Configuration"

View file

@ -98,9 +98,27 @@ var (
// Setting "Permanent Verdicts" at order 96. // Setting "Permanent Verdicts" at order 96.
// Setting "Enable SPN" at order 128.
CfgOptionUseSPNKey = "spn/use" CfgOptionUseSPNKey = "spn/use"
cfgOptionUseSPN config.BoolOption cfgOptionUseSPN config.BoolOption
cfgOptionUseSPNOrder = 129 cfgOptionUseSPNOrder = 129
CfgOptionSPNUsagePolicyKey = "spn/usagePolicy"
cfgOptionSPNUsagePolicy config.StringArrayOption
cfgOptionSPNUsagePolicyOrder = 130
CfgOptionRoutingAlgorithmKey = "spn/routingAlgorithm"
cfgOptionRoutingAlgorithm config.StringOption
cfgOptionRoutingAlgorithmOrder = 144
// Setting "Home Node Rules" at order 145.
CfgOptionExitHubPolicyKey = "spn/exitHubPolicy"
cfgOptionExitHubPolicy config.StringArrayOption
cfgOptionExitHubPolicyOrder = 146
// Setting "DNS Exit Node Rules" at order 147.
) )
// A list of all security level settings. // A list of all security level settings.
@ -119,6 +137,39 @@ var securityLevelSettings = []string{
CfgOptionDisableAutoPermitKey, CfgOptionDisableAutoPermitKey,
} }
var (
// SPNRulesQuickSettings is a list of countries the SPN currently is present in
// 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{
{Name: "Exclude Canada (CA)", Action: config.QuickMergeTop, Value: []string{"- CA"}},
{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 = map[string]string{
"-": "Exclude", // Default.
"+": "Allow",
}
// SPNRulesHelp defines the help text for SPN related Hub selection rules.
SPNRulesHelp = strings.ReplaceAll(`Rules are checked from top to bottom, stopping after the first match. They can match the following attributes of SPN Nodes:
- Country (based on IPs): "US"
- AS number: "AS123456"
- Address: "192.168.0.1"
- Network: "192.168.0.1/24"
- Anything: "*"
`, `"`, "`")
)
func registerConfiguration() error { //nolint:maintidx func registerConfiguration() error { //nolint:maintidx
// Default Filter Action // Default Filter Action
// permit - blocklist mode: everything is allowed unless blocked // permit - blocklist mode: everything is allowed unless blocked
@ -207,15 +258,6 @@ Examples: "192.168.0.1 TCP/HTTP", "LAN UDP/50000-55000", "example.com */HTTPS",
Important: DNS Requests are only matched against domain and filter list rules, all others require an IP address and are checked only with the following IP connection. Important: DNS Requests are only matched against domain and filter list rules, all others require an IP address and are checked only with the following IP connection.
`, `"`, "`") `, `"`, "`")
rulesValidationRegex := strings.Join([]string{
`^(\+|\-) `, // Rule verdict.
`[A-z0-9\.:\-*/]+`, // Entity matching.
`( `, // Start of optional matching.
`[A-z0-9*]+`, // Protocol matching.
`(/[A-z0-9]+(\-[A-z0-9]+)?)?`, // Port and port range matching.
`)?$`, // End of optional matching.
}, "")
// Endpoint Filter List // Endpoint Filter List
err = config.Register(&config.Option{ err = config.Register(&config.Option{
Name: "Outgoing Rules", Name: "Outgoing Rules",
@ -230,7 +272,8 @@ Important: DNS Requests are only matched against domain and filter list rules, a
config.DisplayOrderAnnotation: cfgOptionEndpointsOrder, config.DisplayOrderAnnotation: cfgOptionEndpointsOrder,
config.CategoryAnnotation: "Rules", config.CategoryAnnotation: "Rules",
}, },
ValidationRegex: rulesValidationRegex, ValidationRegex: endpoints.ListEntryValidationRegex,
ValidationFunc: endpoints.ValidateEndpointListConfigOption,
}) })
if err != nil { if err != nil {
return err return err
@ -270,7 +313,8 @@ Important: DNS Requests are only matched against domain and filter list rules, a
}, },
}, },
}, },
ValidationRegex: rulesValidationRegex, ValidationRegex: endpoints.ListEntryValidationRegex,
ValidationFunc: endpoints.ValidateEndpointListConfigOption,
}) })
if err != nil { if err != nil {
return err return err
@ -570,5 +614,98 @@ Please note that if you are using the system resolver, bypass attempts might be
cfgOptionUseSPN = config.Concurrent.GetAsBool(CfgOptionUseSPNKey, true) cfgOptionUseSPN = config.Concurrent.GetAsBool(CfgOptionUseSPNKey, true)
cfgBoolOptions[CfgOptionUseSPNKey] = cfgOptionUseSPN cfgBoolOptions[CfgOptionUseSPNKey] = cfgOptionUseSPN
// SPN Rules
err = config.Register(&config.Option{
Name: "SPN Rules",
Key: CfgOptionSPNUsagePolicyKey,
Description: `Customize which websites should or should not be routed through the SPN. Only active if "Use SPN" is enabled.`,
Help: rulesHelp,
OptType: config.OptTypeStringArray,
DefaultValue: []string{},
Annotations: config.Annotations{
config.StackableAnnotation: true,
config.CategoryAnnotation: "General",
config.DisplayOrderAnnotation: cfgOptionSPNUsagePolicyOrder,
config.DisplayHintAnnotation: endpoints.DisplayHintEndpointList,
endpoints.EndpointListVerdictNamesAnnotation: SPNRulesVerdictNames,
},
ValidationRegex: endpoints.ListEntryValidationRegex,
ValidationFunc: endpoints.ValidateEndpointListConfigOption,
})
if err != nil {
return err
}
cfgOptionSPNUsagePolicy = config.Concurrent.GetAsStringArray(CfgOptionSPNUsagePolicyKey, []string{})
cfgStringArrayOptions[CfgOptionSPNUsagePolicyKey] = cfgOptionSPNUsagePolicy
// Exit Node Rules
err = config.Register(&config.Option{
Name: "Exit Node Rules",
Key: CfgOptionExitHubPolicyKey,
Description: `Customize which countries should or should not be used for your Exit Nodes. Exit Nodes are used to exit the SPN and establish a connection to your destination.
By default, the Portmaster tries to choose the node closest to the destination as the Exit Node. This reduces your exposure to the open Internet. Exit Nodes are chosen for every destination separately.`,
Help: SPNRulesHelp,
OptType: config.OptTypeStringArray,
DefaultValue: []string{},
Annotations: config.Annotations{
config.StackableAnnotation: true,
config.CategoryAnnotation: "Routing",
config.DisplayOrderAnnotation: cfgOptionExitHubPolicyOrder,
config.DisplayHintAnnotation: endpoints.DisplayHintEndpointList,
config.QuickSettingsAnnotation: SPNRulesQuickSettings,
endpoints.EndpointListVerdictNamesAnnotation: SPNRulesVerdictNames,
},
ValidationRegex: endpoints.ListEntryValidationRegex,
ValidationFunc: endpoints.ValidateEndpointListConfigOption,
})
if err != nil {
return err
}
cfgOptionExitHubPolicy = config.Concurrent.GetAsStringArray(CfgOptionExitHubPolicyKey, []string{})
cfgStringArrayOptions[CfgOptionExitHubPolicyKey] = cfgOptionExitHubPolicy
// Select SPN Routing Algorithm
defaultRoutingAlg := "double-hop"
err = config.Register(&config.Option{
Name: "Select SPN Routing Algorithm",
Key: CfgOptionRoutingAlgorithmKey,
Description: "Select the routing algorithm for your connections through the SPN. Configure your preferred balance between speed and privacy.",
OptType: config.OptTypeString,
DefaultValue: defaultRoutingAlg,
Annotations: config.Annotations{
config.DisplayHintAnnotation: config.DisplayHintOneOf,
config.DisplayOrderAnnotation: cfgOptionRoutingAlgorithmOrder,
config.CategoryAnnotation: "Routing",
},
PossibleValues: []config.PossibleValue{
{
Name: "Plain VPN Mode",
Value: "home",
Description: "Always connect to the destination directly from the Home Hub. Only provides very basic privacy, as the Home Hub both knows where you are coming from and where you are connecting to.",
},
{
Name: "Speed Focused",
Value: "single-hop",
Description: "Optimize routes with a minimum of one hop. Provides good speeds. This will often use the Home Hub to connect to destinations near you, but will use more hops to far away destinations for better privacy over long distances.",
},
{
Name: "Balanced",
Value: "double-hop",
Description: "Optimize routes with a minimum of two hops. Provides good privacy as well as good speeds. No single node knows where you are coming from *and* where you are connecting to.",
},
{
Name: "Privacy Focused",
Value: "triple-hop",
Description: "Optimize routes with a minimum of three hops. Provides very good privacy. No single node knows where you are coming from *and* where you are connecting to - with an additional hop just to be sure.",
},
},
})
if err != nil {
return err
}
cfgOptionRoutingAlgorithm = config.Concurrent.GetAsString(CfgOptionRoutingAlgorithmKey, defaultRoutingAlg)
cfgStringOptions[CfgOptionRoutingAlgorithmKey] = cfgOptionRoutingAlgorithm
return nil return nil
} }

View file

@ -4,21 +4,10 @@ package endpoints
// list option. It's meant to be used with DisplayHintAnnotation. // list option. It's meant to be used with DisplayHintAnnotation.
const DisplayHintEndpointList = "endpoint list" const DisplayHintEndpointList = "endpoint list"
// EndpointListAnnotation is the annotation identifier used in configuration // EndpointListVerdictNamesAnnotation is the annotation identifier used in
// options to hint the UI on available endpoint list types. If configured, only // configuration options to hint the UI on names to be used for endpoint list
// the specified set of entities is allowed to be used. The value is expected // verdicts.
// to be a single string or []string. If this annotation is missing, all // If configured, it must be of type map[string]string, mapping the verdict
// values are expected to be allowed. // symbol to a name to be displayed in the UI.
const EndpointListAnnotation = "safing/portmaster:ui:endpoint-list" // May only used when config.DisplayHintAnnotation is set to DisplayHintEndpointList.
const EndpointListVerdictNamesAnnotation = "safing/portmaster:ui:endpoint-list:verdict-names"
// Allowed values for the EndpointListAnnotation.
const (
EndpointListIP = "ip"
EndpointListAsn = "asn"
EndpointListCountry = "country"
EndpointListDomain = "domain"
EndpointListIPRange = "iprange"
EndpointListLists = "lists"
EndpointListScopes = "scopes"
EndpointListProtocolAndPorts = "protocol-port"
)

View file

@ -2,6 +2,7 @@ package endpoints
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"strings" "strings"
@ -58,6 +59,27 @@ entriesLoop:
return endpoints, nil return endpoints, nil
} }
// ListEntryValidationRegex is a regex to bullshit check endpoint list entries.
var ListEntryValidationRegex = strings.Join([]string{
`^(\+|\-) `, // Rule verdict.
`[A-z0-9\.:\-*/]+`, // Entity matching.
`( `, // Start of optional matching.
`[A-z0-9*]+`, // Protocol matching.
`(/[A-z0-9]+(\-[A-z0-9]+)?)?`, // Port and port range matching.
`)?$`, // End of optional matching.
}, "")
// ValidateEndpointListConfigOption validates the given value.
func ValidateEndpointListConfigOption(value interface{}) error {
list, ok := value.([]string)
if !ok {
return errors.New("invalid type")
}
_, err := ParseEndpoints(list)
return err
}
// IsSet returns whether the Endpoints object is "set". // IsSet returns whether the Endpoints object is "set".
func (e Endpoints) IsSet() bool { func (e Endpoints) IsSet() bool {
return len(e) > 0 return len(e) > 0

View file

@ -48,6 +48,7 @@ type LayeredProfile struct {
PreventBypassing config.BoolOption `json:"-"` PreventBypassing config.BoolOption `json:"-"`
DomainHeuristics config.BoolOption `json:"-"` DomainHeuristics config.BoolOption `json:"-"`
UseSPN config.BoolOption `json:"-"` UseSPN config.BoolOption `json:"-"`
SPNRoutingAlgorithm config.StringOption `json:"-"`
} }
// NewLayeredProfile returns a new layered profile based on the given local profile. // NewLayeredProfile returns a new layered profile based on the given local profile.
@ -115,6 +116,10 @@ func NewLayeredProfile(localProfile *Profile) *LayeredProfile {
CfgOptionUseSPNKey, CfgOptionUseSPNKey,
cfgOptionUseSPN, cfgOptionUseSPN,
) )
lp.SPNRoutingAlgorithm = lp.wrapStringOption(
CfgOptionRoutingAlgorithmKey,
cfgOptionRoutingAlgorithm,
)
lp.LayerIDs = append(lp.LayerIDs, localProfile.ScopedID()) lp.LayerIDs = append(lp.LayerIDs, localProfile.ScopedID())
lp.layers = append(lp.layers, localProfile) lp.layers = append(lp.layers, localProfile)
@ -334,6 +339,39 @@ func (lp *LayeredProfile) MatchServiceEndpoint(ctx context.Context, entity *inte
return cfgServiceEndpoints.Match(ctx, entity) return cfgServiceEndpoints.Match(ctx, entity)
} }
// MatchSPNUsagePolicy checks if the given endpoint matches an entry in any of the profiles. This functions requires the layered profile to be read locked.
func (lp *LayeredProfile) MatchSPNUsagePolicy(ctx context.Context, entity *intel.Entity) (endpoints.EPResult, endpoints.Reason) {
for _, layer := range lp.layers {
if layer.spnUsagePolicy.IsSet() {
result, reason := layer.spnUsagePolicy.Match(ctx, entity)
if endpoints.IsDecision(result) {
return result, reason
}
}
}
cfgLock.RLock()
defer cfgLock.RUnlock()
return cfgSPNUsagePolicy.Match(ctx, entity)
}
// StackedExitHubPolicies returns all exit hub policies of the layered profile, including the global one.
func (lp *LayeredProfile) StackedExitHubPolicies() []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.spnExitHubPolicy.IsSet() {
policies = append(policies, layer.spnExitHubPolicy)
}
}
cfgLock.RLock()
defer cfgLock.RUnlock()
policies = append(policies, cfgSPNExitHubPolicy)
return policies
}
// MatchFilterLists matches the entity against the set of filter // MatchFilterLists matches the entity against the set of filter
// lists. This functions requires the layered profile to be read locked. // lists. This functions requires the layered profile to be read locked.
func (lp *LayeredProfile) MatchFilterLists(ctx context.Context, entity *intel.Entity) (endpoints.EPResult, endpoints.Reason) { func (lp *LayeredProfile) MatchFilterLists(ctx context.Context, entity *intel.Entity) (endpoints.EPResult, endpoints.Reason) {
@ -451,9 +489,6 @@ func (lp *LayeredProfile) GetProfileSource(configKey string) string {
return "" return ""
} }
/*
For later:
func (lp *LayeredProfile) wrapStringOption(configKey string, globalConfig config.StringOption) config.StringOption { func (lp *LayeredProfile) wrapStringOption(configKey string, globalConfig config.StringOption) config.StringOption {
var revCnt uint64 = 0 var revCnt uint64 = 0
var value string var value string
@ -485,7 +520,6 @@ func (lp *LayeredProfile) wrapStringOption(configKey string, globalConfig config
return value return value
} }
} }
*/
func max(a, b uint8) uint8 { func max(a, b uint8) uint8 {
if a > b { if a > b {

View file

@ -128,6 +128,8 @@ type Profile struct { //nolint:maligned // not worth the effort
serviceEndpoints endpoints.Endpoints serviceEndpoints endpoints.Endpoints
filterListsSet bool filterListsSet bool
filterListIDs []string filterListIDs []string
spnUsagePolicy endpoints.Endpoints
spnExitHubPolicy endpoints.Endpoints
// Lifecycle Management // Lifecycle Management
outdated *abool.AtomicBool outdated *abool.AtomicBool
@ -202,6 +204,24 @@ func (profile *Profile) parseConfig() error {
} }
} }
list, ok = profile.configPerspective.GetAsStringArray(CfgOptionSPNUsagePolicyKey)
profile.spnUsagePolicy = nil
if ok {
profile.spnUsagePolicy, err = endpoints.ParseEndpoints(list)
if err != nil {
lastErr = err
}
}
list, ok = profile.configPerspective.GetAsStringArray(CfgOptionExitHubPolicyKey)
profile.spnExitHubPolicy = nil
if ok {
profile.spnExitHubPolicy, err = endpoints.ParseEndpoints(list)
if err != nil {
lastErr = err
}
}
return lastErr return lastErr
} }