mirror of
https://github.com/safing/portmaster
synced 2025-09-02 10:39:22 +00:00
Merge pull request #535 from safing/feature/spn-settings
Add SPN Settings
This commit is contained in:
commit
4336c48927
11 changed files with 412 additions and 124 deletions
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
conn.TunnelOpts = &navigator.Options{
|
return
|
||||||
RoutingProfile: navigator.RoutingProfileHomeName,
|
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{
|
||||||
|
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
12
go.mod
|
@ -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
35
go.sum
|
@ -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=
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
|
||||||
)
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -35,19 +35,20 @@ type LayeredProfile struct {
|
||||||
// via the API. If we ever switch away from JSON to something else supported
|
// via the API. If we ever switch away from JSON to something else supported
|
||||||
// by DSD this WILL BREAK!
|
// by DSD this WILL BREAK!
|
||||||
|
|
||||||
DisableAutoPermit config.BoolOption `json:"-"`
|
DisableAutoPermit config.BoolOption `json:"-"`
|
||||||
BlockScopeLocal config.BoolOption `json:"-"`
|
BlockScopeLocal config.BoolOption `json:"-"`
|
||||||
BlockScopeLAN config.BoolOption `json:"-"`
|
BlockScopeLAN config.BoolOption `json:"-"`
|
||||||
BlockScopeInternet config.BoolOption `json:"-"`
|
BlockScopeInternet config.BoolOption `json:"-"`
|
||||||
BlockP2P config.BoolOption `json:"-"`
|
BlockP2P config.BoolOption `json:"-"`
|
||||||
BlockInbound config.BoolOption `json:"-"`
|
BlockInbound config.BoolOption `json:"-"`
|
||||||
RemoveOutOfScopeDNS config.BoolOption `json:"-"`
|
RemoveOutOfScopeDNS config.BoolOption `json:"-"`
|
||||||
RemoveBlockedDNS config.BoolOption `json:"-"`
|
RemoveBlockedDNS config.BoolOption `json:"-"`
|
||||||
FilterSubDomains config.BoolOption `json:"-"`
|
FilterSubDomains config.BoolOption `json:"-"`
|
||||||
FilterCNAMEs config.BoolOption `json:"-"`
|
FilterCNAMEs config.BoolOption `json:"-"`
|
||||||
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 {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue