diff --git a/README.md b/README.md index afa0c3f1..92772990 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,9 @@ experimental: # listen: 0.0.0.0:53 # enhanced-mode: redir-host # or fake-ip # # fake-ip-range: 198.18.0.1/16 # if you don't know what it is, don't change it + # fake-ip-filter: # fake ip white domain list + # - *.lan + # - localhost.ptlogin2.qq.com # nameserver: # - 114.114.114.114 # - tls://dns.rubyfish.cn:853 # dns over tls diff --git a/component/fakeip/pool.go b/component/fakeip/pool.go index 86a92ee2..ec84d8f8 100644 --- a/component/fakeip/pool.go +++ b/component/fakeip/pool.go @@ -6,6 +6,7 @@ import ( "sync" "github.com/Dreamacro/clash/common/cache" + trie "github.com/Dreamacro/clash/component/domain-trie" ) // Pool is a implementation about fake ip generator without storage @@ -15,6 +16,7 @@ type Pool struct { gateway uint32 offset uint32 mux sync.Mutex + host *trie.Trie cache *cache.LruCache } @@ -60,6 +62,14 @@ func (p *Pool) LookBack(ip net.IP) (string, bool) { return "", false } +// LookupHost return if host in host +func (p *Pool) LookupHost(host string) bool { + if p.host == nil { + return false + } + return p.host.Search(host) != nil +} + // Gateway return gateway ip func (p *Pool) Gateway() net.IP { return uintToIP(p.gateway) @@ -96,7 +106,7 @@ func uintToIP(v uint32) net.IP { } // New return Pool instance -func New(ipnet *net.IPNet, size int) (*Pool, error) { +func New(ipnet *net.IPNet, size int, host *trie.Trie) (*Pool, error) { min := ipToUint(ipnet.IP) + 2 ones, bits := ipnet.Mask.Size() @@ -111,6 +121,7 @@ func New(ipnet *net.IPNet, size int) (*Pool, error) { min: min, max: max, gateway: min - 1, + host: host, cache: cache.NewLRUCache(cache.WithSize(size * 2)), }, nil } diff --git a/config/config.go b/config/config.go index 617bdde4..1b35243e 100644 --- a/config/config.go +++ b/config/config.go @@ -81,6 +81,7 @@ type rawDNS struct { Listen string `yaml:"listen"` EnhancedMode dns.EnhancedMode `yaml:"enhanced-mode"` FakeIPRange string `yaml:"fake-ip-range"` + FakeIPFilter []string `yaml:"fake-ip-filter"` } type rawFallbackFilter struct { @@ -523,7 +524,17 @@ func parseDNS(cfg rawDNS) (*DNS, error) { if err != nil { return nil, err } - pool, err := fakeip.New(ipnet, 1000) + + var host *trie.Trie + // fake ip skip host filter + if len(cfg.FakeIPFilter) != 0 { + host = trie.New() + for _, domain := range cfg.FakeIPFilter { + host.Insert(domain, true) + } + } + + pool, err := fakeip.New(ipnet, 1000, host) if err != nil { return nil, err } diff --git a/dns/middleware.go b/dns/middleware.go index bd0aa7d9..2a83c648 100644 --- a/dns/middleware.go +++ b/dns/middleware.go @@ -26,6 +26,10 @@ func withFakeIP(fakePool *fakeip.Pool) middleware { } host := strings.TrimRight(q.Name, ".") + if fakePool.LookupHost(host) { + next(w, r) + return + } rr := &D.A{} rr.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeA, Class: D.ClassINET, Ttl: dnsDefaultTTL}