mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2024-12-22 23:57:26 +08:00
chore: add sourceGeoIP
and sourceIPASN
to metadata
This commit is contained in:
parent
8483178524
commit
4fecf68b8b
@ -46,6 +46,14 @@ func (set *IpCidrSet) IsContain(ip netip.Addr) bool {
|
||||
return set.ToIPSet().Contains(ip.WithZone(""))
|
||||
}
|
||||
|
||||
// MatchIp implements C.IpMatcher
|
||||
func (set *IpCidrSet) MatchIp(ip netip.Addr) bool {
|
||||
if set.IsEmpty() {
|
||||
return false
|
||||
}
|
||||
return set.IsContain(ip)
|
||||
}
|
||||
|
||||
func (set *IpCidrSet) Merge() error {
|
||||
var b netipx.IPSetBuilder
|
||||
b.AddSet(set.ToIPSet())
|
||||
|
@ -35,7 +35,7 @@ type Pool struct {
|
||||
offset netip.Addr
|
||||
cycle bool
|
||||
mux sync.Mutex
|
||||
host []C.Rule
|
||||
host []C.DomainMatcher
|
||||
ipnet netip.Prefix
|
||||
store store
|
||||
}
|
||||
@ -66,8 +66,8 @@ func (p *Pool) LookBack(ip netip.Addr) (string, bool) {
|
||||
|
||||
// ShouldSkipped return if domain should be skipped
|
||||
func (p *Pool) ShouldSkipped(domain string) bool {
|
||||
for _, rule := range p.host {
|
||||
if match, _ := rule.Match(&C.Metadata{Host: domain}); match {
|
||||
for _, matcher := range p.host {
|
||||
if matcher.MatchDomain(domain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -156,7 +156,7 @@ func (p *Pool) restoreState() {
|
||||
|
||||
type Options struct {
|
||||
IPNet netip.Prefix
|
||||
Host []C.Rule
|
||||
Host []C.DomainMatcher
|
||||
|
||||
// Size sets the maximum number of entries in memory
|
||||
// and does not work if Persistence is true
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
"github.com/metacubex/mihomo/component/profile/cachefile"
|
||||
"github.com/metacubex/mihomo/component/trie"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
RP "github.com/metacubex/mihomo/rules/provider"
|
||||
|
||||
"github.com/metacubex/bbolt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -157,7 +156,7 @@ func TestPool_Skip(t *testing.T) {
|
||||
pools, tempfile, err := createPools(Options{
|
||||
IPNet: ipnet,
|
||||
Size: 10,
|
||||
Host: []C.Rule{RP.NewDomainSet(tree.NewDomainSet(), "")},
|
||||
Host: []C.DomainMatcher{tree.NewDomainSet()},
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
defer os.Remove(tempfile)
|
||||
|
@ -22,23 +22,23 @@ var (
|
||||
type Dispatcher struct {
|
||||
enable bool
|
||||
sniffers map[sniffer.Sniffer]SnifferConfig
|
||||
forceDomain []C.Rule
|
||||
skipSrcAddress []C.Rule
|
||||
skipDstAddress []C.Rule
|
||||
skipDomain []C.Rule
|
||||
forceDomain []C.DomainMatcher
|
||||
skipSrcAddress []C.IpMatcher
|
||||
skipDstAddress []C.IpMatcher
|
||||
skipDomain []C.DomainMatcher
|
||||
skipList *lru.LruCache[netip.AddrPort, uint8]
|
||||
forceDnsMapping bool
|
||||
parsePureIp bool
|
||||
}
|
||||
|
||||
func (sd *Dispatcher) shouldOverride(metadata *C.Metadata) bool {
|
||||
for _, rule := range sd.skipDstAddress {
|
||||
if ok, _ := rule.Match(&C.Metadata{DstIP: metadata.DstIP}); ok {
|
||||
for _, matcher := range sd.skipDstAddress {
|
||||
if matcher.MatchIp(metadata.DstIP) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for _, rule := range sd.skipSrcAddress {
|
||||
if ok, _ := rule.Match(&C.Metadata{DstIP: metadata.SrcIP}); ok {
|
||||
for _, matcher := range sd.skipSrcAddress {
|
||||
if matcher.MatchIp(metadata.SrcIP) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -48,8 +48,8 @@ func (sd *Dispatcher) shouldOverride(metadata *C.Metadata) bool {
|
||||
if metadata.DNSMode == C.DNSMapping && sd.forceDnsMapping {
|
||||
return true
|
||||
}
|
||||
for _, rule := range sd.forceDomain {
|
||||
if ok, _ := rule.Match(&C.Metadata{Host: metadata.Host}); ok {
|
||||
for _, matcher := range sd.forceDomain {
|
||||
if matcher.MatchDomain(metadata.Host) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -112,8 +112,8 @@ func (sd *Dispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata) bool
|
||||
return false
|
||||
}
|
||||
|
||||
for _, rule := range sd.skipDomain {
|
||||
if ok, _ := rule.Match(&C.Metadata{Host: host}); ok {
|
||||
for _, matcher := range sd.skipDomain {
|
||||
if matcher.MatchDomain(host) {
|
||||
log.Debugln("[Sniffer] Skip sni[%s]", host)
|
||||
return false
|
||||
}
|
||||
@ -200,10 +200,10 @@ func (sd *Dispatcher) cacheSniffFailed(metadata *C.Metadata) {
|
||||
type Config struct {
|
||||
Enable bool
|
||||
Sniffers map[sniffer.Type]SnifferConfig
|
||||
ForceDomain []C.Rule
|
||||
SkipSrcAddress []C.Rule
|
||||
SkipDstAddress []C.Rule
|
||||
SkipDomain []C.Rule
|
||||
ForceDomain []C.DomainMatcher
|
||||
SkipSrcAddress []C.IpMatcher
|
||||
SkipDstAddress []C.IpMatcher
|
||||
SkipDomain []C.DomainMatcher
|
||||
ForceDnsMapping bool
|
||||
ParsePureIp bool
|
||||
}
|
||||
|
@ -172,6 +172,11 @@ func (ss *DomainSet) Foreach(f func(key string) bool) {
|
||||
})
|
||||
}
|
||||
|
||||
// MatchDomain implements C.DomainMatcher
|
||||
func (ss *DomainSet) MatchDomain(domain string) bool {
|
||||
return ss.Has(domain)
|
||||
}
|
||||
|
||||
func setBit(bm *[]uint64, i int, v int) {
|
||||
for i>>6 >= len(*bm) {
|
||||
*bm = append(*bm, 0)
|
||||
|
@ -143,8 +143,8 @@ type DNS struct {
|
||||
UseSystemHosts bool
|
||||
NameServer []dns.NameServer
|
||||
Fallback []dns.NameServer
|
||||
FallbackIPFilter []C.Rule
|
||||
FallbackDomainFilter []C.Rule
|
||||
FallbackIPFilter []C.IpMatcher
|
||||
FallbackDomainFilter []C.DomainMatcher
|
||||
Listen string
|
||||
EnhancedMode C.DNSMode
|
||||
DefaultNameserver []dns.NameServer
|
||||
@ -640,7 +640,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
||||
}
|
||||
config.Hosts = hosts
|
||||
|
||||
dnsCfg, err := parseDNS(rawCfg, hosts, rules, ruleProviders)
|
||||
dnsCfg, err := parseDNS(rawCfg, hosts, ruleProviders)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1297,7 +1297,7 @@ func parsePureDNSServer(server string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rules []C.Rule, ruleProviders map[string]providerTypes.RuleProvider, respectRules bool, preferH3 bool) ([]dns.Policy, error) {
|
||||
func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], 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,})?`)
|
||||
|
||||
@ -1350,18 +1350,18 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rules [
|
||||
|
||||
if strings.HasPrefix(domain, "rule-set:") {
|
||||
domainSetName := domain[9:]
|
||||
rule, err := parseDomainRuleSet(domainSetName, "dns.nameserver-policy", ruleProviders)
|
||||
matcher, err := parseDomainRuleSet(domainSetName, "dns.nameserver-policy", ruleProviders)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
policy[idx] = dns.Policy{Rule: rule, NameServers: nameservers}
|
||||
policy[idx] = dns.Policy{Matcher: matcher, NameServers: nameservers}
|
||||
} else if strings.HasPrefix(domain, "geosite:") {
|
||||
country := domain[8:]
|
||||
rule, err := RC.NewGEOSITE(country, "dns.nameserver-policy")
|
||||
matcher, err := RC.NewGEOSITE(country, "dns.nameserver-policy")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
policy[idx] = dns.Policy{Rule: rule, NameServers: nameservers}
|
||||
policy[idx] = dns.Policy{Matcher: matcher, NameServers: nameservers}
|
||||
} else {
|
||||
if _, valid := trie.ValidAndSplitDomain(domain); !valid {
|
||||
return nil, fmt.Errorf("DNS ResoverRule invalid domain: %s", domain)
|
||||
@ -1372,7 +1372,7 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rules [
|
||||
return policy, nil
|
||||
}
|
||||
|
||||
func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rules []C.Rule, ruleProviders map[string]providerTypes.RuleProvider) (*DNS, error) {
|
||||
func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], ruleProviders map[string]providerTypes.RuleProvider) (*DNS, error) {
|
||||
cfg := rawCfg.DNS
|
||||
if cfg.Enable && len(cfg.NameServer) == 0 {
|
||||
return nil, fmt.Errorf("if DNS configuration is turned on, NameServer cannot be empty")
|
||||
@ -1400,7 +1400,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy, rules, ruleProviders, cfg.RespectRules, cfg.PreferH3); err != nil {
|
||||
if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy, ruleProviders, cfg.RespectRules, cfg.PreferH3); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -1467,14 +1467,13 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul
|
||||
dnsCfg.FakeIPRange = pool
|
||||
}
|
||||
|
||||
var rule C.Rule
|
||||
if len(cfg.Fallback) != 0 {
|
||||
if cfg.FallbackFilter.GeoIP {
|
||||
rule, err = RC.NewGEOIP(cfg.FallbackFilter.GeoIPCode, "dns.fallback-filter.geoip", false, true)
|
||||
matcher, err := RC.NewGEOIP(cfg.FallbackFilter.GeoIPCode, "dns.fallback-filter.geoip", false, true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load GeoIP dns fallback filter error, %w", err)
|
||||
}
|
||||
dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, rule)
|
||||
dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, matcher)
|
||||
}
|
||||
if len(cfg.FallbackFilter.IPCIDR) > 0 {
|
||||
cidrSet := cidr.NewIpCidrSet()
|
||||
@ -1488,8 +1487,8 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rule = RP.NewIpCidrSet(cidrSet, "dns.fallback-filter.ipcidr")
|
||||
dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, rule)
|
||||
matcher := cidrSet // dns.fallback-filter.ipcidr
|
||||
dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, matcher)
|
||||
}
|
||||
if len(cfg.FallbackFilter.Domain) > 0 {
|
||||
domainTrie := trie.New[struct{}]()
|
||||
@ -1499,17 +1498,17 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul
|
||||
return nil, fmt.Errorf("DNS FallbackDomain[%d] format error: %w", idx, err)
|
||||
}
|
||||
}
|
||||
rule = RP.NewDomainSet(domainTrie.NewDomainSet(), "dns.fallback-filter.domain")
|
||||
dnsCfg.FallbackDomainFilter = append(dnsCfg.FallbackDomainFilter, rule)
|
||||
matcher := domainTrie.NewDomainSet() // dns.fallback-filter.domain
|
||||
dnsCfg.FallbackDomainFilter = append(dnsCfg.FallbackDomainFilter, matcher)
|
||||
}
|
||||
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 = RC.NewGEOSITE(geoSite, "dns.fallback-filter.geosite")
|
||||
matcher, err := RC.NewGEOSITE(geoSite, "dns.fallback-filter.geosite")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("DNS FallbackGeosite[%d] format error: %w", idx, err)
|
||||
}
|
||||
dnsCfg.FallbackDomainFilter = append(dnsCfg.FallbackDomainFilter, rule)
|
||||
dnsCfg.FallbackDomainFilter = append(dnsCfg.FallbackDomainFilter, matcher)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1701,8 +1700,8 @@ func parseSniffer(snifferRaw RawSniffer, ruleProviders map[string]providerTypes.
|
||||
return snifferConfig, nil
|
||||
}
|
||||
|
||||
func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (ipRules []C.Rule, err error) {
|
||||
var rule C.Rule
|
||||
func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (matchers []C.IpMatcher, err error) {
|
||||
var matcher C.IpMatcher
|
||||
for _, ipcidr := range addresses {
|
||||
ipcidrLower := strings.ToLower(ipcidr)
|
||||
if strings.Contains(ipcidrLower, "geoip:") {
|
||||
@ -1710,22 +1709,22 @@ func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string
|
||||
subkeys = subkeys[1:]
|
||||
subkeys = strings.Split(subkeys[0], ",")
|
||||
for _, country := range subkeys {
|
||||
rule, err = RC.NewGEOIP(country, adapterName, false, false)
|
||||
matcher, err = RC.NewGEOIP(country, adapterName, false, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipRules = append(ipRules, rule)
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
} else if strings.Contains(ipcidrLower, "rule-set:") {
|
||||
subkeys := strings.Split(ipcidr, ":")
|
||||
subkeys = subkeys[1:]
|
||||
subkeys = strings.Split(subkeys[0], ",")
|
||||
for _, domainSetName := range subkeys {
|
||||
rule, err = parseIPRuleSet(domainSetName, adapterName, ruleProviders)
|
||||
matcher, err = parseIPRuleSet(domainSetName, adapterName, ruleProviders)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipRules = append(ipRules, rule)
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
} else {
|
||||
if cidrSet == nil {
|
||||
@ -1742,14 +1741,14 @@ func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rule = RP.NewIpCidrSet(cidrSet, adapterName)
|
||||
ipRules = append(ipRules, rule)
|
||||
matcher = cidrSet
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (domainRules []C.Rule, err error) {
|
||||
var rule C.Rule
|
||||
func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (matchers []C.DomainMatcher, err error) {
|
||||
var matcher C.DomainMatcher
|
||||
for _, domain := range domains {
|
||||
domainLower := strings.ToLower(domain)
|
||||
if strings.Contains(domainLower, "geosite:") {
|
||||
@ -1757,22 +1756,22 @@ func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapte
|
||||
subkeys = subkeys[1:]
|
||||
subkeys = strings.Split(subkeys[0], ",")
|
||||
for _, country := range subkeys {
|
||||
rule, err = RC.NewGEOSITE(country, adapterName)
|
||||
matcher, err = RC.NewGEOSITE(country, adapterName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domainRules = append(domainRules, rule)
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
} else if strings.Contains(domainLower, "rule-set:") {
|
||||
subkeys := strings.Split(domain, ":")
|
||||
subkeys = subkeys[1:]
|
||||
subkeys = strings.Split(subkeys[0], ",")
|
||||
for _, domainSetName := range subkeys {
|
||||
rule, err = parseDomainRuleSet(domainSetName, adapterName, ruleProviders)
|
||||
matcher, err = parseDomainRuleSet(domainSetName, adapterName, ruleProviders)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domainRules = append(domainRules, rule)
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
} else {
|
||||
if domainTrie == nil {
|
||||
@ -1785,13 +1784,13 @@ func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapte
|
||||
}
|
||||
}
|
||||
if !domainTrie.IsEmpty() {
|
||||
rule = RP.NewDomainSet(domainTrie.NewDomainSet(), adapterName)
|
||||
domainRules = append(domainRules, rule)
|
||||
matcher = domainTrie.NewDomainSet()
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func parseIPRuleSet(domainSetName string, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (C.Rule, error) {
|
||||
func parseIPRuleSet(domainSetName string, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (C.IpMatcher, error) {
|
||||
if rp, ok := ruleProviders[domainSetName]; !ok {
|
||||
return nil, fmt.Errorf("not found rule-set: %s", domainSetName)
|
||||
} else {
|
||||
@ -1806,7 +1805,7 @@ func parseIPRuleSet(domainSetName string, adapterName string, ruleProviders map[
|
||||
return RP.NewRuleSet(domainSetName, adapterName, true)
|
||||
}
|
||||
|
||||
func parseDomainRuleSet(domainSetName string, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (C.Rule, error) {
|
||||
func parseDomainRuleSet(domainSetName string, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (C.DomainMatcher, error) {
|
||||
if rp, ok := ruleProviders[domainSetName]; !ok {
|
||||
return nil, fmt.Errorf("not found rule-set: %s", domainSetName)
|
||||
} else {
|
||||
|
11
constant/matcher.go
Normal file
11
constant/matcher.go
Normal file
@ -0,0 +1,11 @@
|
||||
package constant
|
||||
|
||||
import "net/netip"
|
||||
|
||||
type DomainMatcher interface {
|
||||
MatchDomain(domain string) bool
|
||||
}
|
||||
|
||||
type IpMatcher interface {
|
||||
MatchIp(ip netip.Addr) bool
|
||||
}
|
@ -133,7 +133,9 @@ type Metadata struct {
|
||||
Type Type `json:"type"`
|
||||
SrcIP netip.Addr `json:"sourceIP"`
|
||||
DstIP netip.Addr `json:"destinationIP"`
|
||||
SrcGeoIP []string `json:"sourceGeoIP"` // can be nil if never queried, empty slice if got no result
|
||||
DstGeoIP []string `json:"destinationGeoIP"` // can be nil if never queried, empty slice if got no result
|
||||
SrcIPASN string `json:"sourceIPASN"`
|
||||
DstIPASN string `json:"destinationIPASN"`
|
||||
SrcPort uint16 `json:"sourcePort,string"` // `,string` is used to compatible with old version json output
|
||||
DstPort uint16 `json:"destinationPort,string"` // `,string` is used to compatible with old version json output
|
||||
|
@ -27,8 +27,6 @@ const (
|
||||
ProcessNameRegex
|
||||
ProcessPathRegex
|
||||
RuleSet
|
||||
DomainSet
|
||||
IpCidrSet
|
||||
Network
|
||||
Uid
|
||||
SubRules
|
||||
@ -92,10 +90,6 @@ func (rt RuleType) String() string {
|
||||
return "Match"
|
||||
case RuleSet:
|
||||
return "RuleSet"
|
||||
case DomainSet:
|
||||
return "DomainSet"
|
||||
case IpCidrSet:
|
||||
return "IpCidrSet"
|
||||
case Network:
|
||||
return "Network"
|
||||
case DSCP:
|
||||
|
@ -21,13 +21,13 @@ func (p domainTriePolicy) Match(domain string) []dnsClient {
|
||||
return nil
|
||||
}
|
||||
|
||||
type domainRulePolicy struct {
|
||||
rule C.Rule
|
||||
type domainMatcherPolicy struct {
|
||||
matcher C.DomainMatcher
|
||||
dnsClients []dnsClient
|
||||
}
|
||||
|
||||
func (p domainRulePolicy) Match(domain string) []dnsClient {
|
||||
if ok, _ := p.rule.Match(&C.Metadata{Host: domain}); ok {
|
||||
func (p domainMatcherPolicy) Match(domain string) []dnsClient {
|
||||
if p.matcher.MatchDomain(domain) {
|
||||
return p.dnsClients
|
||||
}
|
||||
return nil
|
||||
|
@ -42,8 +42,8 @@ type Resolver struct {
|
||||
hosts *trie.DomainTrie[resolver.HostValue]
|
||||
main []dnsClient
|
||||
fallback []dnsClient
|
||||
fallbackDomainFilters []C.Rule
|
||||
fallbackIPFilters []C.Rule
|
||||
fallbackDomainFilters []C.DomainMatcher
|
||||
fallbackIPFilters []C.IpMatcher
|
||||
group singleflight.Group[*D.Msg]
|
||||
cache dnsCache
|
||||
policy []dnsPolicy
|
||||
@ -119,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 ok, _ := filter.Match(&C.Metadata{DstIP: ip}); ok {
|
||||
if filter.MatchIp(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -275,7 +275,7 @@ func (r *Resolver) shouldOnlyQueryFallback(m *D.Msg) bool {
|
||||
}
|
||||
|
||||
for _, df := range r.fallbackDomainFilters {
|
||||
if ok, _ := df.Match(&C.Metadata{Host: domain}); ok {
|
||||
if df.MatchDomain(domain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -398,7 +398,7 @@ func (ns NameServer) Equal(ns2 NameServer) bool {
|
||||
|
||||
type Policy struct {
|
||||
Domain string
|
||||
Rule C.Rule
|
||||
Matcher C.DomainMatcher
|
||||
NameServers []NameServer
|
||||
}
|
||||
|
||||
@ -409,8 +409,8 @@ type Config struct {
|
||||
IPv6 bool
|
||||
IPv6Timeout uint
|
||||
EnhancedMode C.DNSMode
|
||||
FallbackIPFilter []C.Rule
|
||||
FallbackDomainFilter []C.Rule
|
||||
FallbackIPFilter []C.IpMatcher
|
||||
FallbackDomainFilter []C.DomainMatcher
|
||||
Pool *fakeip.Pool
|
||||
Hosts *trie.DomainTrie[resolver.HostValue]
|
||||
Policy []Policy
|
||||
@ -495,8 +495,8 @@ func NewResolver(config Config) *Resolver {
|
||||
}
|
||||
|
||||
for _, policy := range config.Policy {
|
||||
if policy.Rule != nil {
|
||||
insertPolicy(domainRulePolicy{rule: policy.Rule, dnsClients: cacheTransform(policy.NameServers)})
|
||||
if policy.Matcher != nil {
|
||||
insertPolicy(domainMatcherPolicy{matcher: policy.Matcher, dnsClients: cacheTransform(policy.NameServers)})
|
||||
} else {
|
||||
if triePolicy == nil {
|
||||
triePolicy = trie.New[[]dnsClient]()
|
||||
|
@ -3,6 +3,7 @@ package common
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"strings"
|
||||
|
||||
"github.com/metacubex/mihomo/component/geodata"
|
||||
@ -11,6 +12,8 @@ import (
|
||||
"github.com/metacubex/mihomo/component/resolver"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
type GEOIP struct {
|
||||
@ -41,52 +44,84 @@ func (g *GEOIP) Match(metadata *C.Metadata) (bool, string) {
|
||||
}
|
||||
|
||||
if g.country == "lan" {
|
||||
return ip.IsPrivate() ||
|
||||
ip.IsUnspecified() ||
|
||||
ip.IsLoopback() ||
|
||||
ip.IsMulticast() ||
|
||||
ip.IsLinkLocalUnicast() ||
|
||||
resolver.IsFakeBroadcastIP(ip), g.adapter
|
||||
return g.isLan(ip), g.adapter
|
||||
}
|
||||
|
||||
for _, code := range metadata.DstGeoIP {
|
||||
if g.country == code {
|
||||
return true, g.adapter
|
||||
}
|
||||
}
|
||||
|
||||
if !C.GeodataMode {
|
||||
if C.GeodataMode {
|
||||
if g.isSourceIP {
|
||||
codes := mmdb.IPInstance().LookupCode(ip.AsSlice())
|
||||
for _, code := range codes {
|
||||
if g.country == code {
|
||||
return true, g.adapter
|
||||
}
|
||||
if slices.Contains(metadata.SrcGeoIP, g.country) {
|
||||
return true, g.adapter
|
||||
}
|
||||
return false, g.adapter
|
||||
}
|
||||
|
||||
if metadata.DstGeoIP != nil {
|
||||
return false, g.adapter
|
||||
}
|
||||
metadata.DstGeoIP = mmdb.IPInstance().LookupCode(ip.AsSlice())
|
||||
for _, code := range metadata.DstGeoIP {
|
||||
if g.country == code {
|
||||
} else {
|
||||
if slices.Contains(metadata.DstGeoIP, g.country) {
|
||||
return true, g.adapter
|
||||
}
|
||||
}
|
||||
return false, g.adapter
|
||||
matcher, err := g.getIPMatcher()
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
match := matcher.Match(ip)
|
||||
if match {
|
||||
if g.isSourceIP {
|
||||
metadata.SrcGeoIP = append(metadata.SrcGeoIP, g.country)
|
||||
} else {
|
||||
metadata.DstGeoIP = append(metadata.DstGeoIP, g.country)
|
||||
}
|
||||
}
|
||||
return match, g.adapter
|
||||
}
|
||||
|
||||
matcher, err := g.GetIPMatcher()
|
||||
if err != nil {
|
||||
return false, ""
|
||||
if g.isSourceIP {
|
||||
if metadata.SrcGeoIP != nil {
|
||||
return slices.Contains(metadata.SrcGeoIP, g.country), g.adapter
|
||||
}
|
||||
} else {
|
||||
if metadata.DstGeoIP != nil {
|
||||
return slices.Contains(metadata.DstGeoIP, g.country), g.adapter
|
||||
}
|
||||
}
|
||||
match := matcher.Match(ip)
|
||||
if match && !g.isSourceIP {
|
||||
metadata.DstGeoIP = append(metadata.DstGeoIP, g.country)
|
||||
codes := mmdb.IPInstance().LookupCode(ip.AsSlice())
|
||||
if g.isSourceIP {
|
||||
metadata.SrcGeoIP = codes
|
||||
} else {
|
||||
metadata.DstGeoIP = codes
|
||||
}
|
||||
return match, g.adapter
|
||||
if slices.Contains(codes, g.country) {
|
||||
return true, g.adapter
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// MatchIp implements C.IpMatcher
|
||||
func (g *GEOIP) MatchIp(ip netip.Addr) bool {
|
||||
if !ip.IsValid() {
|
||||
return false
|
||||
}
|
||||
|
||||
if g.country == "lan" {
|
||||
return g.isLan(ip)
|
||||
}
|
||||
|
||||
if C.GeodataMode {
|
||||
matcher, err := g.getIPMatcher()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return matcher.Match(ip)
|
||||
}
|
||||
|
||||
codes := mmdb.IPInstance().LookupCode(ip.AsSlice())
|
||||
return slices.Contains(codes, g.country)
|
||||
}
|
||||
|
||||
func (g *GEOIP) isLan(ip netip.Addr) bool {
|
||||
return ip.IsPrivate() ||
|
||||
ip.IsUnspecified() ||
|
||||
ip.IsLoopback() ||
|
||||
ip.IsMulticast() ||
|
||||
ip.IsLinkLocalUnicast() ||
|
||||
resolver.IsFakeBroadcastIP(ip)
|
||||
}
|
||||
|
||||
func (g *GEOIP) Adapter() string {
|
||||
@ -106,14 +141,19 @@ func (g *GEOIP) GetCountry() string {
|
||||
}
|
||||
|
||||
func (g *GEOIP) GetIPMatcher() (router.IPMatcher, error) {
|
||||
if g.geodata {
|
||||
geoIPMatcher, err := geodata.LoadGeoIPMatcher(g.country)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[GeoIP] %w", err)
|
||||
}
|
||||
return geoIPMatcher, nil
|
||||
if C.GeodataMode {
|
||||
return g.getIPMatcher()
|
||||
}
|
||||
return nil, errors.New("geoip country not set")
|
||||
return nil, errors.New("not geodata mode")
|
||||
}
|
||||
|
||||
func (g *GEOIP) getIPMatcher() (router.IPMatcher, error) {
|
||||
geoIPMatcher, err := geodata.LoadGeoIPMatcher(g.country)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[GeoIP] %w", err)
|
||||
}
|
||||
return geoIPMatcher, nil
|
||||
|
||||
}
|
||||
|
||||
func (g *GEOIP) GetRecodeSize() int {
|
||||
@ -141,12 +181,13 @@ func NewGEOIP(country string, adapter string, isSrc, noResolveIP bool) (*GEOIP,
|
||||
return geoip, nil
|
||||
}
|
||||
|
||||
geoip.geodata = true
|
||||
geoIPMatcher, err := geoip.GetIPMatcher() // test load
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if C.GeodataMode {
|
||||
geoIPMatcher, err := geoip.getIPMatcher() // test load
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Infoln("Finished initial GeoIP rule %s => %s, records: %d", country, adapter, geoIPMatcher.Count())
|
||||
}
|
||||
|
||||
log.Infoln("Finished initial GeoIP rule %s => %s, records: %d", country, adapter, geoIPMatcher.Count())
|
||||
return geoip, nil
|
||||
}
|
||||
|
@ -23,15 +23,19 @@ func (gs *GEOSITE) RuleType() C.RuleType {
|
||||
}
|
||||
|
||||
func (gs *GEOSITE) Match(metadata *C.Metadata) (bool, string) {
|
||||
domain := metadata.RuleHost()
|
||||
return gs.MatchDomain(metadata.RuleHost()), gs.adapter
|
||||
}
|
||||
|
||||
// MatchDomain implements C.DomainMatcher
|
||||
func (gs *GEOSITE) MatchDomain(domain string) bool {
|
||||
if len(domain) == 0 {
|
||||
return false, ""
|
||||
return false
|
||||
}
|
||||
matcher, err := gs.GetDomainMatcher()
|
||||
if err != nil {
|
||||
return false, ""
|
||||
return false
|
||||
}
|
||||
return matcher.ApplyDomain(domain), gs.adapter
|
||||
return matcher.ApplyDomain(domain)
|
||||
}
|
||||
|
||||
func (gs *GEOSITE) Adapter() string {
|
||||
|
@ -28,8 +28,11 @@ func (a *ASN) Match(metadata *C.Metadata) (bool, string) {
|
||||
|
||||
result := mmdb.ASNInstance().LookupASN(ip.AsSlice())
|
||||
asnNumber := strconv.FormatUint(uint64(result.AutonomousSystemNumber), 10)
|
||||
if !a.isSourceIP {
|
||||
metadata.DstIPASN = asnNumber + " " + result.AutonomousSystemOrganization
|
||||
ipASN := asnNumber + " " + result.AutonomousSystemOrganization
|
||||
if a.isSourceIP {
|
||||
metadata.SrcIPASN = ipASN
|
||||
} else {
|
||||
metadata.DstIPASN = ipASN
|
||||
}
|
||||
|
||||
match := a.asn == asnNumber
|
||||
|
@ -1,40 +0,0 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"github.com/metacubex/mihomo/component/trie"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
)
|
||||
|
||||
type DomainSet struct {
|
||||
*domainStrategy
|
||||
adapter string
|
||||
}
|
||||
|
||||
func (d *DomainSet) ProviderNames() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DomainSet) RuleType() C.RuleType {
|
||||
return C.DomainSet
|
||||
}
|
||||
|
||||
func (d *DomainSet) Match(metadata *C.Metadata) (bool, string) {
|
||||
return d.domainStrategy.Match(metadata), d.adapter
|
||||
}
|
||||
|
||||
func (d *DomainSet) Adapter() string {
|
||||
return d.adapter
|
||||
}
|
||||
|
||||
func (d *DomainSet) Payload() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func NewDomainSet(domainSet *trie.DomainSet, adapter string) *DomainSet {
|
||||
return &DomainSet{
|
||||
domainStrategy: &domainStrategy{domainSet: domainSet},
|
||||
adapter: adapter,
|
||||
}
|
||||
}
|
||||
|
||||
var _ C.Rule = (*DomainSet)(nil)
|
@ -1,40 +0,0 @@
|
||||
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)
|
@ -1,6 +1,8 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
P "github.com/metacubex/mihomo/constant/provider"
|
||||
"github.com/metacubex/mihomo/rules/common"
|
||||
@ -35,6 +37,18 @@ func (rs *RuleSet) Match(metadata *C.Metadata) (bool, string) {
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// MatchDomain implements C.DomainMatcher
|
||||
func (rs *RuleSet) MatchDomain(domain string) bool {
|
||||
ok, _ := rs.Match(&C.Metadata{Host: domain})
|
||||
return ok
|
||||
}
|
||||
|
||||
// MatchIp implements C.IpMatcher
|
||||
func (rs *RuleSet) MatchIp(ip netip.Addr) bool {
|
||||
ok, _ := rs.Match(&C.Metadata{DstIP: ip})
|
||||
return ok
|
||||
}
|
||||
|
||||
func (rs *RuleSet) Adapter() string {
|
||||
return rs.adapter
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user