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  }