github.com/sagernet/sing@v0.2.6/common/domain/matcher.go (about) 1 package domain 2 3 import ( 4 "sort" 5 "unicode/utf8" 6 ) 7 8 type Matcher struct { 9 set *succinctSet 10 } 11 12 func NewMatcher(domains []string, domainSuffix []string) *Matcher { 13 domainList := make([]string, 0, len(domains)+len(domainSuffix)) 14 seen := make(map[string]bool, len(domainList)) 15 for _, domain := range domainSuffix { 16 if seen[domain] { 17 continue 18 } 19 seen[domain] = true 20 domainList = append(domainList, reverseDomainSuffix(domain)) 21 } 22 for _, domain := range domains { 23 if seen[domain] { 24 continue 25 } 26 seen[domain] = true 27 domainList = append(domainList, reverseDomain(domain)) 28 } 29 sort.Strings(domainList) 30 return &Matcher{ 31 newSuccinctSet(domainList), 32 } 33 } 34 35 func (m *Matcher) Match(domain string) bool { 36 return m.set.Has(reverseDomain(domain)) 37 } 38 39 func reverseDomain(domain string) string { 40 l := len(domain) 41 b := make([]byte, l) 42 for i := 0; i < l; { 43 r, n := utf8.DecodeRuneInString(domain[i:]) 44 i += n 45 utf8.EncodeRune(b[l-i:], r) 46 } 47 return string(b) 48 } 49 50 func reverseDomainSuffix(domain string) string { 51 l := len(domain) 52 b := make([]byte, l+1) 53 for i := 0; i < l; { 54 r, n := utf8.DecodeRuneInString(domain[i:]) 55 i += n 56 utf8.EncodeRune(b[l-i:], r) 57 } 58 b[l] = prefixLabel 59 return string(b) 60 }