github.com/kelleygo/clashcore@v1.0.2/dns/filters.go (about) 1 package dns 2 3 import ( 4 "net/netip" 5 "strings" 6 7 "github.com/kelleygo/clashcore/component/geodata" 8 "github.com/kelleygo/clashcore/component/geodata/router" 9 "github.com/kelleygo/clashcore/component/mmdb" 10 "github.com/kelleygo/clashcore/component/trie" 11 C "github.com/kelleygo/clashcore/constant" 12 "github.com/kelleygo/clashcore/log" 13 ) 14 15 type fallbackIPFilter interface { 16 Match(netip.Addr) bool 17 } 18 19 type geoipFilter struct { 20 code string 21 } 22 23 var geoIPMatcher *router.GeoIPMatcher 24 25 func (gf *geoipFilter) Match(ip netip.Addr) bool { 26 if !C.GeodataMode { 27 codes := mmdb.IPInstance().LookupCode(ip.AsSlice()) 28 for _, code := range codes { 29 if !strings.EqualFold(code, gf.code) && !ip.IsPrivate() { 30 return true 31 } 32 } 33 return false 34 } 35 36 if geoIPMatcher == nil { 37 var err error 38 geoIPMatcher, _, err = geodata.LoadGeoIPMatcher("CN") 39 if err != nil { 40 log.Errorln("[GeoIPFilter] LoadGeoIPMatcher error: %s", err.Error()) 41 return false 42 } 43 } 44 return !geoIPMatcher.Match(ip) 45 } 46 47 type ipnetFilter struct { 48 ipnet netip.Prefix 49 } 50 51 func (inf *ipnetFilter) Match(ip netip.Addr) bool { 52 return inf.ipnet.Contains(ip) 53 } 54 55 type fallbackDomainFilter interface { 56 Match(domain string) bool 57 } 58 59 type domainFilter struct { 60 tree *trie.DomainTrie[struct{}] 61 } 62 63 func NewDomainFilter(domains []string) *domainFilter { 64 df := domainFilter{tree: trie.New[struct{}]()} 65 for _, domain := range domains { 66 _ = df.tree.Insert(domain, struct{}{}) 67 } 68 df.tree.Optimize() 69 return &df 70 } 71 72 func (df *domainFilter) Match(domain string) bool { 73 return df.tree.Search(domain) != nil 74 } 75 76 type geoSiteFilter struct { 77 matchers []router.DomainMatcher 78 } 79 80 func NewGeoSite(group string) (fallbackDomainFilter, error) { 81 if err := geodata.InitGeoSite(); err != nil { 82 log.Errorln("can't initial GeoSite: %s", err) 83 return nil, err 84 } 85 matcher, _, err := geodata.LoadGeoSiteMatcher(group) 86 if err != nil { 87 return nil, err 88 } 89 filter := &geoSiteFilter{ 90 matchers: []router.DomainMatcher{matcher}, 91 } 92 return filter, nil 93 } 94 95 func (gsf *geoSiteFilter) Match(domain string) bool { 96 for _, matcher := range gsf.matchers { 97 if matcher.ApplyDomain(domain) { 98 return true 99 } 100 } 101 return false 102 }