mirror of
https://github.com/safing/portmaster
synced 2025-09-01 18:19:12 +00:00
Merge pull request #176 from safing/fix/domain-endpoint-validation
Fix domain endpoint validation
This commit is contained in:
commit
3b5b2282c4
2 changed files with 86 additions and 47 deletions
|
@ -5,6 +5,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/safing/portmaster/intel"
|
||||
"github.com/safing/portmaster/network/netutils"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -16,8 +17,7 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
domainRegex = regexp.MustCompile(`^\*?(([a-z0-9][a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z]{2,}\.?$`)
|
||||
altDomainRegex = regexp.MustCompile(`^\*?[a-z0-9\.-]+\*$`)
|
||||
allowedDomainChars = regexp.MustCompile(`^[a-z0-9\.-]+$`)
|
||||
)
|
||||
|
||||
// EndpointDomain matches domains.
|
||||
|
@ -90,51 +90,63 @@ func (ep *EndpointDomain) String() string {
|
|||
|
||||
func parseTypeDomain(fields []string) (Endpoint, error) {
|
||||
domain := fields[1]
|
||||
|
||||
if domainRegex.MatchString(domain) || altDomainRegex.MatchString(domain) {
|
||||
ep := &EndpointDomain{
|
||||
OriginalValue: domain,
|
||||
}
|
||||
|
||||
// fix domain ending
|
||||
switch domain[len(domain)-1] {
|
||||
case '.':
|
||||
case '*':
|
||||
default:
|
||||
domain += "."
|
||||
}
|
||||
|
||||
// fix domain case
|
||||
domain = strings.ToLower(domain)
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(domain, "*") && strings.HasSuffix(domain, "*"):
|
||||
ep.MatchType = domainMatchTypeContains
|
||||
ep.Domain = strings.Trim(domain, "*")
|
||||
return ep.parsePPP(ep, fields)
|
||||
|
||||
case strings.HasSuffix(domain, "*"):
|
||||
ep.MatchType = domainMatchTypePrefix
|
||||
ep.Domain = strings.Trim(domain, "*")
|
||||
return ep.parsePPP(ep, fields)
|
||||
|
||||
case strings.HasPrefix(domain, "*"):
|
||||
ep.MatchType = domainMatchTypeSuffix
|
||||
ep.Domain = strings.Trim(domain, "*")
|
||||
return ep.parsePPP(ep, fields)
|
||||
|
||||
case strings.HasPrefix(domain, "."):
|
||||
ep.MatchType = domainMatchTypeZone
|
||||
ep.Domain = strings.TrimLeft(domain, ".")
|
||||
ep.DomainZone = "." + ep.Domain
|
||||
return ep.parsePPP(ep, fields)
|
||||
|
||||
default:
|
||||
ep.MatchType = domainMatchTypeExact
|
||||
ep.Domain = domain
|
||||
return ep.parsePPP(ep, fields)
|
||||
}
|
||||
ep := &EndpointDomain{
|
||||
OriginalValue: domain,
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
// Fix domain ending.
|
||||
switch domain[len(domain)-1] {
|
||||
case '.', '*':
|
||||
default:
|
||||
domain += "."
|
||||
}
|
||||
|
||||
// Fix domain case.
|
||||
domain = strings.ToLower(domain)
|
||||
needValidFQDN := true
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(domain, "*") && strings.HasSuffix(domain, "*"):
|
||||
ep.MatchType = domainMatchTypeContains
|
||||
ep.Domain = strings.TrimPrefix(domain, "*")
|
||||
ep.Domain = strings.TrimSuffix(ep.Domain, "*")
|
||||
needValidFQDN = false
|
||||
|
||||
case strings.HasSuffix(domain, "*"):
|
||||
ep.MatchType = domainMatchTypePrefix
|
||||
ep.Domain = strings.TrimSuffix(domain, "*")
|
||||
needValidFQDN = false
|
||||
|
||||
// Prefix matching cannot be combined with zone matching
|
||||
if strings.HasPrefix(ep.Domain, ".") {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
case strings.HasPrefix(domain, "*"):
|
||||
ep.MatchType = domainMatchTypeSuffix
|
||||
ep.Domain = strings.TrimPrefix(domain, "*")
|
||||
needValidFQDN = false
|
||||
|
||||
case strings.HasPrefix(domain, "."):
|
||||
ep.MatchType = domainMatchTypeZone
|
||||
ep.Domain = strings.TrimPrefix(domain, ".")
|
||||
ep.DomainZone = "." + ep.Domain
|
||||
|
||||
default:
|
||||
ep.MatchType = domainMatchTypeExact
|
||||
ep.Domain = domain
|
||||
}
|
||||
|
||||
// Validate domain "content".
|
||||
switch {
|
||||
case needValidFQDN && !netutils.IsValidFqdn(ep.Domain):
|
||||
return nil, nil
|
||||
case !needValidFQDN && !allowedDomainChars.MatchString(ep.Domain):
|
||||
return nil, nil
|
||||
case strings.Contains(ep.Domain, ".."):
|
||||
// The above regex does not catch double dots.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return ep.parsePPP(ep, fields)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/safing/portmaster/core/pmtesting"
|
||||
"github.com/safing/portmaster/intel"
|
||||
)
|
||||
|
@ -27,6 +29,31 @@ func testEndpointMatch(t *testing.T, ep Endpoint, entity *intel.Entity, expected
|
|||
}
|
||||
}
|
||||
|
||||
func testFormat(t *testing.T, endpoint string, shouldSucceed bool) {
|
||||
_, err := parseEndpoint(endpoint)
|
||||
if shouldSucceed {
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
assert.Error(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEndpointFormat(t *testing.T) {
|
||||
testFormat(t, "+ .", false)
|
||||
testFormat(t, "+ .at", true)
|
||||
testFormat(t, "+ .at.", true)
|
||||
testFormat(t, "+ 1.at", true)
|
||||
testFormat(t, "+ 1.at.", true)
|
||||
testFormat(t, "+ 1.f.ix.de.", true)
|
||||
testFormat(t, "+ *contains*", true)
|
||||
testFormat(t, "+ *has.suffix", true)
|
||||
testFormat(t, "+ *.has.suffix", true)
|
||||
testFormat(t, "+ *has.prefix*", true)
|
||||
testFormat(t, "+ *has.prefix.*", true)
|
||||
testFormat(t, "+ .sub.and.prefix.*", false)
|
||||
testFormat(t, "+ *.sub..and.prefix.*", false)
|
||||
}
|
||||
|
||||
func TestEndpointMatching(t *testing.T) {
|
||||
// ANY
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue