2020-10-08 15:14:07 -05:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2021-01-29 06:01:18 -06:00
|
|
|
"log"
|
2020-10-08 15:14:07 -05:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"math/rand"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/miekg/dns"
|
|
|
|
)
|
|
|
|
|
|
|
|
//ForwardQuery forwards the query to the upstream server
|
|
|
|
//first server to answer wins
|
2021-01-11 17:04:34 -06:00
|
|
|
//accepts config name to select the UP DNS source list
|
2021-01-13 16:38:33 -06:00
|
|
|
func ForwardQuery(query *dns.Msg, config string, nocache bool) *dns.Msg {
|
2021-01-29 06:01:18 -06:00
|
|
|
if ZabovDebug {
|
|
|
|
log.Println("ForwardQuery: nocache", nocache)
|
|
|
|
}
|
2020-10-08 15:14:07 -05:00
|
|
|
go incrementStats("ForwardQueries", 1)
|
|
|
|
|
|
|
|
r := new(dns.Msg)
|
|
|
|
r.SetReply(query)
|
|
|
|
r.Authoritative = true
|
|
|
|
|
|
|
|
fqdn := strings.TrimRight(query.Question[0].Name, ".")
|
|
|
|
|
|
|
|
lfqdn := fmt.Sprintf("%d", query.Question[0].Qtype) + "." + fqdn
|
2021-01-13 16:38:33 -06:00
|
|
|
if !nocache {
|
|
|
|
if cached := GetDomainFromCache(lfqdn); cached != nil {
|
|
|
|
go incrementStats("CacheHit", 1)
|
|
|
|
cached.SetReply(query)
|
|
|
|
cached.Authoritative = true
|
2021-01-29 06:01:18 -06:00
|
|
|
if ZabovDebug {
|
|
|
|
log.Println("ForwardQuery: CacheHit")
|
|
|
|
}
|
|
|
|
cached.Compress = true
|
2021-01-13 16:38:33 -06:00
|
|
|
return cached
|
|
|
|
|
|
|
|
}
|
2020-10-08 15:14:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
c := new(dns.Client)
|
|
|
|
|
|
|
|
c.ReadTimeout = 500 * time.Millisecond
|
|
|
|
c.WriteTimeout = 500 * time.Millisecond
|
|
|
|
|
|
|
|
for {
|
|
|
|
// round robin with retry
|
|
|
|
|
2021-01-24 03:51:01 -06:00
|
|
|
// local responder should always be available also if no internet connection
|
|
|
|
if !NetworkUp && localresponderConfigName != config {
|
2020-10-08 15:14:07 -05:00
|
|
|
time.Sleep(10 * time.Second)
|
|
|
|
go incrementStats("Network Problems ", 1)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2021-01-11 17:04:34 -06:00
|
|
|
d := oneTimeDNS(config)
|
2020-10-08 15:14:07 -05:00
|
|
|
|
|
|
|
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)
|
|
|
|
in.SetReply(query)
|
|
|
|
in.Authoritative = true
|
2021-01-29 06:01:18 -06:00
|
|
|
in.Compress = true
|
2020-10-08 15:14:07 -05:00
|
|
|
go DomainCache(lfqdn, in)
|
2021-01-29 06:01:18 -06:00
|
|
|
if ZabovDebug {
|
|
|
|
log.Println("ForwardQuery: OK!")
|
|
|
|
}
|
|
|
|
|
2020-10-08 15:14:07 -05:00
|
|
|
return in
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
|
|
|
|
fmt.Println("DNS client engine starting")
|
|
|
|
NetworkUp = checkNetworkUp()
|
|
|
|
|
|
|
|
if NetworkUp {
|
|
|
|
fmt.Println("[OK]: Network is UP")
|
|
|
|
} else {
|
|
|
|
fmt.Println("[KO] Network is DOWN: system will check again in 2 minutes")
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-01-11 17:04:34 -06:00
|
|
|
func oneTimeDNS(config string) (dns string) {
|
2020-10-08 15:14:07 -05:00
|
|
|
|
|
|
|
rand.Seed(time.Now().Unix())
|
|
|
|
|
2021-01-13 15:30:04 -06:00
|
|
|
upl := ZabovConfigs[config].ZabovDNSArray
|
2020-10-08 15:14:07 -05:00
|
|
|
|
|
|
|
if len(upl) < 1 {
|
2021-01-14 17:55:08 -06:00
|
|
|
|
|
|
|
if len(ZabovLocalResponder) > 0 {
|
|
|
|
fmt.Println("No DNS defined, fallback to local responder:", ZabovLocalResponder)
|
|
|
|
return ZabovLocalResponder
|
|
|
|
}
|
2020-10-08 15:14:07 -05:00
|
|
|
fmt.Println("No DNS defined, using default 127.0.0.53:53. Hope it works!")
|
|
|
|
return "127.0.0.53:53"
|
|
|
|
}
|
|
|
|
|
|
|
|
n := rand.Intn(128*len(upl)) % len(upl)
|
|
|
|
|
|
|
|
dns = upl[n]
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|