From 92ec5f223681a3dcf1f97e986717cfae353a66e1 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 15 Aug 2024 20:04:24 +0800 Subject: [PATCH] chore: cleanup dns policy match code --- config/config.go | 308 ++++++++++++++++------------------- constant/rule.go | 8 + constant/rule_extra.go | 17 -- dns/filters.go | 102 ------------ dns/policy.go | 27 +-- dns/resolver.go | 121 ++++---------- hub/executor/executor.go | 33 ++-- rules/provider/domain_set.go | 5 +- rules/provider/ipcidr_set.go | 40 +++++ 9 files changed, 241 insertions(+), 420 deletions(-) delete mode 100644 constant/rule_extra.go delete mode 100644 dns/filters.go create mode 100644 rules/provider/ipcidr_set.go diff --git a/config/config.go b/config/config.go index 74ffdd03..c1c155ec 100644 --- a/config/config.go +++ b/config/config.go @@ -20,9 +20,9 @@ import ( N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/mihomo/component/auth" + "github.com/metacubex/mihomo/component/cidr" "github.com/metacubex/mihomo/component/fakeip" "github.com/metacubex/mihomo/component/geodata" - "github.com/metacubex/mihomo/component/geodata/router" P "github.com/metacubex/mihomo/component/process" "github.com/metacubex/mihomo/component/resolver" SNIFF "github.com/metacubex/mihomo/component/sniffer" @@ -114,33 +114,25 @@ type NTP struct { // DNS config type DNS struct { - Enable bool `yaml:"enable"` - PreferH3 bool `yaml:"prefer-h3"` - IPv6 bool `yaml:"ipv6"` - IPv6Timeout uint `yaml:"ipv6-timeout"` - UseSystemHosts bool `yaml:"use-system-hosts"` - NameServer []dns.NameServer `yaml:"nameserver"` - Fallback []dns.NameServer `yaml:"fallback"` - FallbackFilter FallbackFilter `yaml:"fallback-filter"` - Listen string `yaml:"listen"` - EnhancedMode C.DNSMode `yaml:"enhanced-mode"` - DefaultNameserver []dns.NameServer `yaml:"default-nameserver"` - CacheAlgorithm string `yaml:"cache-algorithm"` + Enable bool + PreferH3 bool + IPv6 bool + IPv6Timeout uint + UseSystemHosts bool + NameServer []dns.NameServer + Fallback []dns.NameServer + FallbackIPFilter []C.Rule + FallbackDomainFilter []C.Rule + Listen string + EnhancedMode C.DNSMode + DefaultNameserver []dns.NameServer + CacheAlgorithm string FakeIPRange *fakeip.Pool Hosts *trie.DomainTrie[resolver.HostValue] - NameServerPolicy *orderedmap.OrderedMap[string, []dns.NameServer] + NameServerPolicy []dns.Policy ProxyServerNameserver []dns.NameServer } -// FallbackFilter config -type FallbackFilter struct { - GeoIP bool `yaml:"geoip"` - GeoIPCode string `yaml:"geoip-code"` - IPCIDR []netip.Prefix `yaml:"ipcidr"` - Domain []string `yaml:"domain"` - GeoSite []router.DomainMatcher `yaml:"geosite"` -} - // Profile config type Profile struct { StoreSelected bool `yaml:"store-selected"` @@ -1205,49 +1197,13 @@ func parsePureDNSServer(server string) string { } } -func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], ruleProviders map[string]providerTypes.RuleProvider, respectRules bool, preferH3 bool) (*orderedmap.OrderedMap[string, []dns.NameServer], error) { - policy := orderedmap.New[string, []dns.NameServer]() - updatedPolicy := orderedmap.New[string, any]() +func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rules []C.Rule, ruleProviders map[string]providerTypes.RuleProvider, respectRules bool, preferH3 bool) ([]dns.Policy, error) { + var policy []dns.Policy re := regexp.MustCompile(`[a-zA-Z0-9\-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?`) for pair := nsPolicy.Oldest(); pair != nil; pair = pair.Next() { k, v := pair.Key, pair.Value - if strings.Contains(strings.ToLower(k), ",") { - if strings.Contains(k, "geosite:") { - subkeys := strings.Split(k, ":") - subkeys = subkeys[1:] - subkeys = strings.Split(subkeys[0], ",") - for _, subkey := range subkeys { - newKey := "geosite:" + subkey - updatedPolicy.Store(newKey, v) - } - } else if strings.Contains(strings.ToLower(k), "rule-set:") { - subkeys := strings.Split(k, ":") - subkeys = subkeys[1:] - subkeys = strings.Split(subkeys[0], ",") - for _, subkey := range subkeys { - newKey := "rule-set:" + subkey - updatedPolicy.Store(newKey, v) - } - } else if re.MatchString(k) { - subkeys := strings.Split(k, ",") - for _, subkey := range subkeys { - updatedPolicy.Store(subkey, v) - } - } - } else { - if strings.Contains(strings.ToLower(k), "geosite:") { - updatedPolicy.Store("geosite:"+k[8:], v) - } else if strings.Contains(strings.ToLower(k), "rule-set:") { - updatedPolicy.Store("rule-set:"+k[9:], v) - } - updatedPolicy.Store(k, v) - } - } - - for pair := updatedPolicy.Oldest(); pair != nil; pair = pair.Next() { - domain, server := pair.Key, pair.Value - servers, err := utils.ToStringSlice(server) + servers, err := utils.ToStringSlice(v) if err != nil { return nil, err } @@ -1255,75 +1211,65 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rulePro if err != nil { return nil, err } - if _, valid := trie.ValidAndSplitDomain(domain); !valid { - return nil, fmt.Errorf("DNS ResoverRule invalid domain: %s", domain) + if strings.Contains(strings.ToLower(k), ",") { + if strings.Contains(k, "geosite:") { + subkeys := strings.Split(k, ":") + subkeys = subkeys[1:] + subkeys = strings.Split(subkeys[0], ",") + for _, subkey := range subkeys { + newKey := "geosite:" + subkey + policy = append(policy, dns.Policy{Domain: newKey, NameServers: nameservers}) + } + } else if strings.Contains(strings.ToLower(k), "rule-set:") { + subkeys := strings.Split(k, ":") + subkeys = subkeys[1:] + subkeys = strings.Split(subkeys[0], ",") + for _, subkey := range subkeys { + newKey := "rule-set:" + subkey + policy = append(policy, dns.Policy{Domain: newKey, NameServers: nameservers}) + } + } else if re.MatchString(k) { + subkeys := strings.Split(k, ",") + for _, subkey := range subkeys { + policy = append(policy, dns.Policy{Domain: subkey, NameServers: nameservers}) + } + } + } else { + if strings.Contains(strings.ToLower(k), "geosite:") { + policy = append(policy, dns.Policy{Domain: "geosite:" + k[8:], NameServers: nameservers}) + } else if strings.Contains(strings.ToLower(k), "rule-set:") { + policy = append(policy, dns.Policy{Domain: "rule-set:" + k[9:], NameServers: nameservers}) + } else { + policy = append(policy, dns.Policy{Domain: k, NameServers: nameservers}) + } } + } + + for idx, p := range policy { + domain, nameservers := p.Domain, p.NameServers + if strings.HasPrefix(domain, "rule-set:") { domainSetName := domain[9:] - if provider, ok := ruleProviders[domainSetName]; !ok { - return nil, fmt.Errorf("not found rule-set: %s", domainSetName) - } else { - switch provider.Behavior() { - case providerTypes.IPCIDR: - return nil, fmt.Errorf("rule provider type error, except domain,actual %s", provider.Behavior()) - case providerTypes.Classical: - log.Warnln("%s provider is %s, only matching it contain domain rule", provider.Name(), provider.Behavior()) - } - } - } - policy.Store(domain, nameservers) - } - - return policy, nil -} - -func parseFallbackIPCIDR(ips []string) ([]netip.Prefix, error) { - var ipNets []netip.Prefix - - for idx, ip := range ips { - ipnet, err := netip.ParsePrefix(ip) - if err != nil { - return nil, fmt.Errorf("DNS FallbackIP[%d] format error: %s", idx, err.Error()) - } - ipNets = append(ipNets, ipnet) - } - - return ipNets, nil -} - -func parseFallbackGeoSite(countries []string, rules []C.Rule) ([]router.DomainMatcher, error) { - var sites []router.DomainMatcher - if len(countries) > 0 { - if err := geodata.InitGeoSite(); err != nil { - return nil, fmt.Errorf("can't initial GeoSite: %s", err) - } - log.Warnln("replace fallback-filter.geosite with nameserver-policy, it will be removed in the future") - } - - for _, country := range countries { - found := false - for _, rule := range rules { - if rule.RuleType() == C.GEOSITE { - if strings.EqualFold(country, rule.Payload()) { - found = true - sites = append(sites, rule.(C.RuleGeoSite).GetDomainMatcher()) - log.Infoln("Start initial GeoSite dns fallback filter from rule `%s`", country) - } - } - } - - if !found { - matcher, recordsCount, err := geodata.LoadGeoSiteMatcher(country) + rule, err := parseDomainRuleSet(domainSetName, ruleProviders) if err != nil { return nil, err } - - sites = append(sites, matcher) - - log.Infoln("Start initial GeoSite dns fallback filter `%s`, records: %d", country, recordsCount) + policy[idx] = dns.Policy{Rule: rule, NameServers: nameservers} + } else if strings.HasPrefix(domain, "geosite:") { + country := domain[8:] + rule, err := parseGEOSITE(country, rules) + if err != nil { + return nil, err + } + policy[idx] = dns.Policy{Rule: rule, NameServers: nameservers} + } else { + if _, valid := trie.ValidAndSplitDomain(domain); !valid { + return nil, fmt.Errorf("DNS ResoverRule invalid domain: %s", domain) + } } } - return sites, nil + + return policy, nil } func paresNTP(rawCfg *RawConfig) *NTP { @@ -1357,10 +1303,6 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul IPv6: cfg.IPv6, UseSystemHosts: cfg.UseSystemHosts, EnhancedMode: cfg.EnhancedMode, - FallbackFilter: FallbackFilter{ - IPCIDR: []netip.Prefix{}, - GeoSite: []router.DomainMatcher{}, - }, } var err error if dnsCfg.NameServer, err = parseNameServer(cfg.NameServer, cfg.RespectRules, cfg.PreferH3); err != nil { @@ -1371,7 +1313,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul return nil, err } - if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy, ruleProviders, cfg.RespectRules, cfg.PreferH3); err != nil { + if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy, rules, ruleProviders, cfg.RespectRules, cfg.PreferH3); err != nil { return nil, err } @@ -1438,18 +1380,51 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul dnsCfg.FakeIPRange = pool } + var rule C.Rule if len(cfg.Fallback) != 0 { - dnsCfg.FallbackFilter.GeoIP = cfg.FallbackFilter.GeoIP - dnsCfg.FallbackFilter.GeoIPCode = cfg.FallbackFilter.GeoIPCode - if fallbackip, err := parseFallbackIPCIDR(cfg.FallbackFilter.IPCIDR); err == nil { - dnsCfg.FallbackFilter.IPCIDR = fallbackip + if cfg.FallbackFilter.GeoIP { + rule, err = RC.NewGEOIP(cfg.FallbackFilter.GeoIPCode, "", false, true) + if err != nil { + return nil, fmt.Errorf("load GeoIP dns fallback filter error, %w", err) + } + dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, rule) } - dnsCfg.FallbackFilter.Domain = cfg.FallbackFilter.Domain - fallbackGeoSite, err := parseFallbackGeoSite(cfg.FallbackFilter.GeoSite, rules) - if err != nil { - return nil, fmt.Errorf("load GeoSite dns fallback filter error, %w", err) + if len(cfg.FallbackFilter.IPCIDR) > 0 { + cidrSet := cidr.NewIpCidrSet() + for idx, ipcidr := range cfg.FallbackFilter.IPCIDR { + err = cidrSet.AddIpCidrForString(ipcidr) + if err != nil { + return nil, fmt.Errorf("DNS FallbackIP[%d] format error: %w", idx, err) + } + } + err = cidrSet.Merge() + if err != nil { + return nil, err + } + rule = RP.NewIpCidrSet(cidrSet, "") + dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, rule) + } + if len(cfg.FallbackFilter.Domain) > 0 { + domainTrie := trie.New[struct{}]() + for idx, domain := range cfg.FallbackFilter.Domain { + err = domainTrie.Insert(domain, struct{}{}) + if err != nil { + return nil, fmt.Errorf("DNS FallbackDomain[%d] format error: %w", idx, err) + } + } + rule = RP.NewDomainSet(domainTrie.NewDomainSet(), "") + dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, rule) + } + if len(cfg.FallbackFilter.GeoSite) > 0 { + log.Warnln("replace fallback-filter.geosite with nameserver-policy, it will be removed in the future") + for idx, geoSite := range cfg.FallbackFilter.GeoSite { + rule, err = parseGEOSITE(geoSite, rules) + if err != nil { + return nil, fmt.Errorf("DNS FallbackGeosite[%d] format error: %w", idx, err) + } + dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, rule) + } } - dnsCfg.FallbackFilter.GeoSite = fallbackGeoSite } if cfg.UseHosts { @@ -1636,44 +1611,21 @@ func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], rules subkeys = subkeys[1:] subkeys = strings.Split(subkeys[0], ",") for _, country := range subkeys { - found := false - for _, rule = range rules { - if rule.RuleType() == C.GEOSITE { - if strings.EqualFold(country, rule.Payload()) { - found = true - domainRules = append(domainRules, rule) - } - } - } - if !found { - rule, err = RC.NewGEOSITE(country, "") - if err != nil { - return nil, err - } - domainRules = append(domainRules, rule) + rule, err = parseGEOSITE(country, rules) + if err != nil { + return nil, err } + domainRules = append(domainRules, rule) } } else if strings.Contains(domainLower, "rule-set:") { subkeys := strings.Split(domain, ":") subkeys = subkeys[1:] subkeys = strings.Split(subkeys[0], ",") for _, domainSetName := range subkeys { - if rp, ok := ruleProviders[domainSetName]; !ok { - return nil, fmt.Errorf("not found rule-set: %s", domainSetName) - } else { - switch rp.Behavior() { - case providerTypes.IPCIDR: - return nil, fmt.Errorf("rule provider type error, except domain,actual %s", rp.Behavior()) - case providerTypes.Classical: - log.Warnln("%s provider is %s, only matching it contain domain rule", rp.Name(), rp.Behavior()) - default: - } - } - rule, err = RP.NewRuleSet(domainSetName, "", true) + rule, err = parseDomainRuleSet(domainSetName, ruleProviders) if err != nil { return nil, err } - domainRules = append(domainRules, rule) } } else { @@ -1692,3 +1644,29 @@ func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], rules } return } + +func parseDomainRuleSet(domainSetName string, ruleProviders map[string]providerTypes.RuleProvider) (C.Rule, error) { + if rp, ok := ruleProviders[domainSetName]; !ok { + return nil, fmt.Errorf("not found rule-set: %s", domainSetName) + } else { + switch rp.Behavior() { + case providerTypes.IPCIDR: + return nil, fmt.Errorf("rule provider type error, except domain,actual %s", rp.Behavior()) + case providerTypes.Classical: + log.Warnln("%s provider is %s, only matching it contain domain rule", rp.Name(), rp.Behavior()) + default: + } + } + return RP.NewRuleSet(domainSetName, "", true) +} + +func parseGEOSITE(country string, rules []C.Rule) (C.Rule, error) { + for _, rule := range rules { + if rule.RuleType() == C.GEOSITE { + if strings.EqualFold(country, rule.Payload()) { + return rule, nil + } + } + } + return RC.NewGEOSITE(country, "") +} diff --git a/constant/rule.go b/constant/rule.go index f9f987e6..30cb2f8e 100644 --- a/constant/rule.go +++ b/constant/rule.go @@ -28,6 +28,7 @@ const ( ProcessPathRegex RuleSet DomainSet + IpCidrSet Network Uid SubRules @@ -93,6 +94,8 @@ func (rt RuleType) String() string { return "RuleSet" case DomainSet: return "DomainSet" + case IpCidrSet: + return "IpCidrSet" case Network: return "Network" case DSCP: @@ -121,3 +124,8 @@ type Rule interface { ShouldFindProcess() bool ProviderNames() []string } + +type RuleGroup interface { + Rule + GetRecodeSize() int +} diff --git a/constant/rule_extra.go b/constant/rule_extra.go deleted file mode 100644 index b4ba65d9..00000000 --- a/constant/rule_extra.go +++ /dev/null @@ -1,17 +0,0 @@ -package constant - -import ( - "github.com/metacubex/mihomo/component/geodata/router" -) - -type RuleGeoSite interface { - GetDomainMatcher() router.DomainMatcher -} - -type RuleGeoIP interface { - GetIPMatcher() *router.GeoIPMatcher -} - -type RuleGroup interface { - GetRecodeSize() int -} diff --git a/dns/filters.go b/dns/filters.go deleted file mode 100644 index 138f3429..00000000 --- a/dns/filters.go +++ /dev/null @@ -1,102 +0,0 @@ -package dns - -import ( - "net/netip" - "strings" - - "github.com/metacubex/mihomo/component/geodata" - "github.com/metacubex/mihomo/component/geodata/router" - "github.com/metacubex/mihomo/component/mmdb" - "github.com/metacubex/mihomo/component/trie" - C "github.com/metacubex/mihomo/constant" - "github.com/metacubex/mihomo/log" -) - -type fallbackIPFilter interface { - Match(netip.Addr) bool -} - -type geoipFilter struct { - code string -} - -var geoIPMatcher *router.GeoIPMatcher - -func (gf *geoipFilter) Match(ip netip.Addr) bool { - if !C.GeodataMode { - codes := mmdb.IPInstance().LookupCode(ip.AsSlice()) - for _, code := range codes { - if !strings.EqualFold(code, gf.code) && !ip.IsPrivate() { - return true - } - } - return false - } - - if geoIPMatcher == nil { - var err error - geoIPMatcher, _, err = geodata.LoadGeoIPMatcher("CN") - if err != nil { - log.Errorln("[GeoIPFilter] LoadGeoIPMatcher error: %s", err.Error()) - return false - } - } - return !geoIPMatcher.Match(ip) -} - -type ipnetFilter struct { - ipnet netip.Prefix -} - -func (inf *ipnetFilter) Match(ip netip.Addr) bool { - return inf.ipnet.Contains(ip) -} - -type fallbackDomainFilter interface { - Match(domain string) bool -} - -type domainFilter struct { - tree *trie.DomainTrie[struct{}] -} - -func NewDomainFilter(domains []string) *domainFilter { - df := domainFilter{tree: trie.New[struct{}]()} - for _, domain := range domains { - _ = df.tree.Insert(domain, struct{}{}) - } - df.tree.Optimize() - return &df -} - -func (df *domainFilter) Match(domain string) bool { - return df.tree.Search(domain) != nil -} - -type geoSiteFilter struct { - matchers []router.DomainMatcher -} - -func NewGeoSite(group string) (fallbackDomainFilter, error) { - if err := geodata.InitGeoSite(); err != nil { - log.Errorln("can't initial GeoSite: %s", err) - return nil, err - } - matcher, _, err := geodata.LoadGeoSiteMatcher(group) - if err != nil { - return nil, err - } - filter := &geoSiteFilter{ - matchers: []router.DomainMatcher{matcher}, - } - return filter, nil -} - -func (gsf *geoSiteFilter) Match(domain string) bool { - for _, matcher := range gsf.matchers { - if matcher.ApplyDomain(domain) { - return true - } - } - return false -} diff --git a/dns/policy.go b/dns/policy.go index fc60401b..d872286c 100644 --- a/dns/policy.go +++ b/dns/policy.go @@ -3,7 +3,6 @@ package dns import ( "github.com/metacubex/mihomo/component/trie" C "github.com/metacubex/mihomo/constant" - "github.com/metacubex/mihomo/constant/provider" ) type dnsPolicy interface { @@ -22,32 +21,14 @@ func (p domainTriePolicy) Match(domain string) []dnsClient { return nil } -type geositePolicy struct { - matcher fallbackDomainFilter - inverse bool +type domainRulePolicy struct { + rule C.Rule dnsClients []dnsClient } -func (p geositePolicy) Match(domain string) []dnsClient { - matched := p.matcher.Match(domain) - if matched != p.inverse { +func (p domainRulePolicy) Match(domain string) []dnsClient { + if ok, _ := p.rule.Match(&C.Metadata{Host: domain}); ok { return p.dnsClients } return nil } - -type domainSetPolicy struct { - tunnel provider.Tunnel - name string - dnsClients []dnsClient -} - -func (p domainSetPolicy) Match(domain string) []dnsClient { - if ruleProvider, ok := p.tunnel.RuleProviders()[p.name]; ok { - metadata := &C.Metadata{Host: domain} - if ok := ruleProvider.Match(metadata); ok { - return p.dnsClients - } - } - return nil -} diff --git a/dns/resolver.go b/dns/resolver.go index fc228761..7b9aafd0 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -4,13 +4,11 @@ import ( "context" "errors" "net/netip" - "strings" "time" "github.com/metacubex/mihomo/common/arc" "github.com/metacubex/mihomo/common/lru" "github.com/metacubex/mihomo/component/fakeip" - "github.com/metacubex/mihomo/component/geodata/router" "github.com/metacubex/mihomo/component/resolver" "github.com/metacubex/mihomo/component/trie" C "github.com/metacubex/mihomo/constant" @@ -19,7 +17,6 @@ import ( D "github.com/miekg/dns" "github.com/samber/lo" - orderedmap "github.com/wk8/go-ordered-map/v2" "golang.org/x/exp/maps" "golang.org/x/sync/singleflight" ) @@ -45,8 +42,8 @@ type Resolver struct { hosts *trie.DomainTrie[resolver.HostValue] main []dnsClient fallback []dnsClient - fallbackDomainFilters []fallbackDomainFilter - fallbackIPFilters []fallbackIPFilter + fallbackDomainFilters []C.Rule + fallbackIPFilters []C.Rule group singleflight.Group cache dnsCache policy []dnsPolicy @@ -122,7 +119,7 @@ func (r *Resolver) LookupIPv6(ctx context.Context, host string) ([]netip.Addr, e func (r *Resolver) shouldIPFallback(ip netip.Addr) bool { for _, filter := range r.fallbackIPFilters { - if filter.Match(ip) { + if ok, _ := filter.Match(&C.Metadata{DstIP: ip}); ok { return true } } @@ -277,7 +274,7 @@ func (r *Resolver) shouldOnlyQueryFallback(m *D.Msg) bool { } for _, df := range r.fallbackDomainFilters { - if df.Match(domain) { + if ok, _ := df.Match(&C.Metadata{Host: domain}); ok { return true } } @@ -398,27 +395,26 @@ func (ns NameServer) Equal(ns2 NameServer) bool { return false } -type FallbackFilter struct { - GeoIP bool - GeoIPCode string - IPCIDR []netip.Prefix - Domain []string - GeoSite []router.DomainMatcher +type Policy struct { + Domain string + Rule C.Rule + NameServers []NameServer } type Config struct { - Main, Fallback []NameServer - Default []NameServer - ProxyServer []NameServer - IPv6 bool - IPv6Timeout uint - EnhancedMode C.DNSMode - FallbackFilter FallbackFilter - Pool *fakeip.Pool - Hosts *trie.DomainTrie[resolver.HostValue] - Policy *orderedmap.OrderedMap[string, []NameServer] - Tunnel provider.Tunnel - CacheAlgorithm string + Main, Fallback []NameServer + Default []NameServer + ProxyServer []NameServer + IPv6 bool + IPv6Timeout uint + EnhancedMode C.DNSMode + FallbackIPFilter []C.Rule + FallbackDomainFilter []C.Rule + Pool *fakeip.Pool + Hosts *trie.DomainTrie[resolver.HostValue] + Policy []Policy + Tunnel provider.Tunnel + CacheAlgorithm string } func NewResolver(config Config) *Resolver { @@ -482,7 +478,7 @@ func NewResolver(config Config) *Resolver { r.proxyServer = cacheTransform(config.ProxyServer) } - if config.Policy.Len() != 0 { + if len(config.Policy) != 0 { r.policy = make([]dnsPolicy, 0) var triePolicy *trie.DomainTrie[[]dnsClient] @@ -497,75 +493,20 @@ func NewResolver(config Config) *Resolver { } } - for pair := config.Policy.Oldest(); pair != nil; pair = pair.Next() { - domain, nameserver := pair.Key, pair.Value - - if temp := strings.Split(domain, ":"); len(temp) == 2 { - prefix := temp[0] - key := temp[1] - switch prefix { - case "rule-set": - if _, ok := config.Tunnel.RuleProviders()[key]; ok { - log.Debugln("Adding rule-set policy: %s ", key) - insertPolicy(domainSetPolicy{ - tunnel: config.Tunnel, - name: key, - dnsClients: cacheTransform(nameserver), - }) - continue - } else { - log.Warnln("Can't found ruleset policy: %s", key) - } - case "geosite": - inverse := false - if strings.HasPrefix(key, "!") { - inverse = true - key = key[1:] - } - log.Debugln("Adding geosite policy: %s inversed %t", key, inverse) - matcher, err := NewGeoSite(key) - if err != nil { - log.Warnln("adding geosite policy %s error: %s", key, err) - continue - } - insertPolicy(geositePolicy{ - matcher: matcher, - inverse: inverse, - dnsClients: cacheTransform(nameserver), - }) - continue // skip triePolicy new + for _, policy := range config.Policy { + if policy.Rule != nil { + insertPolicy(domainRulePolicy{rule: policy.Rule, dnsClients: cacheTransform(policy.NameServers)}) + } else { + if triePolicy == nil { + triePolicy = trie.New[[]dnsClient]() } + _ = triePolicy.Insert(policy.Domain, cacheTransform(policy.NameServers)) } - if triePolicy == nil { - triePolicy = trie.New[[]dnsClient]() - } - _ = triePolicy.Insert(domain, cacheTransform(nameserver)) } insertPolicy(nil) } - - fallbackIPFilters := []fallbackIPFilter{} - if config.FallbackFilter.GeoIP { - fallbackIPFilters = append(fallbackIPFilters, &geoipFilter{ - code: config.FallbackFilter.GeoIPCode, - }) - } - for _, ipnet := range config.FallbackFilter.IPCIDR { - fallbackIPFilters = append(fallbackIPFilters, &ipnetFilter{ipnet: ipnet}) - } - r.fallbackIPFilters = fallbackIPFilters - - fallbackDomainFilters := []fallbackDomainFilter{} - if len(config.FallbackFilter.Domain) != 0 { - fallbackDomainFilters = append(fallbackDomainFilters, NewDomainFilter(config.FallbackFilter.Domain)) - } - - if len(config.FallbackFilter.GeoSite) != 0 { - fallbackDomainFilters = append(fallbackDomainFilters, &geoSiteFilter{ - matchers: config.FallbackFilter.GeoSite, - }) - } - r.fallbackDomainFilters = fallbackDomainFilters + r.fallbackIPFilters = config.FallbackIPFilter + r.fallbackDomainFilters = config.FallbackDomainFilter return r } diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 1e578190..6504e96a 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -222,25 +222,20 @@ func updateDNS(c *config.DNS, generalIPv6 bool) { return } cfg := dns.Config{ - Main: c.NameServer, - Fallback: c.Fallback, - IPv6: c.IPv6 && generalIPv6, - IPv6Timeout: c.IPv6Timeout, - EnhancedMode: c.EnhancedMode, - Pool: c.FakeIPRange, - Hosts: c.Hosts, - FallbackFilter: dns.FallbackFilter{ - GeoIP: c.FallbackFilter.GeoIP, - GeoIPCode: c.FallbackFilter.GeoIPCode, - IPCIDR: c.FallbackFilter.IPCIDR, - Domain: c.FallbackFilter.Domain, - GeoSite: c.FallbackFilter.GeoSite, - }, - Default: c.DefaultNameserver, - Policy: c.NameServerPolicy, - ProxyServer: c.ProxyServerNameserver, - Tunnel: tunnel.Tunnel, - CacheAlgorithm: c.CacheAlgorithm, + Main: c.NameServer, + Fallback: c.Fallback, + IPv6: c.IPv6 && generalIPv6, + IPv6Timeout: c.IPv6Timeout, + EnhancedMode: c.EnhancedMode, + Pool: c.FakeIPRange, + Hosts: c.Hosts, + FallbackIPFilter: c.FallbackIPFilter, + FallbackDomainFilter: c.FallbackDomainFilter, + Default: c.DefaultNameserver, + Policy: c.NameServerPolicy, + ProxyServer: c.ProxyServerNameserver, + Tunnel: tunnel.Tunnel, + CacheAlgorithm: c.CacheAlgorithm, } r := dns.NewResolver(cfg) diff --git a/rules/provider/domain_set.go b/rules/provider/domain_set.go index 372b438e..573dd105 100644 --- a/rules/provider/domain_set.go +++ b/rules/provider/domain_set.go @@ -19,10 +19,7 @@ func (d *DomainSet) RuleType() C.RuleType { } func (d *DomainSet) Match(metadata *C.Metadata) (bool, string) { - if d.domainSet == nil { - return false, "" - } - return d.domainSet.Has(metadata.RuleHost()), d.adapter + return d.domainStrategy.Match(metadata), d.adapter } func (d *DomainSet) Adapter() string { diff --git a/rules/provider/ipcidr_set.go b/rules/provider/ipcidr_set.go new file mode 100644 index 00000000..348b6ab0 --- /dev/null +++ b/rules/provider/ipcidr_set.go @@ -0,0 +1,40 @@ +package provider + +import ( + "github.com/metacubex/mihomo/component/cidr" + C "github.com/metacubex/mihomo/constant" +) + +type IpCidrSet struct { + *ipcidrStrategy + adapter string +} + +func (d *IpCidrSet) ProviderNames() []string { + return nil +} + +func (d *IpCidrSet) RuleType() C.RuleType { + return C.IpCidrSet +} + +func (d *IpCidrSet) Match(metadata *C.Metadata) (bool, string) { + return d.ipcidrStrategy.Match(metadata), d.adapter +} + +func (d *IpCidrSet) Adapter() string { + return d.adapter +} + +func (d *IpCidrSet) Payload() string { + return "" +} + +func NewIpCidrSet(cidrSet *cidr.IpCidrSet, adapter string) *IpCidrSet { + return &IpCidrSet{ + ipcidrStrategy: &ipcidrStrategy{cidrSet: cidrSet}, + adapter: adapter, + } +} + +var _ C.Rule = (*IpCidrSet)(nil)