mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2024-11-15 19:22:53 +08:00
chore: cleanup dns policy match code
Some checks are pending
Trigger CMFA Update / trigger-CMFA-update (push) Waiting to run
Some checks are pending
Trigger CMFA Update / trigger-CMFA-update (push) Waiting to run
This commit is contained in:
parent
4c10d42fbf
commit
92ec5f2236
308
config/config.go
308
config/config.go
|
@ -20,9 +20,9 @@ import (
|
|||
N "github.com/metacubex/mihomo/common/net"
|
||||
"github.com/metacubex/mihomo/common/utils"
|
||||
"github.com/metacubex/mihomo/component/auth"
|
||||
"github.com/metacubex/mihomo/component/cidr"
|
||||
"github.com/metacubex/mihomo/component/fakeip"
|
||||
"github.com/metacubex/mihomo/component/geodata"
|
||||
"github.com/metacubex/mihomo/component/geodata/router"
|
||||
P "github.com/metacubex/mihomo/component/process"
|
||||
"github.com/metacubex/mihomo/component/resolver"
|
||||
SNIFF "github.com/metacubex/mihomo/component/sniffer"
|
||||
|
@ -114,33 +114,25 @@ type NTP struct {
|
|||
|
||||
// DNS config
|
||||
type DNS struct {
|
||||
Enable bool `yaml:"enable"`
|
||||
PreferH3 bool `yaml:"prefer-h3"`
|
||||
IPv6 bool `yaml:"ipv6"`
|
||||
IPv6Timeout uint `yaml:"ipv6-timeout"`
|
||||
UseSystemHosts bool `yaml:"use-system-hosts"`
|
||||
NameServer []dns.NameServer `yaml:"nameserver"`
|
||||
Fallback []dns.NameServer `yaml:"fallback"`
|
||||
FallbackFilter FallbackFilter `yaml:"fallback-filter"`
|
||||
Listen string `yaml:"listen"`
|
||||
EnhancedMode C.DNSMode `yaml:"enhanced-mode"`
|
||||
DefaultNameserver []dns.NameServer `yaml:"default-nameserver"`
|
||||
CacheAlgorithm string `yaml:"cache-algorithm"`
|
||||
Enable bool
|
||||
PreferH3 bool
|
||||
IPv6 bool
|
||||
IPv6Timeout uint
|
||||
UseSystemHosts bool
|
||||
NameServer []dns.NameServer
|
||||
Fallback []dns.NameServer
|
||||
FallbackIPFilter []C.Rule
|
||||
FallbackDomainFilter []C.Rule
|
||||
Listen string
|
||||
EnhancedMode C.DNSMode
|
||||
DefaultNameserver []dns.NameServer
|
||||
CacheAlgorithm string
|
||||
FakeIPRange *fakeip.Pool
|
||||
Hosts *trie.DomainTrie[resolver.HostValue]
|
||||
NameServerPolicy *orderedmap.OrderedMap[string, []dns.NameServer]
|
||||
NameServerPolicy []dns.Policy
|
||||
ProxyServerNameserver []dns.NameServer
|
||||
}
|
||||
|
||||
// FallbackFilter config
|
||||
type FallbackFilter struct {
|
||||
GeoIP bool `yaml:"geoip"`
|
||||
GeoIPCode string `yaml:"geoip-code"`
|
||||
IPCIDR []netip.Prefix `yaml:"ipcidr"`
|
||||
Domain []string `yaml:"domain"`
|
||||
GeoSite []router.DomainMatcher `yaml:"geosite"`
|
||||
}
|
||||
|
||||
// Profile config
|
||||
type Profile struct {
|
||||
StoreSelected bool `yaml:"store-selected"`
|
||||
|
@ -1205,49 +1197,13 @@ func parsePureDNSServer(server string) string {
|
|||
}
|
||||
}
|
||||
|
||||
func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], ruleProviders map[string]providerTypes.RuleProvider, respectRules bool, preferH3 bool) (*orderedmap.OrderedMap[string, []dns.NameServer], error) {
|
||||
policy := orderedmap.New[string, []dns.NameServer]()
|
||||
updatedPolicy := orderedmap.New[string, any]()
|
||||
func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rules []C.Rule, ruleProviders map[string]providerTypes.RuleProvider, respectRules bool, preferH3 bool) ([]dns.Policy, error) {
|
||||
var policy []dns.Policy
|
||||
re := regexp.MustCompile(`[a-zA-Z0-9\-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?`)
|
||||
|
||||
for pair := nsPolicy.Oldest(); pair != nil; pair = pair.Next() {
|
||||
k, v := pair.Key, pair.Value
|
||||
if strings.Contains(strings.ToLower(k), ",") {
|
||||
if strings.Contains(k, "geosite:") {
|
||||
subkeys := strings.Split(k, ":")
|
||||
subkeys = subkeys[1:]
|
||||
subkeys = strings.Split(subkeys[0], ",")
|
||||
for _, subkey := range subkeys {
|
||||
newKey := "geosite:" + subkey
|
||||
updatedPolicy.Store(newKey, v)
|
||||
}
|
||||
} else if strings.Contains(strings.ToLower(k), "rule-set:") {
|
||||
subkeys := strings.Split(k, ":")
|
||||
subkeys = subkeys[1:]
|
||||
subkeys = strings.Split(subkeys[0], ",")
|
||||
for _, subkey := range subkeys {
|
||||
newKey := "rule-set:" + subkey
|
||||
updatedPolicy.Store(newKey, v)
|
||||
}
|
||||
} else if re.MatchString(k) {
|
||||
subkeys := strings.Split(k, ",")
|
||||
for _, subkey := range subkeys {
|
||||
updatedPolicy.Store(subkey, v)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if strings.Contains(strings.ToLower(k), "geosite:") {
|
||||
updatedPolicy.Store("geosite:"+k[8:], v)
|
||||
} else if strings.Contains(strings.ToLower(k), "rule-set:") {
|
||||
updatedPolicy.Store("rule-set:"+k[9:], v)
|
||||
}
|
||||
updatedPolicy.Store(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
for pair := updatedPolicy.Oldest(); pair != nil; pair = pair.Next() {
|
||||
domain, server := pair.Key, pair.Value
|
||||
servers, err := utils.ToStringSlice(server)
|
||||
servers, err := utils.ToStringSlice(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1255,75 +1211,65 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rulePro
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, valid := trie.ValidAndSplitDomain(domain); !valid {
|
||||
return nil, fmt.Errorf("DNS ResoverRule invalid domain: %s", domain)
|
||||
if strings.Contains(strings.ToLower(k), ",") {
|
||||
if strings.Contains(k, "geosite:") {
|
||||
subkeys := strings.Split(k, ":")
|
||||
subkeys = subkeys[1:]
|
||||
subkeys = strings.Split(subkeys[0], ",")
|
||||
for _, subkey := range subkeys {
|
||||
newKey := "geosite:" + subkey
|
||||
policy = append(policy, dns.Policy{Domain: newKey, NameServers: nameservers})
|
||||
}
|
||||
} else if strings.Contains(strings.ToLower(k), "rule-set:") {
|
||||
subkeys := strings.Split(k, ":")
|
||||
subkeys = subkeys[1:]
|
||||
subkeys = strings.Split(subkeys[0], ",")
|
||||
for _, subkey := range subkeys {
|
||||
newKey := "rule-set:" + subkey
|
||||
policy = append(policy, dns.Policy{Domain: newKey, NameServers: nameservers})
|
||||
}
|
||||
} else if re.MatchString(k) {
|
||||
subkeys := strings.Split(k, ",")
|
||||
for _, subkey := range subkeys {
|
||||
policy = append(policy, dns.Policy{Domain: subkey, NameServers: nameservers})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if strings.Contains(strings.ToLower(k), "geosite:") {
|
||||
policy = append(policy, dns.Policy{Domain: "geosite:" + k[8:], NameServers: nameservers})
|
||||
} else if strings.Contains(strings.ToLower(k), "rule-set:") {
|
||||
policy = append(policy, dns.Policy{Domain: "rule-set:" + k[9:], NameServers: nameservers})
|
||||
} else {
|
||||
policy = append(policy, dns.Policy{Domain: k, NameServers: nameservers})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for idx, p := range policy {
|
||||
domain, nameservers := p.Domain, p.NameServers
|
||||
|
||||
if strings.HasPrefix(domain, "rule-set:") {
|
||||
domainSetName := domain[9:]
|
||||
if provider, ok := ruleProviders[domainSetName]; !ok {
|
||||
return nil, fmt.Errorf("not found rule-set: %s", domainSetName)
|
||||
} else {
|
||||
switch provider.Behavior() {
|
||||
case providerTypes.IPCIDR:
|
||||
return nil, fmt.Errorf("rule provider type error, except domain,actual %s", provider.Behavior())
|
||||
case providerTypes.Classical:
|
||||
log.Warnln("%s provider is %s, only matching it contain domain rule", provider.Name(), provider.Behavior())
|
||||
}
|
||||
}
|
||||
}
|
||||
policy.Store(domain, nameservers)
|
||||
}
|
||||
|
||||
return policy, nil
|
||||
}
|
||||
|
||||
func parseFallbackIPCIDR(ips []string) ([]netip.Prefix, error) {
|
||||
var ipNets []netip.Prefix
|
||||
|
||||
for idx, ip := range ips {
|
||||
ipnet, err := netip.ParsePrefix(ip)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("DNS FallbackIP[%d] format error: %s", idx, err.Error())
|
||||
}
|
||||
ipNets = append(ipNets, ipnet)
|
||||
}
|
||||
|
||||
return ipNets, nil
|
||||
}
|
||||
|
||||
func parseFallbackGeoSite(countries []string, rules []C.Rule) ([]router.DomainMatcher, error) {
|
||||
var sites []router.DomainMatcher
|
||||
if len(countries) > 0 {
|
||||
if err := geodata.InitGeoSite(); err != nil {
|
||||
return nil, fmt.Errorf("can't initial GeoSite: %s", err)
|
||||
}
|
||||
log.Warnln("replace fallback-filter.geosite with nameserver-policy, it will be removed in the future")
|
||||
}
|
||||
|
||||
for _, country := range countries {
|
||||
found := false
|
||||
for _, rule := range rules {
|
||||
if rule.RuleType() == C.GEOSITE {
|
||||
if strings.EqualFold(country, rule.Payload()) {
|
||||
found = true
|
||||
sites = append(sites, rule.(C.RuleGeoSite).GetDomainMatcher())
|
||||
log.Infoln("Start initial GeoSite dns fallback filter from rule `%s`", country)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
matcher, recordsCount, err := geodata.LoadGeoSiteMatcher(country)
|
||||
rule, err := parseDomainRuleSet(domainSetName, ruleProviders)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sites = append(sites, matcher)
|
||||
|
||||
log.Infoln("Start initial GeoSite dns fallback filter `%s`, records: %d", country, recordsCount)
|
||||
policy[idx] = dns.Policy{Rule: rule, NameServers: nameservers}
|
||||
} else if strings.HasPrefix(domain, "geosite:") {
|
||||
country := domain[8:]
|
||||
rule, err := parseGEOSITE(country, rules)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
policy[idx] = dns.Policy{Rule: rule, NameServers: nameservers}
|
||||
} else {
|
||||
if _, valid := trie.ValidAndSplitDomain(domain); !valid {
|
||||
return nil, fmt.Errorf("DNS ResoverRule invalid domain: %s", domain)
|
||||
}
|
||||
}
|
||||
}
|
||||
return sites, nil
|
||||
|
||||
return policy, nil
|
||||
}
|
||||
|
||||
func paresNTP(rawCfg *RawConfig) *NTP {
|
||||
|
@ -1357,10 +1303,6 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul
|
|||
IPv6: cfg.IPv6,
|
||||
UseSystemHosts: cfg.UseSystemHosts,
|
||||
EnhancedMode: cfg.EnhancedMode,
|
||||
FallbackFilter: FallbackFilter{
|
||||
IPCIDR: []netip.Prefix{},
|
||||
GeoSite: []router.DomainMatcher{},
|
||||
},
|
||||
}
|
||||
var err error
|
||||
if dnsCfg.NameServer, err = parseNameServer(cfg.NameServer, cfg.RespectRules, cfg.PreferH3); err != nil {
|
||||
|
@ -1371,7 +1313,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy, ruleProviders, cfg.RespectRules, cfg.PreferH3); err != nil {
|
||||
if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy, rules, ruleProviders, cfg.RespectRules, cfg.PreferH3); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -1438,18 +1380,51 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul
|
|||
dnsCfg.FakeIPRange = pool
|
||||
}
|
||||
|
||||
var rule C.Rule
|
||||
if len(cfg.Fallback) != 0 {
|
||||
dnsCfg.FallbackFilter.GeoIP = cfg.FallbackFilter.GeoIP
|
||||
dnsCfg.FallbackFilter.GeoIPCode = cfg.FallbackFilter.GeoIPCode
|
||||
if fallbackip, err := parseFallbackIPCIDR(cfg.FallbackFilter.IPCIDR); err == nil {
|
||||
dnsCfg.FallbackFilter.IPCIDR = fallbackip
|
||||
if cfg.FallbackFilter.GeoIP {
|
||||
rule, err = RC.NewGEOIP(cfg.FallbackFilter.GeoIPCode, "", false, true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load GeoIP dns fallback filter error, %w", err)
|
||||
}
|
||||
dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, rule)
|
||||
}
|
||||
dnsCfg.FallbackFilter.Domain = cfg.FallbackFilter.Domain
|
||||
fallbackGeoSite, err := parseFallbackGeoSite(cfg.FallbackFilter.GeoSite, rules)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load GeoSite dns fallback filter error, %w", err)
|
||||
if len(cfg.FallbackFilter.IPCIDR) > 0 {
|
||||
cidrSet := cidr.NewIpCidrSet()
|
||||
for idx, ipcidr := range cfg.FallbackFilter.IPCIDR {
|
||||
err = cidrSet.AddIpCidrForString(ipcidr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("DNS FallbackIP[%d] format error: %w", idx, err)
|
||||
}
|
||||
}
|
||||
err = cidrSet.Merge()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rule = RP.NewIpCidrSet(cidrSet, "")
|
||||
dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, rule)
|
||||
}
|
||||
if len(cfg.FallbackFilter.Domain) > 0 {
|
||||
domainTrie := trie.New[struct{}]()
|
||||
for idx, domain := range cfg.FallbackFilter.Domain {
|
||||
err = domainTrie.Insert(domain, struct{}{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("DNS FallbackDomain[%d] format error: %w", idx, err)
|
||||
}
|
||||
}
|
||||
rule = RP.NewDomainSet(domainTrie.NewDomainSet(), "")
|
||||
dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, rule)
|
||||
}
|
||||
if len(cfg.FallbackFilter.GeoSite) > 0 {
|
||||
log.Warnln("replace fallback-filter.geosite with nameserver-policy, it will be removed in the future")
|
||||
for idx, geoSite := range cfg.FallbackFilter.GeoSite {
|
||||
rule, err = parseGEOSITE(geoSite, rules)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("DNS FallbackGeosite[%d] format error: %w", idx, err)
|
||||
}
|
||||
dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, rule)
|
||||
}
|
||||
}
|
||||
dnsCfg.FallbackFilter.GeoSite = fallbackGeoSite
|
||||
}
|
||||
|
||||
if cfg.UseHosts {
|
||||
|
@ -1636,44 +1611,21 @@ func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], rules
|
|||
subkeys = subkeys[1:]
|
||||
subkeys = strings.Split(subkeys[0], ",")
|
||||
for _, country := range subkeys {
|
||||
found := false
|
||||
for _, rule = range rules {
|
||||
if rule.RuleType() == C.GEOSITE {
|
||||
if strings.EqualFold(country, rule.Payload()) {
|
||||
found = true
|
||||
domainRules = append(domainRules, rule)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
rule, err = RC.NewGEOSITE(country, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domainRules = append(domainRules, rule)
|
||||
rule, err = parseGEOSITE(country, rules)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domainRules = append(domainRules, rule)
|
||||
}
|
||||
} else if strings.Contains(domainLower, "rule-set:") {
|
||||
subkeys := strings.Split(domain, ":")
|
||||
subkeys = subkeys[1:]
|
||||
subkeys = strings.Split(subkeys[0], ",")
|
||||
for _, domainSetName := range subkeys {
|
||||
if rp, ok := ruleProviders[domainSetName]; !ok {
|
||||
return nil, fmt.Errorf("not found rule-set: %s", domainSetName)
|
||||
} else {
|
||||
switch rp.Behavior() {
|
||||
case providerTypes.IPCIDR:
|
||||
return nil, fmt.Errorf("rule provider type error, except domain,actual %s", rp.Behavior())
|
||||
case providerTypes.Classical:
|
||||
log.Warnln("%s provider is %s, only matching it contain domain rule", rp.Name(), rp.Behavior())
|
||||
default:
|
||||
}
|
||||
}
|
||||
rule, err = RP.NewRuleSet(domainSetName, "", true)
|
||||
rule, err = parseDomainRuleSet(domainSetName, ruleProviders)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
domainRules = append(domainRules, rule)
|
||||
}
|
||||
} else {
|
||||
|
@ -1692,3 +1644,29 @@ func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], rules
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
func parseDomainRuleSet(domainSetName string, ruleProviders map[string]providerTypes.RuleProvider) (C.Rule, error) {
|
||||
if rp, ok := ruleProviders[domainSetName]; !ok {
|
||||
return nil, fmt.Errorf("not found rule-set: %s", domainSetName)
|
||||
} else {
|
||||
switch rp.Behavior() {
|
||||
case providerTypes.IPCIDR:
|
||||
return nil, fmt.Errorf("rule provider type error, except domain,actual %s", rp.Behavior())
|
||||
case providerTypes.Classical:
|
||||
log.Warnln("%s provider is %s, only matching it contain domain rule", rp.Name(), rp.Behavior())
|
||||
default:
|
||||
}
|
||||
}
|
||||
return RP.NewRuleSet(domainSetName, "", true)
|
||||
}
|
||||
|
||||
func parseGEOSITE(country string, rules []C.Rule) (C.Rule, error) {
|
||||
for _, rule := range rules {
|
||||
if rule.RuleType() == C.GEOSITE {
|
||||
if strings.EqualFold(country, rule.Payload()) {
|
||||
return rule, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return RC.NewGEOSITE(country, "")
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ const (
|
|||
ProcessPathRegex
|
||||
RuleSet
|
||||
DomainSet
|
||||
IpCidrSet
|
||||
Network
|
||||
Uid
|
||||
SubRules
|
||||
|
@ -93,6 +94,8 @@ func (rt RuleType) String() string {
|
|||
return "RuleSet"
|
||||
case DomainSet:
|
||||
return "DomainSet"
|
||||
case IpCidrSet:
|
||||
return "IpCidrSet"
|
||||
case Network:
|
||||
return "Network"
|
||||
case DSCP:
|
||||
|
@ -121,3 +124,8 @@ type Rule interface {
|
|||
ShouldFindProcess() bool
|
||||
ProviderNames() []string
|
||||
}
|
||||
|
||||
type RuleGroup interface {
|
||||
Rule
|
||||
GetRecodeSize() int
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
package constant
|
||||
|
||||
import (
|
||||
"github.com/metacubex/mihomo/component/geodata/router"
|
||||
)
|
||||
|
||||
type RuleGeoSite interface {
|
||||
GetDomainMatcher() router.DomainMatcher
|
||||
}
|
||||
|
||||
type RuleGeoIP interface {
|
||||
GetIPMatcher() *router.GeoIPMatcher
|
||||
}
|
||||
|
||||
type RuleGroup interface {
|
||||
GetRecodeSize() int
|
||||
}
|
102
dns/filters.go
102
dns/filters.go
|
@ -1,102 +0,0 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"strings"
|
||||
|
||||
"github.com/metacubex/mihomo/component/geodata"
|
||||
"github.com/metacubex/mihomo/component/geodata/router"
|
||||
"github.com/metacubex/mihomo/component/mmdb"
|
||||
"github.com/metacubex/mihomo/component/trie"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
)
|
||||
|
||||
type fallbackIPFilter interface {
|
||||
Match(netip.Addr) bool
|
||||
}
|
||||
|
||||
type geoipFilter struct {
|
||||
code string
|
||||
}
|
||||
|
||||
var geoIPMatcher *router.GeoIPMatcher
|
||||
|
||||
func (gf *geoipFilter) Match(ip netip.Addr) bool {
|
||||
if !C.GeodataMode {
|
||||
codes := mmdb.IPInstance().LookupCode(ip.AsSlice())
|
||||
for _, code := range codes {
|
||||
if !strings.EqualFold(code, gf.code) && !ip.IsPrivate() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if geoIPMatcher == nil {
|
||||
var err error
|
||||
geoIPMatcher, _, err = geodata.LoadGeoIPMatcher("CN")
|
||||
if err != nil {
|
||||
log.Errorln("[GeoIPFilter] LoadGeoIPMatcher error: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
}
|
||||
return !geoIPMatcher.Match(ip)
|
||||
}
|
||||
|
||||
type ipnetFilter struct {
|
||||
ipnet netip.Prefix
|
||||
}
|
||||
|
||||
func (inf *ipnetFilter) Match(ip netip.Addr) bool {
|
||||
return inf.ipnet.Contains(ip)
|
||||
}
|
||||
|
||||
type fallbackDomainFilter interface {
|
||||
Match(domain string) bool
|
||||
}
|
||||
|
||||
type domainFilter struct {
|
||||
tree *trie.DomainTrie[struct{}]
|
||||
}
|
||||
|
||||
func NewDomainFilter(domains []string) *domainFilter {
|
||||
df := domainFilter{tree: trie.New[struct{}]()}
|
||||
for _, domain := range domains {
|
||||
_ = df.tree.Insert(domain, struct{}{})
|
||||
}
|
||||
df.tree.Optimize()
|
||||
return &df
|
||||
}
|
||||
|
||||
func (df *domainFilter) Match(domain string) bool {
|
||||
return df.tree.Search(domain) != nil
|
||||
}
|
||||
|
||||
type geoSiteFilter struct {
|
||||
matchers []router.DomainMatcher
|
||||
}
|
||||
|
||||
func NewGeoSite(group string) (fallbackDomainFilter, error) {
|
||||
if err := geodata.InitGeoSite(); err != nil {
|
||||
log.Errorln("can't initial GeoSite: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
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 {
|
||||
for _, matcher := range gsf.matchers {
|
||||
if matcher.ApplyDomain(domain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -3,7 +3,6 @@ package dns
|
|||
import (
|
||||
"github.com/metacubex/mihomo/component/trie"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
"github.com/metacubex/mihomo/constant/provider"
|
||||
)
|
||||
|
||||
type dnsPolicy interface {
|
||||
|
@ -22,32 +21,14 @@ func (p domainTriePolicy) Match(domain string) []dnsClient {
|
|||
return nil
|
||||
}
|
||||
|
||||
type geositePolicy struct {
|
||||
matcher fallbackDomainFilter
|
||||
inverse bool
|
||||
type domainRulePolicy struct {
|
||||
rule C.Rule
|
||||
dnsClients []dnsClient
|
||||
}
|
||||
|
||||
func (p geositePolicy) Match(domain string) []dnsClient {
|
||||
matched := p.matcher.Match(domain)
|
||||
if matched != p.inverse {
|
||||
func (p domainRulePolicy) Match(domain string) []dnsClient {
|
||||
if ok, _ := p.rule.Match(&C.Metadata{Host: domain}); ok {
|
||||
return p.dnsClients
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type domainSetPolicy struct {
|
||||
tunnel provider.Tunnel
|
||||
name string
|
||||
dnsClients []dnsClient
|
||||
}
|
||||
|
||||
func (p domainSetPolicy) Match(domain string) []dnsClient {
|
||||
if ruleProvider, ok := p.tunnel.RuleProviders()[p.name]; ok {
|
||||
metadata := &C.Metadata{Host: domain}
|
||||
if ok := ruleProvider.Match(metadata); ok {
|
||||
return p.dnsClients
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
121
dns/resolver.go
121
dns/resolver.go
|
@ -4,13 +4,11 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/metacubex/mihomo/common/arc"
|
||||
"github.com/metacubex/mihomo/common/lru"
|
||||
"github.com/metacubex/mihomo/component/fakeip"
|
||||
"github.com/metacubex/mihomo/component/geodata/router"
|
||||
"github.com/metacubex/mihomo/component/resolver"
|
||||
"github.com/metacubex/mihomo/component/trie"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
|
@ -19,7 +17,6 @@ import (
|
|||
|
||||
D "github.com/miekg/dns"
|
||||
"github.com/samber/lo"
|
||||
orderedmap "github.com/wk8/go-ordered-map/v2"
|
||||
"golang.org/x/exp/maps"
|
||||
"golang.org/x/sync/singleflight"
|
||||
)
|
||||
|
@ -45,8 +42,8 @@ type Resolver struct {
|
|||
hosts *trie.DomainTrie[resolver.HostValue]
|
||||
main []dnsClient
|
||||
fallback []dnsClient
|
||||
fallbackDomainFilters []fallbackDomainFilter
|
||||
fallbackIPFilters []fallbackIPFilter
|
||||
fallbackDomainFilters []C.Rule
|
||||
fallbackIPFilters []C.Rule
|
||||
group singleflight.Group
|
||||
cache dnsCache
|
||||
policy []dnsPolicy
|
||||
|
@ -122,7 +119,7 @@ func (r *Resolver) LookupIPv6(ctx context.Context, host string) ([]netip.Addr, e
|
|||
|
||||
func (r *Resolver) shouldIPFallback(ip netip.Addr) bool {
|
||||
for _, filter := range r.fallbackIPFilters {
|
||||
if filter.Match(ip) {
|
||||
if ok, _ := filter.Match(&C.Metadata{DstIP: ip}); ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -277,7 +274,7 @@ func (r *Resolver) shouldOnlyQueryFallback(m *D.Msg) bool {
|
|||
}
|
||||
|
||||
for _, df := range r.fallbackDomainFilters {
|
||||
if df.Match(domain) {
|
||||
if ok, _ := df.Match(&C.Metadata{Host: domain}); ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -398,27 +395,26 @@ func (ns NameServer) Equal(ns2 NameServer) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
type FallbackFilter struct {
|
||||
GeoIP bool
|
||||
GeoIPCode string
|
||||
IPCIDR []netip.Prefix
|
||||
Domain []string
|
||||
GeoSite []router.DomainMatcher
|
||||
type Policy struct {
|
||||
Domain string
|
||||
Rule C.Rule
|
||||
NameServers []NameServer
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Main, Fallback []NameServer
|
||||
Default []NameServer
|
||||
ProxyServer []NameServer
|
||||
IPv6 bool
|
||||
IPv6Timeout uint
|
||||
EnhancedMode C.DNSMode
|
||||
FallbackFilter FallbackFilter
|
||||
Pool *fakeip.Pool
|
||||
Hosts *trie.DomainTrie[resolver.HostValue]
|
||||
Policy *orderedmap.OrderedMap[string, []NameServer]
|
||||
Tunnel provider.Tunnel
|
||||
CacheAlgorithm string
|
||||
Main, Fallback []NameServer
|
||||
Default []NameServer
|
||||
ProxyServer []NameServer
|
||||
IPv6 bool
|
||||
IPv6Timeout uint
|
||||
EnhancedMode C.DNSMode
|
||||
FallbackIPFilter []C.Rule
|
||||
FallbackDomainFilter []C.Rule
|
||||
Pool *fakeip.Pool
|
||||
Hosts *trie.DomainTrie[resolver.HostValue]
|
||||
Policy []Policy
|
||||
Tunnel provider.Tunnel
|
||||
CacheAlgorithm string
|
||||
}
|
||||
|
||||
func NewResolver(config Config) *Resolver {
|
||||
|
@ -482,7 +478,7 @@ func NewResolver(config Config) *Resolver {
|
|||
r.proxyServer = cacheTransform(config.ProxyServer)
|
||||
}
|
||||
|
||||
if config.Policy.Len() != 0 {
|
||||
if len(config.Policy) != 0 {
|
||||
r.policy = make([]dnsPolicy, 0)
|
||||
|
||||
var triePolicy *trie.DomainTrie[[]dnsClient]
|
||||
|
@ -497,75 +493,20 @@ func NewResolver(config Config) *Resolver {
|
|||
}
|
||||
}
|
||||
|
||||
for pair := config.Policy.Oldest(); pair != nil; pair = pair.Next() {
|
||||
domain, nameserver := pair.Key, pair.Value
|
||||
|
||||
if temp := strings.Split(domain, ":"); len(temp) == 2 {
|
||||
prefix := temp[0]
|
||||
key := temp[1]
|
||||
switch prefix {
|
||||
case "rule-set":
|
||||
if _, ok := config.Tunnel.RuleProviders()[key]; ok {
|
||||
log.Debugln("Adding rule-set policy: %s ", key)
|
||||
insertPolicy(domainSetPolicy{
|
||||
tunnel: config.Tunnel,
|
||||
name: key,
|
||||
dnsClients: cacheTransform(nameserver),
|
||||
})
|
||||
continue
|
||||
} else {
|
||||
log.Warnln("Can't found ruleset policy: %s", key)
|
||||
}
|
||||
case "geosite":
|
||||
inverse := false
|
||||
if strings.HasPrefix(key, "!") {
|
||||
inverse = true
|
||||
key = key[1:]
|
||||
}
|
||||
log.Debugln("Adding geosite policy: %s inversed %t", key, inverse)
|
||||
matcher, err := NewGeoSite(key)
|
||||
if err != nil {
|
||||
log.Warnln("adding geosite policy %s error: %s", key, err)
|
||||
continue
|
||||
}
|
||||
insertPolicy(geositePolicy{
|
||||
matcher: matcher,
|
||||
inverse: inverse,
|
||||
dnsClients: cacheTransform(nameserver),
|
||||
})
|
||||
continue // skip triePolicy new
|
||||
for _, policy := range config.Policy {
|
||||
if policy.Rule != nil {
|
||||
insertPolicy(domainRulePolicy{rule: policy.Rule, dnsClients: cacheTransform(policy.NameServers)})
|
||||
} else {
|
||||
if triePolicy == nil {
|
||||
triePolicy = trie.New[[]dnsClient]()
|
||||
}
|
||||
_ = triePolicy.Insert(policy.Domain, cacheTransform(policy.NameServers))
|
||||
}
|
||||
if triePolicy == nil {
|
||||
triePolicy = trie.New[[]dnsClient]()
|
||||
}
|
||||
_ = triePolicy.Insert(domain, cacheTransform(nameserver))
|
||||
}
|
||||
insertPolicy(nil)
|
||||
}
|
||||
|
||||
fallbackIPFilters := []fallbackIPFilter{}
|
||||
if config.FallbackFilter.GeoIP {
|
||||
fallbackIPFilters = append(fallbackIPFilters, &geoipFilter{
|
||||
code: config.FallbackFilter.GeoIPCode,
|
||||
})
|
||||
}
|
||||
for _, ipnet := range config.FallbackFilter.IPCIDR {
|
||||
fallbackIPFilters = append(fallbackIPFilters, &ipnetFilter{ipnet: ipnet})
|
||||
}
|
||||
r.fallbackIPFilters = fallbackIPFilters
|
||||
|
||||
fallbackDomainFilters := []fallbackDomainFilter{}
|
||||
if len(config.FallbackFilter.Domain) != 0 {
|
||||
fallbackDomainFilters = append(fallbackDomainFilters, NewDomainFilter(config.FallbackFilter.Domain))
|
||||
}
|
||||
|
||||
if len(config.FallbackFilter.GeoSite) != 0 {
|
||||
fallbackDomainFilters = append(fallbackDomainFilters, &geoSiteFilter{
|
||||
matchers: config.FallbackFilter.GeoSite,
|
||||
})
|
||||
}
|
||||
r.fallbackDomainFilters = fallbackDomainFilters
|
||||
r.fallbackIPFilters = config.FallbackIPFilter
|
||||
r.fallbackDomainFilters = config.FallbackDomainFilter
|
||||
|
||||
return r
|
||||
}
|
||||
|
|
|
@ -222,25 +222,20 @@ func updateDNS(c *config.DNS, generalIPv6 bool) {
|
|||
return
|
||||
}
|
||||
cfg := dns.Config{
|
||||
Main: c.NameServer,
|
||||
Fallback: c.Fallback,
|
||||
IPv6: c.IPv6 && generalIPv6,
|
||||
IPv6Timeout: c.IPv6Timeout,
|
||||
EnhancedMode: c.EnhancedMode,
|
||||
Pool: c.FakeIPRange,
|
||||
Hosts: c.Hosts,
|
||||
FallbackFilter: dns.FallbackFilter{
|
||||
GeoIP: c.FallbackFilter.GeoIP,
|
||||
GeoIPCode: c.FallbackFilter.GeoIPCode,
|
||||
IPCIDR: c.FallbackFilter.IPCIDR,
|
||||
Domain: c.FallbackFilter.Domain,
|
||||
GeoSite: c.FallbackFilter.GeoSite,
|
||||
},
|
||||
Default: c.DefaultNameserver,
|
||||
Policy: c.NameServerPolicy,
|
||||
ProxyServer: c.ProxyServerNameserver,
|
||||
Tunnel: tunnel.Tunnel,
|
||||
CacheAlgorithm: c.CacheAlgorithm,
|
||||
Main: c.NameServer,
|
||||
Fallback: c.Fallback,
|
||||
IPv6: c.IPv6 && generalIPv6,
|
||||
IPv6Timeout: c.IPv6Timeout,
|
||||
EnhancedMode: c.EnhancedMode,
|
||||
Pool: c.FakeIPRange,
|
||||
Hosts: c.Hosts,
|
||||
FallbackIPFilter: c.FallbackIPFilter,
|
||||
FallbackDomainFilter: c.FallbackDomainFilter,
|
||||
Default: c.DefaultNameserver,
|
||||
Policy: c.NameServerPolicy,
|
||||
ProxyServer: c.ProxyServerNameserver,
|
||||
Tunnel: tunnel.Tunnel,
|
||||
CacheAlgorithm: c.CacheAlgorithm,
|
||||
}
|
||||
|
||||
r := dns.NewResolver(cfg)
|
||||
|
|
|
@ -19,10 +19,7 @@ func (d *DomainSet) RuleType() C.RuleType {
|
|||
}
|
||||
|
||||
func (d *DomainSet) Match(metadata *C.Metadata) (bool, string) {
|
||||
if d.domainSet == nil {
|
||||
return false, ""
|
||||
}
|
||||
return d.domainSet.Has(metadata.RuleHost()), d.adapter
|
||||
return d.domainStrategy.Match(metadata), d.adapter
|
||||
}
|
||||
|
||||
func (d *DomainSet) Adapter() string {
|
||||
|
|
40
rules/provider/ipcidr_set.go
Normal file
40
rules/provider/ipcidr_set.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
"github.com/metacubex/mihomo/component/cidr"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
)
|
||||
|
||||
type IpCidrSet struct {
|
||||
*ipcidrStrategy
|
||||
adapter string
|
||||
}
|
||||
|
||||
func (d *IpCidrSet) ProviderNames() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *IpCidrSet) RuleType() C.RuleType {
|
||||
return C.IpCidrSet
|
||||
}
|
||||
|
||||
func (d *IpCidrSet) Match(metadata *C.Metadata) (bool, string) {
|
||||
return d.ipcidrStrategy.Match(metadata), d.adapter
|
||||
}
|
||||
|
||||
func (d *IpCidrSet) Adapter() string {
|
||||
return d.adapter
|
||||
}
|
||||
|
||||
func (d *IpCidrSet) Payload() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func NewIpCidrSet(cidrSet *cidr.IpCidrSet, adapter string) *IpCidrSet {
|
||||
return &IpCidrSet{
|
||||
ipcidrStrategy: &ipcidrStrategy{cidrSet: cidrSet},
|
||||
adapter: adapter,
|
||||
}
|
||||
}
|
||||
|
||||
var _ C.Rule = (*IpCidrSet)(nil)
|
Loading…
Reference in New Issue
Block a user