mirror of
https://github.com/safing/portmaster
synced 2025-09-01 18:19:12 +00:00
136 lines
3.6 KiB
Go
136 lines
3.6 KiB
Go
package profile
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/Safing/portmaster/intel"
|
|
)
|
|
|
|
// Endpoints is a list of permitted or denied endpoints.
|
|
type Endpoints []*EndpointPermission
|
|
|
|
// EndpointPermission holds a decision about an endpoint.
|
|
type EndpointPermission struct {
|
|
DomainOrIP string
|
|
Wildcard bool
|
|
Protocol uint8
|
|
StartPort uint16
|
|
EndPort uint16
|
|
Permit bool
|
|
Created int64
|
|
}
|
|
|
|
// IsSet returns whether the Endpoints object is "set".
|
|
func (e Endpoints) IsSet() bool {
|
|
if len(e) > 0 {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Check checks if the given domain is governed in the list of domains and returns whether it is permitted.
|
|
// If getDomainOfIP (returns reverse and forward dns matching domain name) is supplied, an IP will be resolved to a domain, if necessary.
|
|
func (e Endpoints) Check(domainOrIP string, protocol uint8, port uint16, checkReverseIP bool, securityLevel uint8) (permit bool, reason string, ok bool) {
|
|
|
|
// ip resolving
|
|
var cachedGetDomainOfIP func() string
|
|
if checkReverseIP {
|
|
var ipResolved bool
|
|
var ipName string
|
|
// setup caching wrapper
|
|
cachedGetDomainOfIP = func() string {
|
|
if !ipResolved {
|
|
result, err := intel.ResolveIPAndValidate(domainOrIP, securityLevel)
|
|
if err != nil {
|
|
// log.Debug()
|
|
ipName = result
|
|
}
|
|
ipResolved = true
|
|
}
|
|
return ipName
|
|
}
|
|
}
|
|
|
|
isDomain := strings.HasSuffix(domainOrIP, ".")
|
|
|
|
for _, entry := range e {
|
|
if ok, reason := entry.Matches(domainOrIP, protocol, port, isDomain, cachedGetDomainOfIP); ok {
|
|
return entry.Permit, reason, true
|
|
}
|
|
}
|
|
|
|
return false, "", false
|
|
}
|
|
|
|
func isSubdomainOf(domain, subdomain string) bool {
|
|
dotPrefixedDomain := "." + domain
|
|
return strings.HasSuffix(subdomain, dotPrefixedDomain)
|
|
}
|
|
|
|
// Matches checks whether the given endpoint has a managed permission. If getDomainOfIP (returns reverse and forward dns matching domain name) is supplied, this declares an incoming connection.
|
|
func (ep EndpointPermission) Matches(domainOrIP string, protocol uint8, port uint16, isDomain bool, getDomainOfIP func() string) (match bool, reason string) {
|
|
if ep.Protocol > 0 && protocol != ep.Protocol {
|
|
return false, ""
|
|
}
|
|
|
|
if ep.StartPort > 0 && (port < ep.StartPort || port > ep.EndPort) {
|
|
return false, ""
|
|
}
|
|
|
|
switch {
|
|
case ep.Wildcard && len(ep.DomainOrIP) == 0:
|
|
// host wildcard
|
|
return true, fmt.Sprintf("%s matches %s", domainOrIP, ep)
|
|
case domainOrIP == ep.DomainOrIP:
|
|
// host match
|
|
return true, fmt.Sprintf("%s matches %s", domainOrIP, ep)
|
|
case isDomain && ep.Wildcard && isSubdomainOf(ep.DomainOrIP, domainOrIP):
|
|
// subdomain match
|
|
return true, fmt.Sprintf("%s matches %s", domainOrIP, ep)
|
|
case !isDomain && getDomainOfIP != nil && getDomainOfIP() == ep.DomainOrIP:
|
|
// resolved IP match
|
|
return true, fmt.Sprintf("%s->%s matches %s", domainOrIP, getDomainOfIP(), ep)
|
|
case !isDomain && getDomainOfIP != nil && ep.Wildcard && isSubdomainOf(ep.DomainOrIP, getDomainOfIP()):
|
|
// resolved IP subdomain match
|
|
return true, fmt.Sprintf("%s->%s matches %s", domainOrIP, getDomainOfIP(), ep)
|
|
default:
|
|
// no match
|
|
return false, ""
|
|
}
|
|
}
|
|
|
|
func (e Endpoints) String() string {
|
|
var s []string
|
|
for _, entry := range e {
|
|
s = append(s, entry.String())
|
|
}
|
|
return fmt.Sprintf("[%s]", strings.Join(s, ", "))
|
|
}
|
|
|
|
func (ep EndpointPermission) String() string {
|
|
s := ep.DomainOrIP
|
|
|
|
s += " "
|
|
|
|
if ep.Protocol > 0 {
|
|
s += strconv.Itoa(int(ep.Protocol))
|
|
} else {
|
|
s += "*"
|
|
}
|
|
|
|
s += "/"
|
|
|
|
if ep.StartPort > 0 {
|
|
if ep.StartPort == ep.EndPort {
|
|
s += strconv.Itoa(int(ep.StartPort))
|
|
} else {
|
|
s += fmt.Sprintf("%d-%d", ep.StartPort, ep.EndPort)
|
|
}
|
|
} else {
|
|
s += "*"
|
|
}
|
|
|
|
return s
|
|
}
|