fix: potential panic caused by dns upstream ready callback

This commit is contained in:
mzz2017
2023-02-27 16:21:53 +08:00
parent 1737d3f7b2
commit 95a8c0ac42
2 changed files with 34 additions and 6 deletions

View File

@ -50,7 +50,8 @@ func New(log *logrus.Logger, dns *config.Dns, opt *NewOption) (s *Dns, err error
if tag == "" { if tag == "" {
return nil, fmt.Errorf("%w: '%v' has no tag", BadUpstreamFormatError, upstreamRaw) return nil, fmt.Errorf("%w: '%v' has no tag", BadUpstreamFormatError, upstreamRaw)
} }
u, err := url.Parse(link) var u *url.URL
u, err = url.Parse(link)
if err != nil { if err != nil {
return nil, fmt.Errorf("%w: %v", BadUpstreamFormatError, err) return nil, fmt.Errorf("%w: %v", BadUpstreamFormatError, err)
} }
@ -73,9 +74,6 @@ func New(log *logrus.Logger, dns *config.Dns, opt *NewOption) (s *Dns, err error
} }
upstreamName2Id[tag] = uint8(len(s.upstream)) upstreamName2Id[tag] = uint8(len(s.upstream))
s.upstream = append(s.upstream, r) s.upstream = append(s.upstream, r)
// Init immediately to avoid DNS leaking in the very beginning because param control_plane_dns_routing will
// be set in callback.
go r.GetUpstream()
} }
// Optimize routings. // Optimize routings.
if dns.Routing.Request.Rules, err = routing.ApplyRulesOptimizers(dns.Routing.Request.Rules, if dns.Routing.Request.Rules, err = routing.ApplyRulesOptimizers(dns.Routing.Request.Rules,
@ -119,6 +117,12 @@ func New(log *logrus.Logger, dns *config.Dns, opt *NewOption) (s *Dns, err error
return s, nil return s, nil
} }
func (s *Dns) InitUpstreams() {
for _, upstream := range s.upstream {
upstream.GetUpstream()
}
}
func (s *Dns) RequestSelect(msg *dnsmessage.Message) (upstream *Upstream, err error) { func (s *Dns) RequestSelect(msg *dnsmessage.Message) (upstream *Upstream, err error) {
if msg.Response { if msg.Response {
return nil, fmt.Errorf("DNS request expected but DNS response received") return nil, fmt.Errorf("DNS request expected but DNS response received")

View File

@ -51,6 +51,9 @@ type ControlPlane struct {
dialMode consts.DialMode dialMode consts.DialMode
routingMatcher *RoutingMatcher routingMatcher *RoutingMatcher
closed chan struct{}
ready chan struct{}
} }
func NewControlPlane( func NewControlPlane(
@ -302,7 +305,14 @@ func NewControlPlane(
outbounds: outbounds, outbounds: outbounds,
dialMode: dialMode, dialMode: dialMode,
routingMatcher: routingMatcher, routingMatcher: routingMatcher,
closed: make(chan struct{}),
ready: make(chan struct{}),
} }
defer func() {
if err != nil {
close(c.closed)
}
}()
/// DNS upstream. /// DNS upstream.
dnsUpstream, err := dns.New(log, dnsConfig, &dns.NewOption{ dnsUpstream, err := dns.New(log, dnsConfig, &dns.NewOption{
@ -313,7 +323,7 @@ func NewControlPlane(
} }
/// Dns controller. /// Dns controller.
c.dnsController, err = NewDnsController(dnsUpstream, &DnsControllerOption{ if c.dnsController, err = NewDnsController(dnsUpstream, &DnsControllerOption{
Log: log, Log: log,
CacheAccessCallback: func(cache *DnsCache) (err error) { CacheAccessCallback: func(cache *DnsCache) (err error) {
// Write mappings into eBPF map: // Write mappings into eBPF map:
@ -331,8 +341,14 @@ func NewControlPlane(
}, nil }, nil
}, },
BestDialerChooser: c.chooseBestDnsDialer, BestDialerChooser: c.chooseBestDnsDialer,
}) }); err != nil {
return nil, err
}
// Init immediately to avoid DNS leaking in the very beginning because param control_plane_dns_routing will
// be set in callback.
dnsUpstream.InitUpstreams()
close(c.ready)
return c, nil return c, nil
} }
@ -342,6 +358,13 @@ func (c *ControlPlane) EjectBpf() *bpfObjects {
} }
func (c *ControlPlane) dnsUpstreamReadyCallback(raw *url.URL, dnsUpstream *dns.Upstream) (err error) { func (c *ControlPlane) dnsUpstreamReadyCallback(raw *url.URL, dnsUpstream *dns.Upstream) (err error) {
// Waiting for ready.
select {
case <-c.closed:
return nil
case <-c.ready:
}
/// Notify dialers to check. /// Notify dialers to check.
c.onceNetworkReady.Do(func() { c.onceNetworkReady.Do(func() {
for _, out := range c.outbounds { for _, out := range c.outbounds {
@ -736,5 +759,6 @@ func (c *ControlPlane) Close() (err error) {
} }
} }
} }
close(c.closed)
return c.core.Close() return c.core.Close()
} }