feat: "!"(not) support for geosite

eg. GEOSITE,!CN,Proxy & dns.fallback-filter.geosite: ['!CN']
This commit is contained in:
adlyq 2022-05-15 13:16:45 +08:00
parent 63917aa020
commit efc7c82cac
4 changed files with 33 additions and 15 deletions

View file

@ -33,9 +33,10 @@ func domainToMatcher(domain *Domain) (strmatcher.Matcher, error) {
type DomainMatcher struct {
matchers strmatcher.IndexMatcher
not bool
}
func NewMphMatcherGroup(domains []*Domain) (*DomainMatcher, error) {
func NewMphMatcherGroup(domains []*Domain, not bool) (*DomainMatcher, error) {
g := strmatcher.NewMphMatcherGroup()
for _, d := range domains {
matcherType, f := matcherTypeMap[d.Type]
@ -50,11 +51,12 @@ func NewMphMatcherGroup(domains []*Domain) (*DomainMatcher, error) {
g.Build()
return &DomainMatcher{
matchers: g,
not: not,
}, nil
}
// NewDomainMatcher new domain matcher.
func NewDomainMatcher(domains []*Domain) (*DomainMatcher, error) {
func NewDomainMatcher(domains []*Domain, not bool) (*DomainMatcher, error) {
g := new(strmatcher.MatcherGroup)
for _, d := range domains {
m, err := domainToMatcher(d)
@ -66,11 +68,16 @@ func NewDomainMatcher(domains []*Domain) (*DomainMatcher, error) {
return &DomainMatcher{
matchers: g,
not: not,
}, nil
}
func (m *DomainMatcher) ApplyDomain(domain string) bool {
return len(m.matchers.Match(strings.ToLower(domain))) > 0
isMatched := len(m.matchers.Match(strings.ToLower(domain))) > 0
if m.not {
isMatched = !isMatched
}
return isMatched
}
// CIDRList is an alias of []*CIDR to provide sort.Interface.

View file

@ -1,6 +1,7 @@
package geodata
import (
"fmt"
"github.com/Dreamacro/clash/component/geodata/router"
C "github.com/Dreamacro/clash/constant"
"strings"
@ -35,6 +36,16 @@ func Verify(name string) bool {
}
func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error) {
if len(countryCode) == 0 {
return nil, 0, fmt.Errorf("country code could not be empty")
}
not := false
if countryCode[0] == '!' {
not = true
countryCode = countryCode[1:]
}
geoLoader, err := GetGeoDataLoader(geoLoaderName)
if err != nil {
return nil, 0, err
@ -50,7 +61,7 @@ func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error)
matcher, err := router.NewDomainMatcher(domains)
mphminimal perfect hash algorithm
*/
matcher, err := router.NewMphMatcherGroup(domains)
matcher, err := router.NewMphMatcherGroup(domains, not)
if err != nil {
return nil, 0, err
}

View file

@ -7,7 +7,6 @@ import (
"go.uber.org/atomic"
"math/rand"
"net/netip"
"strings"
"time"
"github.com/Dreamacro/clash/common/cache"
@ -232,7 +231,7 @@ func (r *Resolver) matchPolicy(m *D.Msg) []dnsClient {
return nil
}
domain := r.msgToDomain(m)
domain := msgToDomain(m)
if domain == "" {
return nil
}
@ -251,7 +250,7 @@ func (r *Resolver) shouldOnlyQueryFallback(m *D.Msg) bool {
return false
}
domain := r.msgToDomain(m)
domain := msgToDomain(m)
if domain == "" {
return false
@ -332,14 +331,6 @@ func (r *Resolver) resolveIP(host string, dnsType uint16) (ips []netip.Addr, err
return
}
func (r *Resolver) msgToDomain(msg *D.Msg) string {
if len(msg.Question) > 0 {
return strings.TrimRight(msg.Question[0].Name, ".")
}
return ""
}
func (r *Resolver) asyncExchange(ctx context.Context, client []dnsClient, msg *D.Msg) <-chan *result {
ch := make(chan *result, 1)
go func() {

View file

@ -6,6 +6,7 @@ import (
"fmt"
"net"
"net/netip"
"strings"
"time"
"github.com/Dreamacro/clash/common/cache"
@ -116,6 +117,14 @@ func msgToIP(msg *D.Msg) []netip.Addr {
return ips
}
func msgToDomain(msg *D.Msg) string {
if len(msg.Question) > 0 {
return strings.TrimRight(msg.Question[0].Name, ".")
}
return ""
}
type wrapPacketConn struct {
net.PacketConn
rAddr net.Addr