From 696b75ee375660bb8478ca94fe2f16b8ad2ff3c3 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 14 Aug 2024 20:02:02 +0800 Subject: [PATCH] feat: `fake-ip-filter` support `rule-set:` and `geosite:` --- component/fakeip/pool.go | 19 +++++++++++-- config/config.go | 59 ++++++++++++++++++++++++++++++++++++++-- docs/config.yaml | 15 ++++++---- 3 files changed, 83 insertions(+), 10 deletions(-) diff --git a/component/fakeip/pool.go b/component/fakeip/pool.go index 2b06fc0bdf..90e648fe2c 100644 --- a/component/fakeip/pool.go +++ b/component/fakeip/pool.go @@ -9,6 +9,7 @@ import ( "github.com/metacubex/mihomo/common/nnip" "github.com/metacubex/mihomo/component/profile/cachefile" "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" ) const ( @@ -36,6 +37,7 @@ type Pool struct { cycle bool mux sync.Mutex host *trie.DomainTrie[struct{}] + rules []C.Rule ipnet netip.Prefix store store } @@ -66,10 +68,18 @@ func (p *Pool) LookBack(ip netip.Addr) (string, bool) { // ShouldSkipped return if domain should be skipped func (p *Pool) ShouldSkipped(domain string) bool { - if p.host == nil { - return false + if p.host != nil { + if p.host.Search(domain) != nil { + return true + } + } + for _, rule := range p.rules { + metadata := &C.Metadata{Host: domain} + if match, _ := rule.Match(metadata); match { + return true + } } - return p.host.Search(domain) != nil + return false } // Exist returns if given ip exists in fake-ip pool @@ -156,6 +166,8 @@ type Options struct { IPNet netip.Prefix Host *trie.DomainTrie[struct{}] + Rules []C.Rule + // Size sets the maximum number of entries in memory // and does not work if Persistence is true Size int @@ -185,6 +197,7 @@ func New(options Options) (*Pool, error) { offset: first.Prev(), cycle: false, host: options.Host, + rules: options.Rules, ipnet: options.IPNet, } if options.Persistence { diff --git a/config/config.go b/config/config.go index 235d71ae5c..fae88e1a04 100644 --- a/config/config.go +++ b/config/config.go @@ -38,6 +38,7 @@ import ( LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/log" R "github.com/metacubex/mihomo/rules" + RC "github.com/metacubex/mihomo/rules/common" RP "github.com/metacubex/mihomo/rules/provider" T "github.com/metacubex/mihomo/tunnel" @@ -1408,13 +1409,63 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul } var host *trie.DomainTrie[struct{}] + var fakeIPRules []C.Rule // fake ip skip host filter if len(cfg.FakeIPFilter) != 0 { host = trie.New[struct{}]() for _, domain := range cfg.FakeIPFilter { - _ = host.Insert(domain, struct{}{}) + if strings.Contains(strings.ToLower(domain), ",") { + if strings.Contains(domain, "geosite:") { + subkeys := strings.Split(domain, ":") + 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 + fakeIPRules = append(fakeIPRules, rule) + } + } + } + if !found { + rule, err := RC.NewGEOSITE(country, "") + if err != nil { + return nil, err + } + fakeIPRules = append(fakeIPRules, rule) + } + } + + } + } else if strings.Contains(strings.ToLower(domain), "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) + if err != nil { + return nil, err + } + + fakeIPRules = append(fakeIPRules, rule) + } + } else { + _ = host.Insert(domain, struct{}{}) + } } - host.Optimize() } if len(dnsCfg.Fallback) != 0 { @@ -1427,6 +1478,9 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul } _ = host.Insert(fb.Addr, struct{}{}) } + } + + if host != nil { host.Optimize() } @@ -1434,6 +1488,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul IPNet: fakeIPRange, Size: 1000, Host: host, + Rules: fakeIPRules, Persistence: rawCfg.Profile.StoreFakeIP, }) if err != nil { diff --git a/docs/config.yaml b/docs/config.yaml index c4644550a0..8db06b6d7d 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -243,6 +243,16 @@ dns: fake-ip-range: 198.18.0.1/16 # fake-ip 池设置 + # 配置不使用 fake-ip 的域名 + fake-ip-filter: + - '*.lan' + - localhost.ptlogin2.qq.com + # fakeip-filter 为 rule-providers 中的名为 fakeip-filter 规则订阅, + # 且 behavior 必须为 domain/classical,当为 classical 时仅会生效域名类规则 + - rule-set:fakeip-filter + # fakeip-filter 为 geosite 中名为 fakeip-filter 的分类(需要自行保证该分类存在) + - geosite:fakeip-filter + # use-hosts: true # 查询 hosts # 配置后面的nameserver、fallback和nameserver-policy向dns服务器的连接过程是否遵守遵守rules规则 @@ -252,11 +262,6 @@ dns: # 此外,这三者配置中的dns服务器如果出现域名会采用default-nameserver配置项解析,也请确保正确配置default-nameserver respect-rules: false - # 配置不使用 fake-ip 的域名 - # fake-ip-filter: - # - '*.lan' - # - localhost.ptlogin2.qq.com - # DNS 主要域名配置 # 支持 UDP,TCP,DoT,DoH,DoQ # 这部分为主要 DNS 配置,影响所有直连,确保使用对大陆解析精准的 DNS