1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-07-05 13:35:23 +00:00
v2fly/common/strmatcher/matchergroup_domain.go

102 lines
2.0 KiB
Go
Raw Normal View History

2018-08-19 19:04:15 +00:00
package strmatcher
import "strings"
func breakDomain(domain string) []string {
return strings.Split(domain, ".")
}
type node struct {
values []uint32
sub map[string]*node
2018-08-19 19:04:15 +00:00
}
// DomainMatcherGroup is an implementation of MatcherGroup.
// It uses trie to optimize both memory consumption and lookup speed. Trie node is domain label based.
2018-08-19 19:04:15 +00:00
type DomainMatcherGroup struct {
root *node
}
// AddDomainMatcher implements MatcherGroupForDomain.AddDomainMatcher.
func (g *DomainMatcherGroup) AddDomainMatcher(matcher DomainMatcher, value uint32) {
2018-08-19 19:04:15 +00:00
if g.root == nil {
2018-08-22 20:49:02 +00:00
g.root = new(node)
2018-08-19 19:04:15 +00:00
}
current := g.root
parts := breakDomain(matcher.Pattern())
2018-08-19 19:04:15 +00:00
for i := len(parts) - 1; i >= 0; i-- {
part := parts[i]
2018-08-22 20:49:02 +00:00
if current.sub == nil {
current.sub = make(map[string]*node)
}
2018-08-19 19:04:15 +00:00
next := current.sub[part]
if next == nil {
2018-08-22 20:49:02 +00:00
next = new(node)
2018-08-19 19:04:15 +00:00
current.sub[part] = next
}
current = next
}
current.values = append(current.values, value)
2018-08-19 19:04:15 +00:00
}
// Match implements MatcherGroup.Match.
func (g *DomainMatcherGroup) Match(domain string) []uint32 {
if domain == "" {
return nil
2018-11-02 11:14:41 +00:00
}
2018-08-19 19:04:15 +00:00
current := g.root
if current == nil {
return nil
}
2018-11-02 11:14:41 +00:00
nextPart := func(idx int) int {
for i := idx - 1; i >= 0; i-- {
if domain[i] == '.' {
return i
}
}
return -1
}
matches := [][]uint32{}
2018-11-02 11:14:41 +00:00
idx := len(domain)
for {
if idx == -1 || current.sub == nil {
2018-08-22 20:49:02 +00:00
break
}
2018-11-02 11:14:41 +00:00
nidx := nextPart(idx)
part := domain[nidx+1 : idx]
2018-08-19 19:04:15 +00:00
next := current.sub[part]
if next == nil {
break
}
current = next
2018-11-02 11:14:41 +00:00
idx = nidx
if len(current.values) > 0 {
matches = append(matches, current.values)
}
}
switch len(matches) {
case 0:
return nil
case 1:
return matches[0]
default:
result := []uint32{}
for idx := range matches {
// Insert reversely, the subdomain that matches further ranks higher
result = append(result, matches[len(matches)-1-idx]...)
}
return result
2018-08-19 19:04:15 +00:00
}
}
// MatchAny implements MatcherGroup.MatchAny.
func (g *DomainMatcherGroup) MatchAny(domain string) bool {
return len(g.Match(domain)) > 0
}