New syntax for blocking/whitelisting rules: exact matching

Example: =example.com

Matches `example.com` but not `api.example.com`
This commit is contained in:
Frank Denis 2018-04-09 13:02:42 +02:00
parent de6a8d230e
commit 7d10628a5f
4 changed files with 20 additions and 0 deletions

View File

@ -10,6 +10,7 @@
## ads.* | matches anything with an "ads." prefix ## ads.* | matches anything with an "ads." prefix
## *.example.com | matches example.com and all names within that zone such as www.example.com ## *.example.com | matches example.com and all names within that zone such as www.example.com
## example.com | identical to the above ## example.com | identical to the above
## =example.com | block example.com but not *.example.com
## *sex* | matches any name containing that substring ## *sex* | matches any name containing that substring
## ads[0-9]* | matches "ads" followed by one or more digits ## ads[0-9]* | matches "ads" followed by one or more digits
## ads*.example* | *, ? and [] can be used anywhere, but prefixes/suffixes are faster ## ads*.example* | *, ? and [] can be used anywhere, but prefixes/suffixes are faster

View File

@ -297,6 +297,7 @@ cache_neg_ttl = 60
## Blacklists are made of one pattern per line. Example of valid patterns: ## Blacklists are made of one pattern per line. Example of valid patterns:
## ##
## example.com ## example.com
## =example.com
## *sex* ## *sex*
## ads.* ## ads.*
## ads*.example.* ## ads*.example.*

View File

@ -10,6 +10,7 @@
## ads.* | matches anything with an "ads." prefix ## ads.* | matches anything with an "ads." prefix
## *.example.com | matches example.com and all names within that zone such as www.example.com ## *.example.com | matches example.com and all names within that zone such as www.example.com
## example.com | identical to the above ## example.com | identical to the above
## =example.com | whitelists example.com but not *.example.com
## *sex* | matches any name containing that substring ## *sex* | matches any name containing that substring
## ads[0-9]* | matches "ads" followed by one or more digits ## ads[0-9]* | matches "ads" followed by one or more digits
## ads*.example* | *, ? and [] can be used anywhere, but prefixes/suffixes are faster ## ads*.example* | *, ? and [] can be used anywhere, but prefixes/suffixes are faster

View File

@ -18,6 +18,7 @@ const (
PatternTypeSuffix PatternTypeSuffix
PatternTypeSubstring PatternTypeSubstring
PatternTypePattern PatternTypePattern
PatternTypeExact
) )
type PatternMatcher struct { type PatternMatcher struct {
@ -25,6 +26,7 @@ type PatternMatcher struct {
blockedSuffixes *critbitgo.Trie blockedSuffixes *critbitgo.Trie
blockedSubstrings []string blockedSubstrings []string
blockedPatterns []string blockedPatterns []string
blockedExact map[string]interface{}
indirectVals map[string]interface{} indirectVals map[string]interface{}
} }
@ -32,6 +34,7 @@ func NewPatternPatcher() *PatternMatcher {
patternMatcher := PatternMatcher{ patternMatcher := PatternMatcher{
blockedPrefixes: critbitgo.NewTrie(), blockedPrefixes: critbitgo.NewTrie(),
blockedSuffixes: critbitgo.NewTrie(), blockedSuffixes: critbitgo.NewTrie(),
blockedExact: make(map[string]interface{}),
indirectVals: make(map[string]interface{}), indirectVals: make(map[string]interface{}),
} }
return &patternMatcher return &patternMatcher
@ -51,6 +54,7 @@ func isGlobCandidate(str string) bool {
func (patternMatcher *PatternMatcher) Add(pattern string, val interface{}, position int) (PatternType, error) { func (patternMatcher *PatternMatcher) Add(pattern string, val interface{}, position int) (PatternType, error) {
leadingStar := strings.HasPrefix(pattern, "*") leadingStar := strings.HasPrefix(pattern, "*")
trailingStar := strings.HasSuffix(pattern, "*") trailingStar := strings.HasSuffix(pattern, "*")
exact := strings.HasPrefix(pattern, "=")
patternType := PatternTypeNone patternType := PatternTypeNone
if isGlobCandidate(pattern) { if isGlobCandidate(pattern) {
patternType = PatternTypePattern patternType = PatternTypePattern
@ -70,6 +74,12 @@ func (patternMatcher *PatternMatcher) Add(pattern string, val interface{}, posit
return patternType, fmt.Errorf("Syntax error in block rules at pattern %d", position) return patternType, fmt.Errorf("Syntax error in block rules at pattern %d", position)
} }
pattern = pattern[:len(pattern)-1] pattern = pattern[:len(pattern)-1]
} else if exact {
patternType = PatternTypeExact
if len(pattern) < 2 {
return patternType, fmt.Errorf("Syntax error in block rules at pattern %d", position)
}
pattern = pattern[1:]
} else { } else {
patternType = PatternTypeSuffix patternType = PatternTypeSuffix
if leadingStar { if leadingStar {
@ -97,6 +107,8 @@ func (patternMatcher *PatternMatcher) Add(pattern string, val interface{}, posit
patternMatcher.blockedPrefixes.Insert([]byte(pattern), val) patternMatcher.blockedPrefixes.Insert([]byte(pattern), val)
case PatternTypeSuffix: case PatternTypeSuffix:
patternMatcher.blockedSuffixes.Insert([]byte(StringReverse(pattern)), val) patternMatcher.blockedSuffixes.Insert([]byte(StringReverse(pattern)), val)
case PatternTypeExact:
patternMatcher.blockedExact[pattern] = val
default: default:
dlog.Fatal("Unexpected block type") dlog.Fatal("Unexpected block type")
} }
@ -140,5 +152,10 @@ func (patternMatcher *PatternMatcher) Eval(qName string) (reject bool, reason st
return true, pattern, patternMatcher.indirectVals[pattern] return true, pattern, patternMatcher.indirectVals[pattern]
} }
} }
if xval := patternMatcher.blockedExact[qName]; xval != nil {
return true, qName, xval
}
return false, "", nil return false, "", nil
} }