diff --git a/component/fakeip/pool.go b/component/fakeip/pool.go index 41b848b3..ea5a934a 100644 --- a/component/fakeip/pool.go +++ b/component/fakeip/pool.go @@ -29,16 +29,17 @@ type store interface { // Pool is an implementation about fake ip generator without storage type Pool struct { - gateway netip.Addr - first netip.Addr - last netip.Addr - offset netip.Addr - cycle bool - mux sync.Mutex - host []C.DomainMatcher - mode C.FilterMode - ipnet netip.Prefix - store store + gateway netip.Addr + first netip.Addr + last netip.Addr + offset netip.Addr + cycle bool + mux sync.Mutex + host []C.DomainMatcher + realhost []C.DomainMatcher + mode C.FilterMode + ipnet netip.Prefix + store store } // Lookup return a fake ip with host @@ -75,12 +76,22 @@ func (p *Pool) ShouldSkipped(domain string) bool { } func (p *Pool) shouldSkipped(domain string) bool { + // When both fake-ip-filter and real-ip-filter match, the fake-ip-filter takes precedence. + // If neither filter matches, fake-ip is returned. + // For example: + // If an ad domain (www.ad.com) matches both fake-ip-filter:AD and real-ip-filter:cn, fake-ip will be returned. + // If a blocked domain (wiki.metacubex.one) does not match either filter, fake-ip will be returned by default. for _, matcher := range p.host { if matcher.MatchDomain(domain) { return true } } - return false + for _, matcher := range p.realhost { + if matcher.MatchDomain(domain) { + return false + } + } + return true } // Exist returns if given ip exists in fake-ip pool @@ -164,9 +175,10 @@ func (p *Pool) restoreState() { } type Options struct { - IPNet netip.Prefix - Host []C.DomainMatcher - Mode C.FilterMode + IPNet netip.Prefix + Host []C.DomainMatcher + RealHost []C.DomainMatcher + Mode C.FilterMode // Size sets the maximum number of entries in memory // and does not work if Persistence is true @@ -191,14 +203,15 @@ func New(options Options) (*Pool, error) { } pool := &Pool{ - gateway: gateway, - first: first, - last: last, - offset: first.Prev(), - cycle: false, - host: options.Host, - mode: options.Mode, - ipnet: options.IPNet, + gateway: gateway, + first: first, + last: last, + offset: first.Prev(), + cycle: false, + host: options.Host, + realhost: options.RealHost, + mode: options.Mode, + ipnet: options.IPNet, } if options.Persistence { pool.store = newCachefileStore(cachefile.Cache()) diff --git a/config/config.go b/config/config.go index 9067d14f..fdc93fbe 100644 --- a/config/config.go +++ b/config/config.go @@ -206,6 +206,7 @@ type RawDNS struct { EnhancedMode C.DNSMode `yaml:"enhanced-mode" json:"enhanced-mode"` FakeIPRange string `yaml:"fake-ip-range" json:"fake-ip-range"` FakeIPFilter []string `yaml:"fake-ip-filter" json:"fake-ip-filter"` + RealIPFilter []string `yaml:"real-ip-filter" json:"real-ip-filter"` FakeIPFilterMode C.FilterMode `yaml:"fake-ip-filter-mode" json:"fake-ip-filter-mode"` DefaultNameserver []string `yaml:"default-nameserver" json:"default-nameserver"` CacheAlgorithm string `yaml:"cache-algorithm" json:"cache-algorithm"` @@ -1449,10 +1450,17 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul return nil, err } + // real ip via host rule + realHost, err := parseDomain(cfg.RealIPFilter, fakeIPTrie, "dns.real-ip-filter", ruleProviders) + if err != nil { + return nil, err + } + pool, err := fakeip.New(fakeip.Options{ IPNet: fakeIPRange, Size: 1000, Host: host, + RealHost: realHost, Mode: cfg.FakeIPFilterMode, Persistence: rawCfg.Profile.StoreFakeIP, }) diff --git a/docs/config.yaml b/docs/config.yaml index 9c480b3f..a97a279f 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -257,6 +257,20 @@ dns: # 可设置为whitelist,即只有匹配成功才返回fake-ip fake-ip-filter-mode: blacklist + # fake-ip 白名单模式 + # 当 fake-ip-filter 和 real-ip-filter 同时匹配时,fake-ip-filter 优先级更高。 + # 如果都没有匹配到规则,则返回 fake-ip。 + # 例如: + # 如果广告域名 (www.ad.com) 同时满足 fake-ip-filter:AD 和 real-ip-filter:cn,则返回 fake-ip。 + # 如果被墙域名 (wiki.metacubex.one) 都没匹配到,默认返回 fake-ip。 + # fake-ip-filter-mode: whitelist + # fake-ip-filter: + # - rule-set:anti-AD + # - geosite:gfw + # real-ip-filter: + # - geosite:cn + # - rule-set:douyin + # use-hosts: true # 查询 hosts # 配置后面的nameserver、fallback和nameserver-policy向dns服务器的连接过程是否遵守遵守rules规则