From f397a680a0776f3ecbe6ed613e94bc183d3f7234 Mon Sep 17 00:00:00 2001 From: "Aldo Adirajasa Fathoni (fathonix)" Date: Thu, 29 May 2025 21:33:36 +0800 Subject: [PATCH 1/5] Initial support for multiple default upstreams --- internal/config/router_config.go | 4 +- internal/server/handler.go | 65 +++++++++++++++++++------------- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/internal/config/router_config.go b/internal/config/router_config.go index 39119f0..b93188c 100644 --- a/internal/config/router_config.go +++ b/internal/config/router_config.go @@ -15,7 +15,7 @@ import ( ) // DefaultUpstream is a system wide default -const DefaultUpstream = "1.1.1.1" +var DefaultUpstream = []string{"1.1.1.1"} // ServerConfig ... type ServerConfig struct { @@ -37,7 +37,7 @@ type RouterConfig struct { Port int `json:"port"` Upstreams []UpstreamConfig `json:"upstreams"` InternalRecords []InternalRecordConfig `json:"internal"` - DefaultUpstream string `json:"default_upstream"` + DefaultUpstream []string `json:"default_upstream"` } // LogConfig is self explanatatory diff --git a/internal/server/handler.go b/internal/server/handler.go index 4dd6abc..bce4d67 100644 --- a/internal/server/handler.go +++ b/internal/server/handler.go @@ -77,31 +77,40 @@ func (h *DNSHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { msg.Answer = internalAnswer } else { // use upstream next - upstreamHost := getDNSServerFromLookup(h.RouterConf, domain) - logger.Debug("[%d] DNSLookup %s %s -> %s", h.ServerIndex, domain, getRecordTypeString(msg.Question[0].Qtype), upstreamHost) - - if upstreamHost == "nxdomain" { - // Return nxdomain asap - msg.SetRcode(r, dns.RcodeNameError) - } else { - // Forward to the determined upstream dns server - m := new(dns.Msg) - m.SetQuestion(dns.Fqdn(domain), msg.Question[0].Qtype) - m.RecursionDesired = true - - upstreamResponse, _, err := c.Exchange(m, net.JoinHostPort(upstreamHost, "53")) - if upstreamResponse == nil { - logger.Error("UpstreamError", err) - return - } + upstreamHosts := getDNSServerFromLookup(h.RouterConf, domain) + + for upstreamHostIndex, upstreamHost := range upstreamHosts { + logger.Debug("[%d] DNSLookup %s %s -> %s", h.ServerIndex, domain, getRecordTypeString(msg.Question[0].Qtype), upstreamHost) - if upstreamResponse.Rcode != dns.RcodeSuccess { - msg.SetRcode(r, upstreamResponse.Rcode) + if upstreamHost == "nxdomain" { + // Return nxdomain asap + msg.SetRcode(r, dns.RcodeNameError) + return } else { - msg.Answer = upstreamResponse.Answer - // Cache it - if memCache != nil { - memCache.Set(cacheKey, upstreamResponse.Answer, cache.DefaultExpiration) + // Forward to the determined upstream dns server + m := new(dns.Msg) + m.SetQuestion(dns.Fqdn(domain), msg.Question[0].Qtype) + m.RecursionDesired = true + + upstreamResponse, _, err := c.Exchange(m, net.JoinHostPort(upstreamHost, "53")) + if upstreamResponse == nil { + logger.Error("UpstreamError", err) + if len(upstreamHosts) - 1 > upstreamHostIndex { + logger.Debug("[%d] DNSLookupRetry %s -> %s", upstreamHost, upstreamHost[upstreamHostIndex + 1]) + continue + } else { + return + } + } + + if upstreamResponse.Rcode != dns.RcodeSuccess { + msg.SetRcode(r, upstreamResponse.Rcode) + } else { + msg.Answer = upstreamResponse.Answer + // Cache it + if memCache != nil { + memCache.Set(cacheKey, upstreamResponse.Answer, cache.DefaultExpiration) + } } } } @@ -113,20 +122,22 @@ func (h *DNSHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { } } -func getDNSServerFromLookup(conf config.RouterConfig, domain string) string { - dnsServer := conf.DefaultUpstream +func getDNSServerFromLookup(conf config.RouterConfig, domain string) []string { + var dnsServer []string if len(conf.Upstreams) > 0 { for _, upstream := range conf.Upstreams { if found := upstream.CompiledRegex.MatchString(domain); found { if upstream.NXDomain { - dnsServer = "nxdomain" + dnsServer = []string{"nxdomain"} } else { - dnsServer = upstream.DNSServer + dnsServer = []string{upstream.DNSServer} } break } } + } else { + dnsServer = conf.DefaultUpstream } return dnsServer From 00275506850902994249323b0a5b81c1b351eb65 Mon Sep 17 00:00:00 2001 From: "Aldo Adirajasa Fathoni (fathonix)" Date: Thu, 29 May 2025 21:38:17 +0800 Subject: [PATCH 2/5] Reflect multiple default upstreams support in configuration examples --- README.md | 5 ++++- config.json.example | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 121f7f9..9f851d9 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,10 @@ Given the following configuration: { "host": "127.0.0.1", "port": 53, - "default_upstream": "1.1.1.1", + "default_upstream": [ + "1.1.1.1", + "1.0.0.1" + ], "internal": [ { "regex": "mail.example.com", diff --git a/config.json.example b/config.json.example index 8c74396..91bca6c 100644 --- a/config.json.example +++ b/config.json.example @@ -7,7 +7,10 @@ { "host": "127.0.0.1", "port": 53, - "default_upstream": "1.1.1.1", + "default_upstream": [ + "1.1.1.1", + "1.0.0.1" + ], "internal": [ { "regex": "mail.example.com", From 816df247e9de70d32f6296e84b5ce14198a5661d Mon Sep 17 00:00:00 2001 From: "Aldo Adirajasa Fathoni (fathonix)" Date: Fri, 30 May 2025 16:19:00 +0800 Subject: [PATCH 3/5] Switch golangci-lint to v2 --- scripts/lint.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/lint.sh b/scripts/lint.sh index 0ddcf3b..27d599e 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -7,7 +7,7 @@ cd "$PROJECT_DIR" if ! command -v golangci-lint &>/dev/null; then echo -e "${YELLOW}Installing golangci-lint ...${RESET}" - go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest + go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest fi if ! command -v govulncheck &>/dev/null; then From 026adf5254587fe3d8f9b8f08625776551234efd Mon Sep 17 00:00:00 2001 From: "Aldo Adirajasa Fathoni (fathonix)" Date: Fri, 30 May 2025 16:28:16 +0800 Subject: [PATCH 4/5] Remove return from else clause --- internal/server/handler.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/internal/server/handler.go b/internal/server/handler.go index 4affa6d..f38d32c 100644 --- a/internal/server/handler.go +++ b/internal/server/handler.go @@ -86,7 +86,6 @@ func (h *DNSHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { if upstreamHost == "nxdomain" { // Return nxdomain asap msg.SetRcode(r, dns.RcodeNameError) - return } else { // Forward to the determined upstream dns server m := new(dns.Msg) @@ -96,12 +95,11 @@ func (h *DNSHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { upstreamResponse, _, err := c.Exchange(m, net.JoinHostPort(upstreamHost, "53")) if upstreamResponse == nil { logger.Error("UpstreamError", err) - if len(upstreamHosts) - 1 > upstreamHostIndex { - logger.Debug("[%d] DNSLookupRetry %s -> %s", upstreamHost, upstreamHost[upstreamHostIndex + 1]) + if (len(upstreamHosts) - 1) > upstreamHostIndex { + logger.Debug("[%d] DNSLookupRetry %s -> %s", upstreamHost, upstreamHost[upstreamHostIndex+1]) continue - } else { - return } + return } if upstreamResponse.Rcode != dns.RcodeSuccess { From 0edc26a72f1daeea226b6112ee9069c3ebb647ed Mon Sep 17 00:00:00 2001 From: "Aldo Adirajasa Fathoni (fathonix)" Date: Fri, 30 May 2025 17:02:28 +0800 Subject: [PATCH 5/5] Fix wrong variable to log --- internal/server/handler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/server/handler.go b/internal/server/handler.go index f38d32c..a7db552 100644 --- a/internal/server/handler.go +++ b/internal/server/handler.go @@ -96,7 +96,7 @@ func (h *DNSHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { if upstreamResponse == nil { logger.Error("UpstreamError", err) if (len(upstreamHosts) - 1) > upstreamHostIndex { - logger.Debug("[%d] DNSLookupRetry %s -> %s", upstreamHost, upstreamHost[upstreamHostIndex+1]) + logger.Debug("[%d] DNSLookupRetry %s -> %s", upstreamHost, upstreamHosts[upstreamHostIndex+1]) continue } return