Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for specifying real-ip-filter in DNS #1552

Open
wants to merge 1 commit into
base: Alpha
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 35 additions & 22 deletions component/fakeip/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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())
Expand Down
8 changes: 8 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down Expand Up @@ -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,
})
Expand Down
14 changes: 14 additions & 0 deletions docs/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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规则
Expand Down