From d84cc29392257e341f38f23b4164627d1306e593 Mon Sep 17 00:00:00 2001 From: bloved Date: Fri, 29 Oct 2021 15:34:49 +0200 Subject: [PATCH] ADDED: parallel queries to to multiple DNS servers new setting ZabovParallelQueries: max number of parallel queries --- 01.conf.go | 26 +++++++++- config.sample.json | 4 +- dns-upstream.txt | 2 - dns_client.go | 122 +++++++++++++++++++++++++++++++++------------ main.go | 19 +++---- 5 files changed, 128 insertions(+), 45 deletions(-) diff --git a/01.conf.go b/01.conf.go index 7411968..ec65fbb 100644 --- a/01.conf.go +++ b/01.conf.go @@ -124,7 +124,28 @@ func init() { } else { conf.ZabovCache = true } - conf.ZabovDNSArray = fileByLines(conf.ZabovUpDNS) + ZabovDNSArray := fileByLines(conf.ZabovUpDNS) + + conf.ZabovDNSArray = []string{} + + for _, value := range ZabovDNSArray { + tvalue := strings.TrimSpace(value) + if tvalue != "" && !strings.HasPrefix(tvalue, "#") { + conf.ZabovDNSArray = append(conf.ZabovDNSArray, tvalue) + } + } + + if confRaw["parallelqueries"] != nil { + conf.ZabovParallelQueries = int(confRaw["parallelqueries"].(float64)) + } + if conf.ZabovParallelQueries > len(conf.ZabovDNSArray) { + conf.ZabovParallelQueries = len(conf.ZabovDNSArray) + } + if conf.ZabovParallelQueries < 1 { + conf.ZabovParallelQueries = 1 + } + + fmt.Println("ZabovParallelQueries:", conf.ZabovParallelQueries) ZabovConfigs[name] = &conf } @@ -282,7 +303,8 @@ func init() { if localresponder["responder"] != nil { ZabovLocalResponder = localresponder["responder"].(string) if len(ZabovLocalResponder) > 0 { - local := ZabovConfig{ZabovDNSArray: []string{ZabovLocalResponder}, references: 1} + local := ZabovConfig{ZabovDNSArray: []string{ZabovLocalResponder}, + references: 1, ZabovParallelQueries: 1} ZabovConfigs[localresponderConfigName] = &local fmt.Println("ZabovLocalResponder:", ZabovLocalResponder) } diff --git a/config.sample.json b/config.sample.json index cd68e77..018ee88 100644 --- a/config.sample.json +++ b/config.sample.json @@ -36,7 +36,9 @@ "singlefilters":"./urls-domains-updated.txt", "doublefilters":"./urls-hosts-normal.txt", "blackholeip":"127.0.0.1", - "hostsfile":"./urls-local-normal.txt" + "hostsfile":"./urls-local-normal.txt", + "whitelist":"./urls-wl-normal.txt", + "parallelqueries":4 }, "children":{ "upstream":"./dns-familyscreen.txt", diff --git a/dns-upstream.txt b/dns-upstream.txt index 83a6424..162884b 100644 --- a/dns-upstream.txt +++ b/dns-upstream.txt @@ -225,7 +225,6 @@ 212.89.128.28:53 213.133.116.14:53 213.166.247.100:53 -217.243.173.82:53 217.5.182.118:53 217.7.80.40:53 217.7.81.136:53 @@ -362,7 +361,6 @@ 85.214.62.160:53 85.93.91.101:53 87.106.63.208:53 -87.118.126.225:53 88.198.37.146:53 88.99.66.18:53 89.163.150.209:53 diff --git a/dns_client.go b/dns_client.go index 861f503..6cd92fb 100644 --- a/dns_client.go +++ b/dns_client.go @@ -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 } diff --git a/main.go b/main.go index 618ba40..a4af035 100644 --- a/main.go +++ b/main.go @@ -35,15 +35,16 @@ type handler struct{} // ZabovConfig contains all Zabov configs type ZabovConfig struct { - ZabovSingleBL string // json:singlefilters -> ZabovSingleBL list of urls returning a file with just names of domains - ZabovDoubleBL string // json:doublefilters -> ZabovDoubleBL list of urls returning a file with IPdomain - ZabovAddBL net.IP // json:blackholeip -> ZabovAddBL is the IP we want to send all the clients to. Usually is 127.0.0.1 - ZabovHostsFile string // json:hostsfile -> ZabovHostsFile is the file we use to keep our hosts - ZabovWhiteList string // json:hostsfile -> ZabovWhiteList is the file we use to keep white listed hosts - ZabovUpDNS string // json:upstream -> ZabovUpDNS keeps the name of upstream DNSs - ZabovDNSArray []string // contains all the DNS we mention, parsed from ZabovUpDNS file - ZabovCache bool // allows to disable cache - references int // contains references to this config; if zero, config shall be removed + ZabovSingleBL string // json:singlefilters -> ZabovSingleBL list of urls returning a file with just names of domains + ZabovDoubleBL string // json:doublefilters -> ZabovDoubleBL list of urls returning a file with IPdomain + ZabovAddBL net.IP // json:blackholeip -> ZabovAddBL is the IP we want to send all the clients to. Usually is 127.0.0.1 + ZabovHostsFile string // json:hostsfile -> ZabovHostsFile is the file we use to keep our hosts + ZabovWhiteList string // json:hostsfile -> ZabovWhiteList is the file we use to keep white listed hosts + ZabovUpDNS string // json:upstream -> ZabovUpDNS keeps the name of upstream DNSs + ZabovDNSArray []string // contains all the DNS we mention, parsed from ZabovUpDNS file + ZabovCache bool // allows to disable cache + ZabovParallelQueries int // contains max number of parallel queries to multiple DNS servers + references int // contains references to this config; if zero, config shall be removed } // ZabovConfigs contains all Zabov configs