|
|
|
@ -11,6 +11,75 @@ import ( |
|
|
|
|
"github.com/miekg/dns" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
func SingleResolve(query *dns.Msg, d string, lfqdn string, ch chan *dns.Msg) { |
|
|
|
|
c := new(dns.Client) |
|
|
|
|
|
|
|
|
|
c.ReadTimeout = 500 * time.Millisecond |
|
|
|
|
c.WriteTimeout = 500 * time.Millisecond |
|
|
|
|
|
|
|
|
|
in, _, err := c.Exchange(query, d) |
|
|
|
|
if err != nil { |
|
|
|
|
fmt.Printf("SingleResolve: Problem with DNS %s : %s\n", d, err.Error()) |
|
|
|
|
go incrementStats("DNS Problems "+d, 1) |
|
|
|
|
ch <- nil |
|
|
|
|
} else { |
|
|
|
|
go incrementStats(d, 1) |
|
|
|
|
Rcode := in.MsgHdr.Rcode |
|
|
|
|
in.SetReply(query) |
|
|
|
|
in.MsgHdr.Rcode = Rcode |
|
|
|
|
in.Authoritative = true |
|
|
|
|
in.Compress = true |
|
|
|
|
go DomainCache(lfqdn, in) |
|
|
|
|
if ZabovDebug { |
|
|
|
|
log.Println("SingleResolve: OK:", d, lfqdn) |
|
|
|
|
} |
|
|
|
|
ch <- in |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func ParallelResolve(query *dns.Msg, config string, lfqdn string) *dns.Msg { |
|
|
|
|
|
|
|
|
|
var resCur *dns.Msg |
|
|
|
|
var res *dns.Msg |
|
|
|
|
ch := make(chan *dns.Msg) |
|
|
|
|
|
|
|
|
|
dnss := oneTimeDNS(config, ZabovConfigs[config].ZabovParallelQueries) |
|
|
|
|
|
|
|
|
|
for _, d := range dnss { |
|
|
|
|
log.Println("ParallelResolve: running SingleResolve on:", d, lfqdn) |
|
|
|
|
go SingleResolve(query, d, lfqdn, ch) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ZabovDebug { |
|
|
|
|
log.Println("ParallelResolve: wait for results...") |
|
|
|
|
} |
|
|
|
|
for range dnss { |
|
|
|
|
resCur = <-ch |
|
|
|
|
if resCur != nil { |
|
|
|
|
|
|
|
|
|
if res == nil { |
|
|
|
|
if ZabovDebug { |
|
|
|
|
log.Println("ParallelResolve: got first result!") |
|
|
|
|
} |
|
|
|
|
res = resCur |
|
|
|
|
} else if resCur.Rcode == dns.RcodeSuccess { |
|
|
|
|
if ZabovDebug { |
|
|
|
|
log.Println("ParallelResolve: got next result, RcodeSuccess, replacing previous...") |
|
|
|
|
} |
|
|
|
|
res = resCur |
|
|
|
|
} else { |
|
|
|
|
if ZabovDebug { |
|
|
|
|
log.Println("ParallelResolve: got next result, discarding...") |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if res.Rcode == dns.RcodeSuccess { |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return res |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//ForwardQuery forwards the query to the upstream server
|
|
|
|
|
//first server to answer wins
|
|
|
|
|
//accepts config name to select the UP DNS source list
|
|
|
|
@ -39,15 +108,9 @@ func ForwardQuery(query *dns.Msg, config string, nocache bool) *dns.Msg { |
|
|
|
|
} |
|
|
|
|
cached.Compress = true |
|
|
|
|
return cached |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
c := new(dns.Client) |
|
|
|
|
|
|
|
|
|
c.ReadTimeout = 500 * time.Millisecond |
|
|
|
|
c.WriteTimeout = 500 * time.Millisecond |
|
|
|
|
|
|
|
|
|
for { |
|
|
|
|
// round robin with retry
|
|
|
|
|
|
|
|
|
@ -58,27 +121,10 @@ func ForwardQuery(query *dns.Msg, config string, nocache bool) *dns.Msg { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
d := oneTimeDNS(config) |
|
|
|
|
|
|
|
|
|
in, _, err := c.Exchange(query, d) |
|
|
|
|
if err != nil { |
|
|
|
|
fmt.Printf("Problem with DNS %s : %s\n", d, err.Error()) |
|
|
|
|
go incrementStats("DNS Problems "+d, 1) |
|
|
|
|
continue |
|
|
|
|
} else { |
|
|
|
|
go incrementStats(d, 1) |
|
|
|
|
Rcode := in.MsgHdr.Rcode |
|
|
|
|
in.SetReply(query) |
|
|
|
|
in.MsgHdr.Rcode = Rcode |
|
|
|
|
in.Authoritative = true |
|
|
|
|
in.Compress = true |
|
|
|
|
go DomainCache(lfqdn, in) |
|
|
|
|
if ZabovDebug { |
|
|
|
|
log.Println("ForwardQuery: OK!") |
|
|
|
|
} |
|
|
|
|
in := ParallelResolve(query, config, lfqdn) |
|
|
|
|
|
|
|
|
|
if in != nil { |
|
|
|
|
return in |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
@ -98,9 +144,12 @@ func init() { |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func oneTimeDNS(config string) (dns string) { |
|
|
|
|
func oneTimeDNS(config string, count int) (dns []string) { |
|
|
|
|
|
|
|
|
|
rand.Seed(time.Now().Unix()) |
|
|
|
|
if count == 0 { |
|
|
|
|
count = 1 |
|
|
|
|
} |
|
|
|
|
rand.Seed(time.Now().UnixNano()) |
|
|
|
|
|
|
|
|
|
upl := ZabovConfigs[config].ZabovDNSArray |
|
|
|
|
|
|
|
|
@ -108,16 +157,27 @@ func oneTimeDNS(config string) (dns string) { |
|
|
|
|
|
|
|
|
|
if len(ZabovLocalResponder) > 0 { |
|
|
|
|
fmt.Println("No DNS defined, fallback to local responder:", ZabovLocalResponder) |
|
|
|
|
return ZabovLocalResponder |
|
|
|
|
return []string{ZabovLocalResponder} |
|
|
|
|
} |
|
|
|
|
fmt.Println("No DNS defined, using default 127.0.0.53:53. Hope it works!") |
|
|
|
|
return "127.0.0.53:53" |
|
|
|
|
return []string{"127.0.0.53:53"} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
n := rand.Intn(128*len(upl)) % len(upl) |
|
|
|
|
|
|
|
|
|
dns = upl[n] |
|
|
|
|
res := []string{} |
|
|
|
|
for i := 0; i < count; i++ { |
|
|
|
|
res = append(res, upl[(n+i)%len(upl)]) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return |
|
|
|
|
check := make(map[string]int) |
|
|
|
|
for _, val := range res { |
|
|
|
|
check[val] = 1 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
res = []string{} |
|
|
|
|
for d, _ := range check { |
|
|
|
|
res = append(res, d) |
|
|
|
|
} |
|
|
|
|
return res |
|
|
|
|
} |
|
|
|
|