mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2025-05-23 02:18:03 +08:00
chore: cleanup dns policy match code
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"
|
N "github.com/metacubex/mihomo/common/net"
|
||||||
"github.com/metacubex/mihomo/common/utils"
|
"github.com/metacubex/mihomo/common/utils"
|
||||||
"github.com/metacubex/mihomo/component/auth"
|
"github.com/metacubex/mihomo/component/auth"
|
||||||
|
"github.com/metacubex/mihomo/component/cidr"
|
||||||
"github.com/metacubex/mihomo/component/fakeip"
|
"github.com/metacubex/mihomo/component/fakeip"
|
||||||
"github.com/metacubex/mihomo/component/geodata"
|
"github.com/metacubex/mihomo/component/geodata"
|
||||||
"github.com/metacubex/mihomo/component/geodata/router"
|
|
||||||
P "github.com/metacubex/mihomo/component/process"
|
P "github.com/metacubex/mihomo/component/process"
|
||||||
"github.com/metacubex/mihomo/component/resolver"
|
"github.com/metacubex/mihomo/component/resolver"
|
||||||
SNIFF "github.com/metacubex/mihomo/component/sniffer"
|
SNIFF "github.com/metacubex/mihomo/component/sniffer"
|
||||||
@ -114,33 +114,25 @@ type NTP struct {
|
|||||||
|
|
||||||
// DNS config
|
// DNS config
|
||||||
type DNS struct {
|
type DNS struct {
|
||||||
Enable bool `yaml:"enable"`
|
Enable bool
|
||||||
PreferH3 bool `yaml:"prefer-h3"`
|
PreferH3 bool
|
||||||
IPv6 bool `yaml:"ipv6"`
|
IPv6 bool
|
||||||
IPv6Timeout uint `yaml:"ipv6-timeout"`
|
IPv6Timeout uint
|
||||||
UseSystemHosts bool `yaml:"use-system-hosts"`
|
UseSystemHosts bool
|
||||||
NameServer []dns.NameServer `yaml:"nameserver"`
|
NameServer []dns.NameServer
|
||||||
Fallback []dns.NameServer `yaml:"fallback"`
|
Fallback []dns.NameServer
|
||||||
FallbackFilter FallbackFilter `yaml:"fallback-filter"`
|
FallbackIPFilter []C.Rule
|
||||||
Listen string `yaml:"listen"`
|
FallbackDomainFilter []C.Rule
|
||||||
EnhancedMode C.DNSMode `yaml:"enhanced-mode"`
|
Listen string
|
||||||
DefaultNameserver []dns.NameServer `yaml:"default-nameserver"`
|
EnhancedMode C.DNSMode
|
||||||
CacheAlgorithm string `yaml:"cache-algorithm"`
|
DefaultNameserver []dns.NameServer
|
||||||
|
CacheAlgorithm string
|
||||||
FakeIPRange *fakeip.Pool
|
FakeIPRange *fakeip.Pool
|
||||||
Hosts *trie.DomainTrie[resolver.HostValue]
|
Hosts *trie.DomainTrie[resolver.HostValue]
|
||||||
NameServerPolicy *orderedmap.OrderedMap[string, []dns.NameServer]
|
NameServerPolicy []dns.Policy
|
||||||
ProxyServerNameserver []dns.NameServer
|
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
|
// Profile config
|
||||||
type Profile struct {
|
type Profile struct {
|
||||||
StoreSelected bool `yaml:"store-selected"`
|
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) {
|
func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rules []C.Rule, ruleProviders map[string]providerTypes.RuleProvider, respectRules bool, preferH3 bool) ([]dns.Policy, error) {
|
||||||
policy := orderedmap.New[string, []dns.NameServer]()
|
var policy []dns.Policy
|
||||||
updatedPolicy := orderedmap.New[string, any]()
|
|
||||||
re := regexp.MustCompile(`[a-zA-Z0-9\-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?`)
|
re := regexp.MustCompile(`[a-zA-Z0-9\-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?`)
|
||||||
|
|
||||||
for pair := nsPolicy.Oldest(); pair != nil; pair = pair.Next() {
|
for pair := nsPolicy.Oldest(); pair != nil; pair = pair.Next() {
|
||||||
k, v := pair.Key, pair.Value
|
k, v := pair.Key, pair.Value
|
||||||
if strings.Contains(strings.ToLower(k), ",") {
|
servers, err := utils.ToStringSlice(v)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1255,75 +1211,65 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rulePro
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if _, valid := trie.ValidAndSplitDomain(domain); !valid {
|
if strings.Contains(strings.ToLower(k), ",") {
|
||||||
return nil, fmt.Errorf("DNS ResoverRule invalid domain: %s", domain)
|
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:") {
|
if strings.HasPrefix(domain, "rule-set:") {
|
||||||
domainSetName := domain[9:]
|
domainSetName := domain[9:]
|
||||||
if provider, ok := ruleProviders[domainSetName]; !ok {
|
rule, err := parseDomainRuleSet(domainSetName, ruleProviders)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
policy[idx] = dns.Policy{Rule: rule, NameServers: nameservers}
|
||||||
sites = append(sites, matcher)
|
} else if strings.HasPrefix(domain, "geosite:") {
|
||||||
|
country := domain[8:]
|
||||||
log.Infoln("Start initial GeoSite dns fallback filter `%s`, records: %d", country, recordsCount)
|
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 {
|
func paresNTP(rawCfg *RawConfig) *NTP {
|
||||||
@ -1357,10 +1303,6 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul
|
|||||||
IPv6: cfg.IPv6,
|
IPv6: cfg.IPv6,
|
||||||
UseSystemHosts: cfg.UseSystemHosts,
|
UseSystemHosts: cfg.UseSystemHosts,
|
||||||
EnhancedMode: cfg.EnhancedMode,
|
EnhancedMode: cfg.EnhancedMode,
|
||||||
FallbackFilter: FallbackFilter{
|
|
||||||
IPCIDR: []netip.Prefix{},
|
|
||||||
GeoSite: []router.DomainMatcher{},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
if dnsCfg.NameServer, err = parseNameServer(cfg.NameServer, cfg.RespectRules, cfg.PreferH3); err != nil {
|
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
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1438,18 +1380,51 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul
|
|||||||
dnsCfg.FakeIPRange = pool
|
dnsCfg.FakeIPRange = pool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var rule C.Rule
|
||||||
if len(cfg.Fallback) != 0 {
|
if len(cfg.Fallback) != 0 {
|
||||||
dnsCfg.FallbackFilter.GeoIP = cfg.FallbackFilter.GeoIP
|
if cfg.FallbackFilter.GeoIP {
|
||||||
dnsCfg.FallbackFilter.GeoIPCode = cfg.FallbackFilter.GeoIPCode
|
rule, err = RC.NewGEOIP(cfg.FallbackFilter.GeoIPCode, "", false, true)
|
||||||
if fallbackip, err := parseFallbackIPCIDR(cfg.FallbackFilter.IPCIDR); err == nil {
|
if err != nil {
|
||||||
dnsCfg.FallbackFilter.IPCIDR = fallbackip
|
return nil, fmt.Errorf("load GeoIP dns fallback filter error, %w", err)
|
||||||
|
}
|
||||||
|
dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, rule)
|
||||||
}
|
}
|
||||||
dnsCfg.FallbackFilter.Domain = cfg.FallbackFilter.Domain
|
if len(cfg.FallbackFilter.IPCIDR) > 0 {
|
||||||
fallbackGeoSite, err := parseFallbackGeoSite(cfg.FallbackFilter.GeoSite, rules)
|
cidrSet := cidr.NewIpCidrSet()
|
||||||
if err != nil {
|
for idx, ipcidr := range cfg.FallbackFilter.IPCIDR {
|
||||||
return nil, fmt.Errorf("load GeoSite dns fallback filter error, %w", err)
|
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 {
|
if cfg.UseHosts {
|
||||||
@ -1636,44 +1611,21 @@ func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], rules
|
|||||||
subkeys = subkeys[1:]
|
subkeys = subkeys[1:]
|
||||||
subkeys = strings.Split(subkeys[0], ",")
|
subkeys = strings.Split(subkeys[0], ",")
|
||||||
for _, country := range subkeys {
|
for _, country := range subkeys {
|
||||||
found := false
|
rule, err = parseGEOSITE(country, rules)
|
||||||
for _, rule = range rules {
|
if err != nil {
|
||||||
if rule.RuleType() == C.GEOSITE {
|
return nil, err
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
domainRules = append(domainRules, rule)
|
||||||
}
|
}
|
||||||
} else if strings.Contains(domainLower, "rule-set:") {
|
} else if strings.Contains(domainLower, "rule-set:") {
|
||||||
subkeys := strings.Split(domain, ":")
|
subkeys := strings.Split(domain, ":")
|
||||||
subkeys = subkeys[1:]
|
subkeys = subkeys[1:]
|
||||||
subkeys = strings.Split(subkeys[0], ",")
|
subkeys = strings.Split(subkeys[0], ",")
|
||||||
for _, domainSetName := range subkeys {
|
for _, domainSetName := range subkeys {
|
||||||
if rp, ok := ruleProviders[domainSetName]; !ok {
|
rule, err = parseDomainRuleSet(domainSetName, ruleProviders)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
domainRules = append(domainRules, rule)
|
domainRules = append(domainRules, rule)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1692,3 +1644,29 @@ func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], rules
|
|||||||
}
|
}
|
||||||
return
|
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
|
ProcessPathRegex
|
||||||
RuleSet
|
RuleSet
|
||||||
DomainSet
|
DomainSet
|
||||||
|
IpCidrSet
|
||||||
Network
|
Network
|
||||||
Uid
|
Uid
|
||||||
SubRules
|
SubRules
|
||||||
@ -93,6 +94,8 @@ func (rt RuleType) String() string {
|
|||||||
return "RuleSet"
|
return "RuleSet"
|
||||||
case DomainSet:
|
case DomainSet:
|
||||||
return "DomainSet"
|
return "DomainSet"
|
||||||
|
case IpCidrSet:
|
||||||
|
return "IpCidrSet"
|
||||||
case Network:
|
case Network:
|
||||||
return "Network"
|
return "Network"
|
||||||
case DSCP:
|
case DSCP:
|
||||||
@ -121,3 +124,8 @@ type Rule interface {
|
|||||||
ShouldFindProcess() bool
|
ShouldFindProcess() bool
|
||||||
ProviderNames() []string
|
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 (
|
import (
|
||||||
"github.com/metacubex/mihomo/component/trie"
|
"github.com/metacubex/mihomo/component/trie"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
"github.com/metacubex/mihomo/constant/provider"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type dnsPolicy interface {
|
type dnsPolicy interface {
|
||||||
@ -22,32 +21,14 @@ func (p domainTriePolicy) Match(domain string) []dnsClient {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type geositePolicy struct {
|
type domainRulePolicy struct {
|
||||||
matcher fallbackDomainFilter
|
rule C.Rule
|
||||||
inverse bool
|
|
||||||
dnsClients []dnsClient
|
dnsClients []dnsClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p geositePolicy) Match(domain string) []dnsClient {
|
func (p domainRulePolicy) Match(domain string) []dnsClient {
|
||||||
matched := p.matcher.Match(domain)
|
if ok, _ := p.rule.Match(&C.Metadata{Host: domain}); ok {
|
||||||
if matched != p.inverse {
|
|
||||||
return p.dnsClients
|
return p.dnsClients
|
||||||
}
|
}
|
||||||
return nil
|
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"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/metacubex/mihomo/common/arc"
|
"github.com/metacubex/mihomo/common/arc"
|
||||||
"github.com/metacubex/mihomo/common/lru"
|
"github.com/metacubex/mihomo/common/lru"
|
||||||
"github.com/metacubex/mihomo/component/fakeip"
|
"github.com/metacubex/mihomo/component/fakeip"
|
||||||
"github.com/metacubex/mihomo/component/geodata/router"
|
|
||||||
"github.com/metacubex/mihomo/component/resolver"
|
"github.com/metacubex/mihomo/component/resolver"
|
||||||
"github.com/metacubex/mihomo/component/trie"
|
"github.com/metacubex/mihomo/component/trie"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
@ -19,7 +17,6 @@ import (
|
|||||||
|
|
||||||
D "github.com/miekg/dns"
|
D "github.com/miekg/dns"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
orderedmap "github.com/wk8/go-ordered-map/v2"
|
|
||||||
"golang.org/x/exp/maps"
|
"golang.org/x/exp/maps"
|
||||||
"golang.org/x/sync/singleflight"
|
"golang.org/x/sync/singleflight"
|
||||||
)
|
)
|
||||||
@ -45,8 +42,8 @@ type Resolver struct {
|
|||||||
hosts *trie.DomainTrie[resolver.HostValue]
|
hosts *trie.DomainTrie[resolver.HostValue]
|
||||||
main []dnsClient
|
main []dnsClient
|
||||||
fallback []dnsClient
|
fallback []dnsClient
|
||||||
fallbackDomainFilters []fallbackDomainFilter
|
fallbackDomainFilters []C.Rule
|
||||||
fallbackIPFilters []fallbackIPFilter
|
fallbackIPFilters []C.Rule
|
||||||
group singleflight.Group
|
group singleflight.Group
|
||||||
cache dnsCache
|
cache dnsCache
|
||||||
policy []dnsPolicy
|
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 {
|
func (r *Resolver) shouldIPFallback(ip netip.Addr) bool {
|
||||||
for _, filter := range r.fallbackIPFilters {
|
for _, filter := range r.fallbackIPFilters {
|
||||||
if filter.Match(ip) {
|
if ok, _ := filter.Match(&C.Metadata{DstIP: ip}); ok {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -277,7 +274,7 @@ func (r *Resolver) shouldOnlyQueryFallback(m *D.Msg) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, df := range r.fallbackDomainFilters {
|
for _, df := range r.fallbackDomainFilters {
|
||||||
if df.Match(domain) {
|
if ok, _ := df.Match(&C.Metadata{Host: domain}); ok {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -398,27 +395,26 @@ func (ns NameServer) Equal(ns2 NameServer) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
type FallbackFilter struct {
|
type Policy struct {
|
||||||
GeoIP bool
|
Domain string
|
||||||
GeoIPCode string
|
Rule C.Rule
|
||||||
IPCIDR []netip.Prefix
|
NameServers []NameServer
|
||||||
Domain []string
|
|
||||||
GeoSite []router.DomainMatcher
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Main, Fallback []NameServer
|
Main, Fallback []NameServer
|
||||||
Default []NameServer
|
Default []NameServer
|
||||||
ProxyServer []NameServer
|
ProxyServer []NameServer
|
||||||
IPv6 bool
|
IPv6 bool
|
||||||
IPv6Timeout uint
|
IPv6Timeout uint
|
||||||
EnhancedMode C.DNSMode
|
EnhancedMode C.DNSMode
|
||||||
FallbackFilter FallbackFilter
|
FallbackIPFilter []C.Rule
|
||||||
Pool *fakeip.Pool
|
FallbackDomainFilter []C.Rule
|
||||||
Hosts *trie.DomainTrie[resolver.HostValue]
|
Pool *fakeip.Pool
|
||||||
Policy *orderedmap.OrderedMap[string, []NameServer]
|
Hosts *trie.DomainTrie[resolver.HostValue]
|
||||||
Tunnel provider.Tunnel
|
Policy []Policy
|
||||||
CacheAlgorithm string
|
Tunnel provider.Tunnel
|
||||||
|
CacheAlgorithm string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewResolver(config Config) *Resolver {
|
func NewResolver(config Config) *Resolver {
|
||||||
@ -482,7 +478,7 @@ func NewResolver(config Config) *Resolver {
|
|||||||
r.proxyServer = cacheTransform(config.ProxyServer)
|
r.proxyServer = cacheTransform(config.ProxyServer)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Policy.Len() != 0 {
|
if len(config.Policy) != 0 {
|
||||||
r.policy = make([]dnsPolicy, 0)
|
r.policy = make([]dnsPolicy, 0)
|
||||||
|
|
||||||
var triePolicy *trie.DomainTrie[[]dnsClient]
|
var triePolicy *trie.DomainTrie[[]dnsClient]
|
||||||
@ -497,75 +493,20 @@ func NewResolver(config Config) *Resolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for pair := config.Policy.Oldest(); pair != nil; pair = pair.Next() {
|
for _, policy := range config.Policy {
|
||||||
domain, nameserver := pair.Key, pair.Value
|
if policy.Rule != nil {
|
||||||
|
insertPolicy(domainRulePolicy{rule: policy.Rule, dnsClients: cacheTransform(policy.NameServers)})
|
||||||
if temp := strings.Split(domain, ":"); len(temp) == 2 {
|
} else {
|
||||||
prefix := temp[0]
|
if triePolicy == nil {
|
||||||
key := temp[1]
|
triePolicy = trie.New[[]dnsClient]()
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
_ = triePolicy.Insert(policy.Domain, cacheTransform(policy.NameServers))
|
||||||
}
|
}
|
||||||
if triePolicy == nil {
|
|
||||||
triePolicy = trie.New[[]dnsClient]()
|
|
||||||
}
|
|
||||||
_ = triePolicy.Insert(domain, cacheTransform(nameserver))
|
|
||||||
}
|
}
|
||||||
insertPolicy(nil)
|
insertPolicy(nil)
|
||||||
}
|
}
|
||||||
|
r.fallbackIPFilters = config.FallbackIPFilter
|
||||||
fallbackIPFilters := []fallbackIPFilter{}
|
r.fallbackDomainFilters = config.FallbackDomainFilter
|
||||||
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
|
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
@ -222,25 +222,20 @@ func updateDNS(c *config.DNS, generalIPv6 bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
cfg := dns.Config{
|
cfg := dns.Config{
|
||||||
Main: c.NameServer,
|
Main: c.NameServer,
|
||||||
Fallback: c.Fallback,
|
Fallback: c.Fallback,
|
||||||
IPv6: c.IPv6 && generalIPv6,
|
IPv6: c.IPv6 && generalIPv6,
|
||||||
IPv6Timeout: c.IPv6Timeout,
|
IPv6Timeout: c.IPv6Timeout,
|
||||||
EnhancedMode: c.EnhancedMode,
|
EnhancedMode: c.EnhancedMode,
|
||||||
Pool: c.FakeIPRange,
|
Pool: c.FakeIPRange,
|
||||||
Hosts: c.Hosts,
|
Hosts: c.Hosts,
|
||||||
FallbackFilter: dns.FallbackFilter{
|
FallbackIPFilter: c.FallbackIPFilter,
|
||||||
GeoIP: c.FallbackFilter.GeoIP,
|
FallbackDomainFilter: c.FallbackDomainFilter,
|
||||||
GeoIPCode: c.FallbackFilter.GeoIPCode,
|
Default: c.DefaultNameserver,
|
||||||
IPCIDR: c.FallbackFilter.IPCIDR,
|
Policy: c.NameServerPolicy,
|
||||||
Domain: c.FallbackFilter.Domain,
|
ProxyServer: c.ProxyServerNameserver,
|
||||||
GeoSite: c.FallbackFilter.GeoSite,
|
Tunnel: tunnel.Tunnel,
|
||||||
},
|
CacheAlgorithm: c.CacheAlgorithm,
|
||||||
Default: c.DefaultNameserver,
|
|
||||||
Policy: c.NameServerPolicy,
|
|
||||||
ProxyServer: c.ProxyServerNameserver,
|
|
||||||
Tunnel: tunnel.Tunnel,
|
|
||||||
CacheAlgorithm: c.CacheAlgorithm,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r := dns.NewResolver(cfg)
|
r := dns.NewResolver(cfg)
|
||||||
|
@ -19,10 +19,7 @@ func (d *DomainSet) RuleType() C.RuleType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DomainSet) Match(metadata *C.Metadata) (bool, string) {
|
func (d *DomainSet) Match(metadata *C.Metadata) (bool, string) {
|
||||||
if d.domainSet == nil {
|
return d.domainStrategy.Match(metadata), d.adapter
|
||||||
return false, ""
|
|
||||||
}
|
|
||||||
return d.domainSet.Has(metadata.RuleHost()), d.adapter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DomainSet) Adapter() string {
|
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