feature: geosite-based nameserver policy

This commit is contained in:
i40e 2023-01-21 14:40:36 +08:00 committed by metacubex
parent 1924b308fd
commit 02684a868f
2 changed files with 52 additions and 6 deletions

View file

@ -91,6 +91,17 @@ type geoSiteFilter struct {
matchers []*router.DomainMatcher matchers []*router.DomainMatcher
} }
func NewGeoSite(group string) (fallbackDomainFilter, error) {
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 { func (gsf *geoSiteFilter) Match(domain string) bool {
for _, matcher := range gsf.matchers { for _, matcher := range gsf.matchers {
if matcher.ApplyDomain(domain) { if matcher.ApplyDomain(domain) {

View file

@ -4,17 +4,20 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"go.uber.org/atomic"
"math/rand" "math/rand"
"net/netip" "net/netip"
"strings"
"time" "time"
"go.uber.org/atomic"
"github.com/Dreamacro/clash/common/cache" "github.com/Dreamacro/clash/common/cache"
"github.com/Dreamacro/clash/component/fakeip" "github.com/Dreamacro/clash/component/fakeip"
"github.com/Dreamacro/clash/component/geodata/router" "github.com/Dreamacro/clash/component/geodata/router"
"github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/component/resolver"
"github.com/Dreamacro/clash/component/trie" "github.com/Dreamacro/clash/component/trie"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
D "github.com/miekg/dns" D "github.com/miekg/dns"
"golang.org/x/sync/singleflight" "golang.org/x/sync/singleflight"
@ -30,6 +33,12 @@ type result struct {
Error error Error error
} }
type geositePolicyRecord struct {
matcher fallbackDomainFilter
policy *Policy
inversedMatching bool
}
type Resolver struct { type Resolver struct {
ipv6 bool ipv6 bool
hosts *trie.DomainTrie[netip.Addr] hosts *trie.DomainTrie[netip.Addr]
@ -40,6 +49,7 @@ type Resolver struct {
group singleflight.Group group singleflight.Group
lruCache *cache.LruCache[string, *D.Msg] lruCache *cache.LruCache[string, *D.Msg]
policy *trie.DomainTrie[*Policy] policy *trie.DomainTrie[*Policy]
geositePolicy []geositePolicyRecord
proxyServer []dnsClient proxyServer []dnsClient
} }
@ -272,12 +282,18 @@ func (r *Resolver) matchPolicy(m *D.Msg) []dnsClient {
} }
record := r.policy.Search(domain) record := r.policy.Search(domain)
if record == nil { if record != nil {
return nil p := record.Data()
return p.GetData()
} }
p := record.Data() for _, geositeRecord := range r.geositePolicy {
return p.GetData() matched := geositeRecord.matcher.Match(domain)
if matched != geositeRecord.inversedMatching {
return geositeRecord.policy.GetData()
}
}
return nil
} }
func (r *Resolver) shouldOnlyQueryFallback(m *D.Msg) bool { func (r *Resolver) shouldOnlyQueryFallback(m *D.Msg) bool {
@ -433,7 +449,26 @@ func NewResolver(config Config) *Resolver {
if len(config.Policy) != 0 { if len(config.Policy) != 0 {
r.policy = trie.New[*Policy]() r.policy = trie.New[*Policy]()
for domain, nameserver := range config.Policy { for domain, nameserver := range config.Policy {
_ = r.policy.Insert(domain, NewPolicy(transform([]NameServer{nameserver}, defaultResolver))) if strings.HasPrefix(strings.ToLower(domain), "@geosite:") {
groupname := domain[9:]
inverse := false
if strings.HasPrefix(groupname, "!") {
inverse = true
groupname = groupname[1:]
}
log.Debugln("adding geosite policy: %s inversed %s", groupname, inverse)
matcher, err := NewGeoSite(groupname)
if err != nil {
continue
}
r.geositePolicy = append(r.geositePolicy, geositePolicyRecord{
matcher: matcher,
policy: NewPolicy(transform([]NameServer{nameserver}, defaultResolver)),
inversedMatching: inverse,
})
} else {
_ = r.policy.Insert(domain, NewPolicy(transform([]NameServer{nameserver}, defaultResolver)))
}
} }
r.policy.Optimize() r.policy.Optimize()
} }