1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-12-21 17:46:58 -05:00

feat/fix: dns query subscriptions group by A and AAAA. fix problem that empty result would poll dns server in DoH mode

This commit is contained in:
mzz2017 2020-02-04 20:57:58 +08:00 committed by kslr
parent 4a663f2b25
commit 7f4f8091f9
2 changed files with 71 additions and 13 deletions

View File

@ -12,6 +12,7 @@ import (
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
dns_feature "v2ray.com/core/features/dns"
"golang.org/x/net/dns/dnsmessage" "golang.org/x/net/dns/dnsmessage"
"v2ray.com/core/common" "v2ray.com/core/common"
@ -213,9 +214,13 @@ func (s *DoHNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
if updated { if updated {
s.ips[req.domain] = rec s.ips[req.domain] = rec
s.pub.Publish(req.domain, nil)
} }
switch req.reqType {
case dnsmessage.TypeA:
s.pub.Publish(req.domain+"4", nil)
case dnsmessage.TypeAAAA:
s.pub.Publish(req.domain+"6", nil)
}
s.Unlock() s.Unlock()
common.Must(s.cleanup.Start()) common.Must(s.cleanup.Start())
} }
@ -336,12 +341,15 @@ func (s *DoHNameServer) findIPsForDomain(domain string, option IPOption) ([]net.
return nil, lastErr return nil, lastErr
} }
if (option.IPv4Enable && record.A != nil) || (option.IPv6Enable && record.AAAA != nil) {
return nil, dns_feature.ErrEmptyResponse
}
return nil, errRecordNotFound return nil, errRecordNotFound
} }
// QueryIP is called from dns.Server->queryIPTimeout // QueryIP is called from dns.Server->queryIPTimeout
func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, option IPOption) ([]net.IP, error) { func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, option IPOption) ([]net.IP, error) {
fqdn := Fqdn(domain) fqdn := Fqdn(domain)
ips, err := s.findIPsForDomain(fqdn, option) ips, err := s.findIPsForDomain(fqdn, option)
@ -350,9 +358,32 @@ func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, option IPOpt
return ips, err return ips, err
} }
sub := s.pub.Subscribe(fqdn) // ipv4 and ipv6 belong to different subscription groups
defer sub.Close() var sub4, sub6 *pubsub.Subscriber
if option.IPv4Enable {
sub4 = s.pub.Subscribe(fqdn + "4")
defer sub4.Close()
}
if option.IPv6Enable {
sub6 = s.pub.Subscribe(fqdn + "6")
defer sub6.Close()
}
done := make(chan interface{})
go func() {
if sub4 != nil {
select {
case <-sub4.Wait():
case <-ctx.Done():
}
}
if sub6 != nil {
select {
case <-sub6.Wait():
case <-ctx.Done():
}
}
close(done)
}()
s.sendQuery(ctx, fqdn, option) s.sendQuery(ctx, fqdn, option)
for { for {
@ -364,7 +395,7 @@ func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, option IPOpt
select { select {
case <-ctx.Done(): case <-ctx.Done():
return nil, ctx.Err() return nil, ctx.Err()
case <-sub.Wait(): case <-done:
} }
} }
} }

View File

@ -158,9 +158,13 @@ func (s *ClassicNameServer) updateIP(domain string, newRec record) {
if updated { if updated {
s.ips[domain] = rec s.ips[domain] = rec
s.pub.Publish(domain, nil)
} }
if newRec.A != nil {
s.pub.Publish(domain+"4", nil)
}
if newRec.AAAA != nil {
s.pub.Publish(domain+"6", nil)
}
s.Unlock() s.Unlock()
common.Must(s.cleanup.Start()) common.Must(s.cleanup.Start())
} }
@ -245,9 +249,32 @@ func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, option I
return ips, err return ips, err
} }
sub := s.pub.Subscribe(fqdn) // ipv4 and ipv6 belong to different subscription groups
defer sub.Close() var sub4, sub6 *pubsub.Subscriber
if option.IPv4Enable {
sub4 = s.pub.Subscribe(fqdn + "4")
defer sub4.Close()
}
if option.IPv6Enable {
sub6 = s.pub.Subscribe(fqdn + "6")
defer sub6.Close()
}
done := make(chan interface{})
go func() {
if sub4 != nil {
select {
case <-sub4.Wait():
case <-ctx.Done():
}
}
if sub6 != nil {
select {
case <-sub6.Wait():
case <-ctx.Done():
}
}
close(done)
}()
s.sendQuery(ctx, fqdn, option) s.sendQuery(ctx, fqdn, option)
for { for {
@ -259,7 +286,7 @@ func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, option I
select { select {
case <-ctx.Done(): case <-ctx.Done():
return nil, ctx.Err() return nil, ctx.Err()
case <-sub.Wait(): case <-done:
} }
} }
} }