Add endpoint type network scope
Also, update default service endpoint list configuration to allow localhost
This commit is contained in:
@@ -121,17 +121,12 @@ func registerConfiguration() error {
|
||||
cfgOptionDisableAutoPermit = config.Concurrent.GetAsInt(CfgOptionDisableAutoPermitKey, int64(status.SecurityLevelsAll))
|
||||
cfgIntOptions[CfgOptionDisableAutoPermitKey] = cfgOptionDisableAutoPermit
|
||||
|
||||
// Endpoint Filter List
|
||||
err = config.Register(&config.Option{
|
||||
Name: "Endpoint Filter List",
|
||||
Key: CfgOptionEndpointsKey,
|
||||
Description: "Filter outgoing connections by matching the destination endpoint. Network Scope restrictions still apply.",
|
||||
Help: `Format:
|
||||
filterListHelp := `Format:
|
||||
Permission:
|
||||
"+": permit
|
||||
"-": block
|
||||
Host Matching:
|
||||
IP, CIDR, Country Code, ASN, Filterlist, "*" for any
|
||||
IP, CIDR, Country Code, ASN, Filterlist, Network Scope, "*" for any
|
||||
Domains:
|
||||
"example.com": exact match
|
||||
".example.com": exact match + subdomains
|
||||
@@ -144,11 +139,20 @@ func registerConfiguration() error {
|
||||
Examples:
|
||||
+ .example.com */HTTP
|
||||
- .example.com
|
||||
+ 192.168.0.1/24
|
||||
+ 192.168.0.1
|
||||
+ 192.168.1.1/24
|
||||
+ Localhost,LAN
|
||||
- AS123456789
|
||||
- L:MAL
|
||||
- AS0
|
||||
+ AT
|
||||
- *`,
|
||||
- *`
|
||||
|
||||
// Endpoint Filter List
|
||||
err = config.Register(&config.Option{
|
||||
Name: "Endpoint Filter List",
|
||||
Key: CfgOptionEndpointsKey,
|
||||
Description: "Filter outgoing connections by matching the destination endpoint. Network Scope restrictions still apply.",
|
||||
Help: filterListHelp,
|
||||
Order: cfgOptionEndpointsOrder,
|
||||
OptType: config.OptTypeStringArray,
|
||||
DefaultValue: []string{},
|
||||
@@ -163,35 +167,13 @@ Examples:
|
||||
|
||||
// Service Endpoint Filter List
|
||||
err = config.Register(&config.Option{
|
||||
Name: "Service Endpoint Filter List",
|
||||
Key: CfgOptionServiceEndpointsKey,
|
||||
Description: "Filter incoming connections by matching the source endpoint. Network Scope restrictions and the inbound permission still apply. Also not that the implicit default action of this list is to always block.",
|
||||
Help: `Format:
|
||||
Permission:
|
||||
"+": permit
|
||||
"-": block
|
||||
Host Matching:
|
||||
IP, CIDR, Country Code, ASN, Filterlist, "*" for any
|
||||
Domains:
|
||||
"example.com": exact match
|
||||
".example.com": exact match + subdomains
|
||||
"*xample.com": prefix wildcard
|
||||
"example.*": suffix wildcard
|
||||
"*example*": prefix and suffix wildcard
|
||||
Protocol and Port Matching (optional):
|
||||
<protocol>/<port>
|
||||
|
||||
Examples:
|
||||
+ .example.com */HTTP
|
||||
- .example.com
|
||||
+ 192.168.0.1/24
|
||||
- L:MAL
|
||||
- AS0
|
||||
+ AT
|
||||
- *`,
|
||||
Name: "Service Endpoint Filter List",
|
||||
Key: CfgOptionServiceEndpointsKey,
|
||||
Description: "Filter incoming connections by matching the source endpoint. Network Scope restrictions and the inbound permission still apply. Also not that the implicit default action of this list is to always block.",
|
||||
Help: filterListHelp,
|
||||
Order: cfgOptionServiceEndpointsOrder,
|
||||
OptType: config.OptTypeStringArray,
|
||||
DefaultValue: []string{},
|
||||
DefaultValue: []string{"+ Localhost"},
|
||||
ExternalOptType: "endpoint list",
|
||||
ValidationRegex: `^(\+|\-) [A-z0-9\.:\-*/]+( [A-z0-9/]+)?$`,
|
||||
})
|
||||
|
||||
112
profile/endpoints/endpoint-scopes.go
Normal file
112
profile/endpoints/endpoint-scopes.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package endpoints
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/safing/portmaster/network/netutils"
|
||||
|
||||
"github.com/safing/portmaster/intel"
|
||||
)
|
||||
|
||||
const (
|
||||
scopeLocalhost = 1
|
||||
scopeLocalhostName = "Localhost"
|
||||
scopeLocalhostMatcher = "localhost"
|
||||
|
||||
scopeLAN = 2
|
||||
scopeLANName = "LAN"
|
||||
scopeLANMatcher = "lan"
|
||||
|
||||
scopeInternet = 4
|
||||
scopeInternetName = "Internet"
|
||||
scopeInternetMatcher = "internet"
|
||||
)
|
||||
|
||||
// EndpointScope matches network scopes.
|
||||
type EndpointScope struct {
|
||||
EndpointBase
|
||||
|
||||
scopes uint8
|
||||
}
|
||||
|
||||
// Localhost
|
||||
// LAN
|
||||
// Internet
|
||||
|
||||
// Matches checks whether the given entity matches this endpoint definition.
|
||||
func (ep *EndpointScope) Matches(entity *intel.Entity) (EPResult, Reason) {
|
||||
if entity.IP == nil {
|
||||
return Undeterminable, nil
|
||||
}
|
||||
|
||||
classification := netutils.ClassifyIP(entity.IP)
|
||||
var scope uint8
|
||||
switch classification {
|
||||
case netutils.HostLocal:
|
||||
scope = scopeLocalhost
|
||||
case netutils.LinkLocal:
|
||||
scope = scopeLAN
|
||||
case netutils.SiteLocal:
|
||||
scope = scopeLAN
|
||||
case netutils.Global:
|
||||
scope = scopeInternet
|
||||
case netutils.LocalMulticast:
|
||||
scope = scopeLAN
|
||||
case netutils.GlobalMulticast:
|
||||
scope = scopeInternet
|
||||
}
|
||||
|
||||
if ep.scopes&scope > 0 {
|
||||
return ep.match(ep, entity, ep.Scopes(), "scope matches")
|
||||
}
|
||||
return NoMatch, nil
|
||||
}
|
||||
|
||||
// Scopes returns the string representation of all scopes.
|
||||
func (ep *EndpointScope) Scopes() string {
|
||||
if ep.scopes == 3 || ep.scopes > 4 {
|
||||
// single scope
|
||||
switch ep.scopes {
|
||||
case scopeLocalhost:
|
||||
return scopeLocalhostName
|
||||
case scopeLAN:
|
||||
return scopeLANName
|
||||
case scopeInternet:
|
||||
return scopeInternetName
|
||||
}
|
||||
}
|
||||
|
||||
// multiple scopes
|
||||
var s []string
|
||||
if ep.scopes&scopeLocalhost > 0 {
|
||||
s = append(s, scopeLocalhostName)
|
||||
}
|
||||
if ep.scopes&scopeLAN > 0 {
|
||||
s = append(s, scopeLANName)
|
||||
}
|
||||
if ep.scopes&scopeInternet > 0 {
|
||||
s = append(s, scopeInternetName)
|
||||
}
|
||||
return strings.Join(s, ",")
|
||||
}
|
||||
|
||||
func (ep *EndpointScope) String() string {
|
||||
return ep.renderPPP(ep.Scopes())
|
||||
}
|
||||
|
||||
func parseTypeScope(fields []string) (Endpoint, error) {
|
||||
ep := &EndpointScope{}
|
||||
for _, val := range strings.Split(strings.ToLower(fields[1]), ",") {
|
||||
switch val {
|
||||
case scopeLocalhostMatcher:
|
||||
ep.scopes &= scopeLocalhost
|
||||
case scopeLANMatcher:
|
||||
ep.scopes &= scopeLAN
|
||||
case scopeInternetMatcher:
|
||||
ep.scopes &= scopeInternet
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
return ep.parsePPP(ep, fields)
|
||||
}
|
||||
@@ -231,6 +231,10 @@ func parseEndpoint(value string) (endpoint Endpoint, err error) {
|
||||
if endpoint, err = parseTypeASN(fields); endpoint != nil || err != nil {
|
||||
return
|
||||
}
|
||||
// scopes
|
||||
if endpoint, err = parseTypeScope(fields); endpoint != nil || err != nil {
|
||||
return
|
||||
}
|
||||
// lists
|
||||
if endpoint, err = parseTypeList(fields); endpoint != nil || err != nil {
|
||||
return
|
||||
|
||||
@@ -342,7 +342,26 @@ func TestEndpointMatching(t *testing.T) {
|
||||
IP: net.ParseIP("151.101.1.164"), // nytimes.com
|
||||
}).Init(), NoMatch)
|
||||
|
||||
// Scope
|
||||
|
||||
ep, err = parseEndpoint("+ Localhost,LAN")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testEndpointMatch(t, ep, (&intel.Entity{
|
||||
IP: net.ParseIP("192.168.0.1"),
|
||||
}).Init(), Permitted)
|
||||
testEndpointMatch(t, ep, (&intel.Entity{
|
||||
IP: net.ParseIP("151.101.1.164"), // nytimes.com
|
||||
}).Init(), NoMatch)
|
||||
|
||||
// Lists
|
||||
|
||||
ep, err = parseEndpoint("+ L:A,B,C")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// TODO: write test for lists matcher
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user