feature: geosite-based nameserver policy
This commit is contained in:
parent
b2c7c989e0
commit
0bf0750d50
2 changed files with 52 additions and 6 deletions
|
@ -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) {
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue