From 45740be4afd11cc1764d9907daf1d995891c6a53 Mon Sep 17 00:00:00 2001 From: Loyalsoldier <10487845+Loyalsoldier@users.noreply.github.com> Date: Wed, 3 Mar 2021 16:53:42 +0800 Subject: [PATCH] Fix panic: index out of range (#727) --- app/dns/dns.go | 7 ++----- app/dns/nameserver.go | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/app/dns/dns.go b/app/dns/dns.go index 836f3490f..b5bc49704 100644 --- a/app/dns/dns.go +++ b/app/dns/dns.go @@ -66,9 +66,6 @@ func New(ctx context.Context, config *Config) (*DNS, error) { for _, ns := range config.NameServer { domainRuleCount += len(ns.PrioritizedDomain) } - // Fixes https://github.com/v2fly/v2ray-core/issues/529 - // Compatible with `localhost` nameserver specified in config file - domainRuleCount += len(localTLDsAndDotlessDomains) // MatcherInfos is ensured to cover the maximum index domainMatcher could return, where matcher's index starts from 1 matcherInfos := make([]DomainMatcherInfo, domainRuleCount+1) @@ -86,7 +83,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) { for _, ns := range config.NameServer { clientIdx := len(clients) - updateDomain := func(domainRule strmatcher.Matcher, originalRuleIdx int) error { + updateDomain := func(domainRule strmatcher.Matcher, originalRuleIdx int, matcherInfos []DomainMatcherInfo) error { midx := domainMatcher.Add(domainRule) matcherInfos[midx] = DomainMatcherInfo{ clientIdx: uint16(clientIdx), @@ -100,7 +97,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) { case net.IPv4len, net.IPv6len: myClientIP = net.IP(ns.ClientIp) } - client, err := NewClient(ctx, ns, myClientIP, geoipContainer, updateDomain) + client, err := NewClient(ctx, ns, myClientIP, geoipContainer, &matcherInfos, updateDomain) if err != nil { return nil, newError("failed to create client").Base(err) } diff --git a/app/dns/nameserver.go b/app/dns/nameserver.go index ed91f2fc0..f886c51d8 100644 --- a/app/dns/nameserver.go +++ b/app/dns/nameserver.go @@ -65,7 +65,7 @@ func NewServer(dest net.Destination, dispatcher routing.Dispatcher) (Server, err } // NewClient creates a DNS client managing a name server with client IP, domain rules and expected IPs. -func NewClient(ctx context.Context, ns *NameServer, clientIP net.IP, container router.GeoIPMatcherContainer, updateDomainRule func(strmatcher.Matcher, int) error) (*Client, error) { +func NewClient(ctx context.Context, ns *NameServer, clientIP net.IP, container router.GeoIPMatcherContainer, matcherInfos *[]DomainMatcherInfo, updateDomainRule func(strmatcher.Matcher, int, []DomainMatcherInfo) error) (*Client, error) { client := &Client{} err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error { // Create a new server for each client for now @@ -78,6 +78,19 @@ func NewClient(ctx context.Context, ns *NameServer, clientIP net.IP, container r if _, isLocalDNS := server.(*LocalNameServer); isLocalDNS { ns.PrioritizedDomain = append(ns.PrioritizedDomain, localTLDsAndDotlessDomains...) ns.OriginalRules = append(ns.OriginalRules, localTLDsAndDotlessDomainsRule) + // The following lines is a solution to avoid core panics(rule index out of range) when setting `localhost` DNS client in config. + // Because the `localhost` DNS client will apend len(localTLDsAndDotlessDomains) rules into matcherInfos to match `geosite:private` default rule. + // But `matcherInfos` has no enough length to add rules, which leads to core panics (rule index out of range). + // To avoid this, the length of `matcherInfos` must be equal to the expected, so manually append it with Golang default zero value first for later modification. + // Related issues: + // https://github.com/v2fly/v2ray-core/issues/529 + // https://github.com/v2fly/v2ray-core/issues/719 + for i := 0; i < len(localTLDsAndDotlessDomains); i++ { + *matcherInfos = append(*matcherInfos, DomainMatcherInfo{ + clientIdx: uint16(0), + domainRuleIdx: uint16(0), + }) + } } // Establish domain rules @@ -104,7 +117,7 @@ func NewClient(ctx context.Context, ns *NameServer, clientIP net.IP, container r rules = append(rules, domainRule.String()) ruleCurr++ } - err = updateDomainRule(domainRule, originalRuleIdx) + err = updateDomainRule(domainRule, originalRuleIdx, *matcherInfos) if err != nil { return newError("failed to create prioritized domain").Base(err).AtWarning() }