Pull request: 2704 local addresses vol.3
Merge in DNS/adguard-home from 2704-local-addresses-vol.3 to master Updates #2704. Updates #2829. Updates #2928. Squashed commit of the following: commit 8c42355c0093a3ac6951f79a5211e7891800f93a Author: Eugene Burkov <e.burkov@adguard.com> Date: Wed Apr 7 18:07:41 2021 +0300 dnsforward: rm errors pkg commit 7594a21a620239951039454dd5686a872e6f41a8 Merge: 830b0834908452f8Author: Eugene Burkov <e.burkov@adguard.com> Date: Wed Apr 7 18:00:03 2021 +0300 Merge branch 'master' into 2704-local-addresses-vol.3 commit 830b0834090510096061fed20b600195ab3773b8 Author: Eugene Burkov <e.burkov@adguard.com> Date: Wed Apr 7 17:47:51 2021 +0300 dnsforward: reduce local upstream timeout commit 493e81d9e8bacdc690f88af29a38d211b9733c7e Author: Ildar Kamalov <ik@adguard.com> Date: Tue Apr 6 19:11:00 2021 +0300 client: private_upstream test commit a0194ac28f15114578359b8c2460cd9af621e912 Author: Eugene Burkov <e.burkov@adguard.com> Date: Tue Apr 6 18:36:23 2021 +0300 all: expand api, fix conflicts commit 0f4e06836fed958391aa597c8b02453564980ca3 Merge: 89cf93ad8746005dAuthor: Eugene Burkov <e.burkov@adguard.com> Date: Tue Apr 6 18:35:04 2021 +0300 Merge branch 'master' into 2704-local-addresses-vol.3 commit 89cf93ad4f26c2bf4f1b18ecaa4d3a1e169f9b06 Author: Ildar Kamalov <ik@adguard.com> Date: Tue Apr 6 18:02:40 2021 +0300 client: add local ptr upstreams to upstream test commit e6dd869dddd4888474d625cbb005bad6390e4760 Author: Ildar Kamalov <ik@adguard.com> Date: Tue Apr 6 15:24:22 2021 +0300 client: add private DNS form commit b858057b9a957a416117f22b8bd0025f90e8c758 Author: Eugene Burkov <e.burkov@adguard.com> Date: Tue Apr 6 13:05:28 2021 +0300 aghstrings: mk cloning correct commit 8009ba60a6a7d6ceb7b6483a29f4e68d533af243 Author: Eugene Burkov <e.burkov@adguard.com> Date: Tue Apr 6 12:37:46 2021 +0300 aghstrings: fix lil bug commit 0dd19f2e7cc7c0de21517c37abd8336a907e1c0d Author: Eugene Burkov <e.burkov@adguard.com> Date: Mon Apr 5 20:45:01 2021 +0300 all: log changes commit eb5558d96fffa6e7bca7e14d3740d26e47382e23 Author: Eugene Burkov <e.burkov@adguard.com> Date: Mon Apr 5 20:18:53 2021 +0300 dnsforward: keep the style commit d6d5fcbde40a633129c0e04887b81cf0b1ce6875 Author: Eugene Burkov <e.burkov@adguard.com> Date: Mon Apr 5 20:02:52 2021 +0300 dnsforward: disable redundant filtering for local ptr commit 4f864c32027d10db9bcb4a264d2338df8c20afac Author: Eugene Burkov <e.burkov@adguard.com> Date: Mon Apr 5 17:53:17 2021 +0300 dnsforward: imp tests commit 7848e6f2341868f8ba0bb839956a0b7444cf02ca Author: Eugene Burkov <e.burkov@adguard.com> Date: Mon Apr 5 14:52:12 2021 +0300 all: imp code commit 19ac30653800eebf8aaee499f65560ae2d458a5a Author: Eugene Burkov <e.burkov@adguard.com> Date: Sun Apr 4 16:28:05 2021 +0300 all: mv more logic to aghstrings commit fac892ec5f0d2e30d6d64def0609267bbae4a202 Author: Eugene Burkov <e.burkov@adguard.com> Date: Fri Apr 2 20:23:23 2021 +0300 dnsforward: use filepath commit 05a3aeef1181b914788d14c7519287d467ab301f Author: Eugene Burkov <e.burkov@adguard.com> Date: Fri Apr 2 20:17:54 2021 +0300 aghstrings: introduce the pkg commit f24e1b63d6e1bf266a4ed063f46f86d7abf65663 Author: Eugene Burkov <e.burkov@adguard.com> Date: Fri Apr 2 20:01:23 2021 +0300 all: imp code commit 0217a0ebb341f99a90c9b68013bebf6ff73d08ae Author: Eugene Burkov <e.burkov@adguard.com> Date: Fri Apr 2 18:04:13 2021 +0300 openapi: log changes ... and 3 more commits
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/urlfilter"
|
||||
"github.com/AdguardTeam/urlfilter/filterlist"
|
||||
@@ -36,16 +37,15 @@ func (a *accessCtx) Init(allowedClients, disallowedClients, blockedHosts []strin
|
||||
return err
|
||||
}
|
||||
|
||||
buf := strings.Builder{}
|
||||
b := &strings.Builder{}
|
||||
for _, s := range blockedHosts {
|
||||
buf.WriteString(s)
|
||||
buf.WriteString("\n")
|
||||
aghstrings.WriteToBuilder(b, s, "\n")
|
||||
}
|
||||
|
||||
listArray := []filterlist.RuleList{}
|
||||
list := &filterlist.StringRuleList{
|
||||
ID: int(0),
|
||||
RulesText: buf.String(),
|
||||
RulesText: b.String(),
|
||||
IgnoreCosmetic: true,
|
||||
}
|
||||
listArray = append(listArray, list)
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
"net/http"
|
||||
"sort"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/util"
|
||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||
"github.com/AdguardTeam/dnsproxy/upstream"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
@@ -149,6 +149,13 @@ type ServerConfig struct {
|
||||
|
||||
// Register an HTTP handler
|
||||
HTTPRegister func(string, string, func(http.ResponseWriter, *http.Request))
|
||||
|
||||
// ResolveClients signals if the RDNS should resolve clients' addresses.
|
||||
ResolveClients bool
|
||||
|
||||
// LocalPTRResolvers is a slice of addresses to be used as upstreams for
|
||||
// resolving PTR queries for local addresses.
|
||||
LocalPTRResolvers []string
|
||||
}
|
||||
|
||||
// if any of ServerConfig values are zero, then default values from below are used
|
||||
@@ -274,7 +281,7 @@ func (s *Server) prepareUpstreamSettings() error {
|
||||
}
|
||||
d := string(data)
|
||||
for len(d) != 0 {
|
||||
s := util.SplitNext(&d, '\n')
|
||||
s := aghstrings.SplitNext(&d, '\n')
|
||||
upstreams = append(upstreams, s)
|
||||
}
|
||||
log.Debug("dns: using %d upstream servers from file %s", len(upstreams), s.conf.UpstreamDNSFileName)
|
||||
|
||||
@@ -293,6 +293,14 @@ func (s *Server) processRestrictLocal(ctx *dnsContext) (rc resultCode) {
|
||||
// Do not perform unreversing ever again.
|
||||
ctx.unreversedReqIP = ip
|
||||
|
||||
// Disable redundant filtering.
|
||||
filterSetts := s.getClientRequestFilteringSettings(ctx)
|
||||
filterSetts.ParentalEnabled = false
|
||||
filterSetts.SafeBrowsingEnabled = false
|
||||
filterSetts.SafeSearchEnabled = false
|
||||
filterSetts.ServicesRules = nil
|
||||
ctx.setts = filterSetts
|
||||
|
||||
// Nothing to restrict.
|
||||
return resultCodeSuccess
|
||||
}
|
||||
@@ -405,15 +413,19 @@ func processFilteringBeforeRequest(ctx *dnsContext) (rc resultCode) {
|
||||
var err error
|
||||
ctx.protectionEnabled = s.conf.ProtectionEnabled && s.dnsFilter != nil
|
||||
if ctx.protectionEnabled {
|
||||
ctx.setts = s.getClientRequestFilteringSettings(ctx)
|
||||
if ctx.setts == nil {
|
||||
ctx.setts = s.getClientRequestFilteringSettings(ctx)
|
||||
}
|
||||
ctx.result, err = s.filterDNSRequest(ctx)
|
||||
}
|
||||
s.RUnlock()
|
||||
|
||||
if err != nil {
|
||||
ctx.err = err
|
||||
|
||||
return resultCodeError
|
||||
}
|
||||
|
||||
return resultCodeSuccess
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,13 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/agherr"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/querylog"
|
||||
@@ -92,7 +95,6 @@ type DNSCreateParams struct {
|
||||
QueryLog querylog.QueryLog
|
||||
DHCPServer dhcpd.ServerInterface
|
||||
SubnetDetector *aghnet.SubnetDetector
|
||||
LocalResolvers aghnet.Exchanger
|
||||
AutohostTLD string
|
||||
}
|
||||
|
||||
@@ -127,7 +129,6 @@ func NewServer(p DNSCreateParams) (s *Server, err error) {
|
||||
stats: p.Stats,
|
||||
queryLog: p.QueryLog,
|
||||
subnetDetector: p.SubnetDetector,
|
||||
localResolvers: p.LocalResolvers,
|
||||
autohostSuffix: autohostSuffix,
|
||||
}
|
||||
|
||||
@@ -176,15 +177,23 @@ func (s *Server) WriteDiskConfig(c *FilteringConfig) {
|
||||
s.RLock()
|
||||
sc := s.conf.FilteringConfig
|
||||
*c = sc
|
||||
c.RatelimitWhitelist = stringArrayDup(sc.RatelimitWhitelist)
|
||||
c.BootstrapDNS = stringArrayDup(sc.BootstrapDNS)
|
||||
c.AllowedClients = stringArrayDup(sc.AllowedClients)
|
||||
c.DisallowedClients = stringArrayDup(sc.DisallowedClients)
|
||||
c.BlockedHosts = stringArrayDup(sc.BlockedHosts)
|
||||
c.UpstreamDNS = stringArrayDup(sc.UpstreamDNS)
|
||||
c.RatelimitWhitelist = aghstrings.CloneSlice(sc.RatelimitWhitelist)
|
||||
c.BootstrapDNS = aghstrings.CloneSlice(sc.BootstrapDNS)
|
||||
c.AllowedClients = aghstrings.CloneSlice(sc.AllowedClients)
|
||||
c.DisallowedClients = aghstrings.CloneSlice(sc.DisallowedClients)
|
||||
c.BlockedHosts = aghstrings.CloneSlice(sc.BlockedHosts)
|
||||
c.UpstreamDNS = aghstrings.CloneSlice(sc.UpstreamDNS)
|
||||
s.RUnlock()
|
||||
}
|
||||
|
||||
// RDNSSettings returns the copy of actual RDNS configuration.
|
||||
func (s *Server) RDNSSettings() (localPTRResolvers []string, resolveClients bool) {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
|
||||
return aghstrings.CloneSlice(s.conf.LocalPTRResolvers), s.conf.ResolveClients
|
||||
}
|
||||
|
||||
// Resolve - get IP addresses by host name from an upstream server.
|
||||
// No request/response filtering is performed.
|
||||
// Query log and Stats are not updated.
|
||||
@@ -195,24 +204,73 @@ func (s *Server) Resolve(host string) ([]net.IPAddr, error) {
|
||||
return s.internalProxy.LookupIPAddr(host)
|
||||
}
|
||||
|
||||
// Exchange - send DNS request to an upstream server and receive response
|
||||
// No request/response filtering is performed.
|
||||
// Query log and Stats are not updated.
|
||||
// This method may be called before Start().
|
||||
func (s *Server) Exchange(req *dns.Msg) (*dns.Msg, error) {
|
||||
// RDNSExchanger is a resolver for clients' addresses.
|
||||
type RDNSExchanger interface {
|
||||
// Exchange tries to resolve the ip in a suitable way, e.g. either as
|
||||
// local or as external.
|
||||
Exchange(ip net.IP) (host string, err error)
|
||||
}
|
||||
|
||||
const (
|
||||
// rDNSEmptyAnswerErr is returned by Exchange method when the answer
|
||||
// section of respond is empty.
|
||||
rDNSEmptyAnswerErr agherr.Error = "the answer section is empty"
|
||||
|
||||
// rDNSNotPTRErr is returned by Exchange method when the response is not
|
||||
// of PTR type.
|
||||
rDNSNotPTRErr agherr.Error = "the response is not a ptr"
|
||||
)
|
||||
|
||||
// Exchange implements the RDNSExchanger interface for *Server.
|
||||
func (s *Server) Exchange(ip net.IP) (host string, err error) {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
|
||||
ctx := &proxy.DNSContext{
|
||||
Proto: "udp",
|
||||
Req: req,
|
||||
StartTime: time.Now(),
|
||||
if !s.conf.ResolveClients {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
arpa := dns.Fqdn(aghnet.ReverseAddr(ip))
|
||||
req := &dns.Msg{
|
||||
MsgHdr: dns.MsgHdr{
|
||||
Id: dns.Id(),
|
||||
RecursionDesired: true,
|
||||
},
|
||||
Compress: true,
|
||||
Question: []dns.Question{{
|
||||
Name: arpa,
|
||||
Qtype: dns.TypePTR,
|
||||
Qclass: dns.ClassINET,
|
||||
}},
|
||||
}
|
||||
|
||||
var resp *dns.Msg
|
||||
if s.subnetDetector.IsLocallyServedNetwork(ip) {
|
||||
resp, err = s.localResolvers.Exchange(req)
|
||||
} else {
|
||||
ctx := &proxy.DNSContext{
|
||||
Proto: "udp",
|
||||
Req: req,
|
||||
StartTime: time.Now(),
|
||||
}
|
||||
err = s.internalProxy.Resolve(ctx)
|
||||
|
||||
resp = ctx.Res
|
||||
}
|
||||
err := s.internalProxy.Resolve(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
return ctx.Res, nil
|
||||
|
||||
if len(resp.Answer) == 0 {
|
||||
return "", fmt.Errorf("lookup for %q: %w", arpa, rDNSEmptyAnswerErr)
|
||||
}
|
||||
|
||||
ptr, ok := resp.Answer[0].(*dns.PTR)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("type checking: %w", rDNSNotPTRErr)
|
||||
}
|
||||
|
||||
return strings.TrimSuffix(ptr.Ptr, "."), nil
|
||||
}
|
||||
|
||||
// Start starts the DNS server.
|
||||
@@ -231,6 +289,110 @@ func (s *Server) startLocked() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// defaultLocalTimeout is the default timeout for resolving addresses from
|
||||
// locally-served networks. It is assumed that local resolvers should work much
|
||||
// faster than ordinary upstreams.
|
||||
const defaultLocalTimeout = 1 * time.Second
|
||||
|
||||
// collectDNSIPAddrs returns the slice of IP addresses without port number which
|
||||
// we are listening on. For internal use only.
|
||||
func (s *Server) collectDNSIPAddrs() (addrs []string, err error) {
|
||||
addrs = make([]string, len(s.conf.TCPListenAddrs)+len(s.conf.UDPListenAddrs))
|
||||
var i int
|
||||
var ip net.IP
|
||||
for _, addr := range s.conf.TCPListenAddrs {
|
||||
if addr == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if ip = addr.IP; ip.IsUnspecified() {
|
||||
return aghnet.CollectAllIfacesAddrs()
|
||||
}
|
||||
|
||||
addrs[i] = ip.String()
|
||||
i++
|
||||
}
|
||||
for _, addr := range s.conf.UDPListenAddrs {
|
||||
if addr == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if ip = addr.IP; ip.IsUnspecified() {
|
||||
return aghnet.CollectAllIfacesAddrs()
|
||||
}
|
||||
|
||||
addrs[i] = ip.String()
|
||||
i++
|
||||
}
|
||||
|
||||
return addrs[:i], nil
|
||||
}
|
||||
|
||||
// stringSetSubtract subtracts b from a interpreted as sets.
|
||||
func stringSetSubtract(a, b []string) (c []string) {
|
||||
// unit is an object to be used as value in set.
|
||||
type unit = struct{}
|
||||
|
||||
cSet := make(map[string]unit)
|
||||
for _, k := range a {
|
||||
cSet[k] = unit{}
|
||||
}
|
||||
|
||||
for _, k := range b {
|
||||
delete(cSet, k)
|
||||
}
|
||||
|
||||
c = make([]string, len(cSet))
|
||||
i := 0
|
||||
for k := range cSet {
|
||||
c[i] = k
|
||||
i++
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// setupResolvers initializes the resolvers for local addresses. For internal
|
||||
// use only.
|
||||
func (s *Server) setupResolvers(localAddrs []string) (err error) {
|
||||
bootstraps := s.conf.BootstrapDNS
|
||||
if len(localAddrs) == 0 {
|
||||
var sysRes aghnet.SystemResolvers
|
||||
// TODO(e.burkov): Enable the refresher after the actual
|
||||
// implementation passes the public testing.
|
||||
sysRes, err = aghnet.NewSystemResolvers(0, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
localAddrs = sysRes.Get()
|
||||
bootstraps = nil
|
||||
}
|
||||
log.Debug("upstreams to resolve PTR for local addresses: %v", localAddrs)
|
||||
|
||||
var ourAddrs []string
|
||||
ourAddrs, err = s.collectDNSIPAddrs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO(e.burkov): The approach of subtracting sets of strings
|
||||
// is not really applicable here since in case of listening on
|
||||
// all network interfaces we should check the whole interface's
|
||||
// network to cut off all the loopback addresses as well.
|
||||
localAddrs = stringSetSubtract(localAddrs, ourAddrs)
|
||||
|
||||
if s.localResolvers, err = aghnet.NewMultiAddrExchanger(
|
||||
localAddrs,
|
||||
bootstraps,
|
||||
defaultLocalTimeout,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Prepare the object
|
||||
func (s *Server) Prepare(config *ServerConfig) error {
|
||||
// Initialize the server configuration
|
||||
@@ -305,6 +467,12 @@ func (s *Server) Prepare(config *ServerConfig) error {
|
||||
// Create the main DNS proxy instance
|
||||
// --
|
||||
s.dnsProxy = &proxy.Proxy{Config: proxyConfig}
|
||||
|
||||
err = s.setupResolvers(s.conf.LocalPTRResolvers)
|
||||
if err != nil {
|
||||
return fmt.Errorf("setting up resolvers: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/agherr"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghtest"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
|
||||
@@ -73,7 +74,6 @@ func createTestServer(t *testing.T, filterConf *dnsfilter.Config, forwardConf Se
|
||||
s, err = NewServer(DNSCreateParams{
|
||||
DNSFilter: f,
|
||||
SubnetDetector: snd,
|
||||
LocalResolvers: &aghtest.Exchanger{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -82,6 +82,11 @@ func createTestServer(t *testing.T, filterConf *dnsfilter.Config, forwardConf Se
|
||||
err = s.Prepare(nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
s.localResolvers = &aghtest.Exchanger{}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -728,7 +733,6 @@ func TestBlockedCustomIP(t *testing.T) {
|
||||
s, err = NewServer(DNSCreateParams{
|
||||
DNSFilter: dnsfilter.New(&dnsfilter.Config{}, filters),
|
||||
SubnetDetector: snd,
|
||||
LocalResolvers: &aghtest.Exchanger{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -866,7 +870,6 @@ func TestRewrite(t *testing.T) {
|
||||
s, err = NewServer(DNSCreateParams{
|
||||
DNSFilter: f,
|
||||
SubnetDetector: snd,
|
||||
LocalResolvers: &aghtest.Exchanger{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -1029,7 +1032,6 @@ func TestPTRResponseFromDHCPLeases(t *testing.T) {
|
||||
DNSFilter: dnsfilter.New(&dnsfilter.Config{}, nil),
|
||||
DHCPServer: &testDHCP{},
|
||||
SubnetDetector: snd,
|
||||
LocalResolvers: &aghtest.Exchanger{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -1094,7 +1096,6 @@ func TestPTRResponseFromHosts(t *testing.T) {
|
||||
s, err = NewServer(DNSCreateParams{
|
||||
DNSFilter: dnsfilter.New(&c, nil),
|
||||
SubnetDetector: snd,
|
||||
LocalResolvers: &aghtest.Exchanger{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -1164,3 +1165,100 @@ func TestNewServer(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_Exchange(t *testing.T) {
|
||||
extUpstream := &aghtest.TestUpstream{
|
||||
Reverse: map[string][]string{
|
||||
"1.1.1.1.in-addr.arpa.": {"one.one.one.one"},
|
||||
},
|
||||
}
|
||||
locUpstream := &aghtest.TestUpstream{
|
||||
Reverse: map[string][]string{
|
||||
"1.1.168.192.in-addr.arpa.": {"local.domain"},
|
||||
"2.1.168.192.in-addr.arpa.": {},
|
||||
},
|
||||
}
|
||||
upstreamErr := agherr.Error("upstream error")
|
||||
errUpstream := &aghtest.TestErrUpstream{
|
||||
Err: upstreamErr,
|
||||
}
|
||||
nonPtrUpstream := &aghtest.TestBlockUpstream{
|
||||
Hostname: "some-host",
|
||||
Block: true,
|
||||
}
|
||||
|
||||
dns := NewCustomServer(&proxy.Proxy{
|
||||
Config: proxy.Config{
|
||||
UpstreamConfig: &proxy.UpstreamConfig{
|
||||
Upstreams: []upstream.Upstream{extUpstream},
|
||||
},
|
||||
},
|
||||
})
|
||||
dns.conf.ResolveClients = true
|
||||
|
||||
var err error
|
||||
dns.subnetDetector, err = aghnet.NewSubnetDetector()
|
||||
require.NoError(t, err)
|
||||
|
||||
localIP := net.IP{192, 168, 1, 1}
|
||||
testCases := []struct {
|
||||
name string
|
||||
want string
|
||||
wantErr error
|
||||
locUpstream upstream.Upstream
|
||||
req net.IP
|
||||
}{{
|
||||
name: "external_good",
|
||||
want: "one.one.one.one",
|
||||
wantErr: nil,
|
||||
locUpstream: nil,
|
||||
req: net.IP{1, 1, 1, 1},
|
||||
}, {
|
||||
name: "local_good",
|
||||
want: "local.domain",
|
||||
wantErr: nil,
|
||||
locUpstream: locUpstream,
|
||||
req: localIP,
|
||||
}, {
|
||||
name: "upstream_error",
|
||||
want: "",
|
||||
wantErr: upstreamErr,
|
||||
locUpstream: errUpstream,
|
||||
req: localIP,
|
||||
}, {
|
||||
name: "empty_answer_error",
|
||||
want: "",
|
||||
wantErr: rDNSEmptyAnswerErr,
|
||||
locUpstream: locUpstream,
|
||||
req: net.IP{192, 168, 1, 2},
|
||||
}, {
|
||||
name: "not_ptr_error",
|
||||
want: "",
|
||||
wantErr: rDNSNotPTRErr,
|
||||
locUpstream: nonPtrUpstream,
|
||||
req: localIP,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
dns.localResolvers = &aghtest.Exchanger{
|
||||
Ups: tc.locUpstream,
|
||||
}
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
host, eerr := dns.Exchange(tc.req)
|
||||
|
||||
require.ErrorIs(t, eerr, tc.wantErr)
|
||||
assert.Equal(t, tc.want, host)
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("resolving_disabled", func(t *testing.T) {
|
||||
dns.conf.ResolveClients = false
|
||||
for _, tc := range testCases {
|
||||
host, eerr := dns.Exchange(tc.req)
|
||||
|
||||
require.NoError(t, eerr)
|
||||
assert.Empty(t, host)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -42,15 +42,15 @@ func (s *Server) getClientRequestFilteringSettings(ctx *dnsContext) *dnsfilter.F
|
||||
return &setts
|
||||
}
|
||||
|
||||
// filterDNSRequest applies the dnsFilter and sets d.Res if the request
|
||||
// was filtered.
|
||||
// filterDNSRequest applies the dnsFilter and sets d.Res if the request was
|
||||
// filtered.
|
||||
func (s *Server) filterDNSRequest(ctx *dnsContext) (*dnsfilter.Result, error) {
|
||||
d := ctx.proxyCtx
|
||||
// TODO(e.burkov): Consistently use req instead of d.Req since it is
|
||||
// declared.
|
||||
req := d.Req
|
||||
host := strings.TrimSuffix(req.Question[0].Name, ".")
|
||||
res, err := s.dnsFilter.CheckHost(host, d.Req.Question[0].Qtype, ctx.setts)
|
||||
res, err := s.dnsFilter.CheckHost(host, req.Question[0].Qtype, ctx.setts)
|
||||
if err != nil {
|
||||
// Return immediately if there's an error
|
||||
return nil, fmt.Errorf("dnsfilter failed to check host %q: %w", host, err)
|
||||
@@ -63,8 +63,8 @@ func (s *Server) filterDNSRequest(ctx *dnsContext) (*dnsfilter.Result, error) {
|
||||
// Resolve the new canonical name, not the original host
|
||||
// name. The original question is readded in
|
||||
// processFilteringAfterResponse.
|
||||
ctx.origQuestion = d.Req.Question[0]
|
||||
d.Req.Question[0].Name = dns.Fqdn(res.CanonName)
|
||||
ctx.origQuestion = req.Question[0]
|
||||
req.Question[0].Name = dns.Fqdn(res.CanonName)
|
||||
} else if res.Reason == dnsfilter.RewrittenAutoHosts && len(res.ReverseHosts) != 0 {
|
||||
resp := s.makeResponse(req)
|
||||
for _, h := range res.ReverseHosts {
|
||||
@@ -84,7 +84,7 @@ func (s *Server) filterDNSRequest(ctx *dnsContext) (*dnsfilter.Result, error) {
|
||||
}
|
||||
|
||||
d.Res = resp
|
||||
} else if res.Reason == dnsfilter.Rewritten || res.Reason == dnsfilter.RewrittenAutoHosts {
|
||||
} else if res.Reason.In(dnsfilter.Rewritten, dnsfilter.RewrittenAutoHosts) {
|
||||
resp := s.makeResponse(req)
|
||||
|
||||
name := host
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/agherr"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
|
||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||
"github.com/AdguardTeam/dnsproxy/upstream"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
@@ -27,59 +28,67 @@ type dnsConfig struct {
|
||||
UpstreamsFile *string `json:"upstream_dns_file"`
|
||||
Bootstraps *[]string `json:"bootstrap_dns"`
|
||||
|
||||
ProtectionEnabled *bool `json:"protection_enabled"`
|
||||
RateLimit *uint32 `json:"ratelimit"`
|
||||
BlockingMode *string `json:"blocking_mode"`
|
||||
BlockingIPv4 net.IP `json:"blocking_ipv4"`
|
||||
BlockingIPv6 net.IP `json:"blocking_ipv6"`
|
||||
EDNSCSEnabled *bool `json:"edns_cs_enabled"`
|
||||
DNSSECEnabled *bool `json:"dnssec_enabled"`
|
||||
DisableIPv6 *bool `json:"disable_ipv6"`
|
||||
UpstreamMode *string `json:"upstream_mode"`
|
||||
CacheSize *uint32 `json:"cache_size"`
|
||||
CacheMinTTL *uint32 `json:"cache_ttl_min"`
|
||||
CacheMaxTTL *uint32 `json:"cache_ttl_max"`
|
||||
ProtectionEnabled *bool `json:"protection_enabled"`
|
||||
RateLimit *uint32 `json:"ratelimit"`
|
||||
BlockingMode *string `json:"blocking_mode"`
|
||||
BlockingIPv4 net.IP `json:"blocking_ipv4"`
|
||||
BlockingIPv6 net.IP `json:"blocking_ipv6"`
|
||||
EDNSCSEnabled *bool `json:"edns_cs_enabled"`
|
||||
DNSSECEnabled *bool `json:"dnssec_enabled"`
|
||||
DisableIPv6 *bool `json:"disable_ipv6"`
|
||||
UpstreamMode *string `json:"upstream_mode"`
|
||||
CacheSize *uint32 `json:"cache_size"`
|
||||
CacheMinTTL *uint32 `json:"cache_ttl_min"`
|
||||
CacheMaxTTL *uint32 `json:"cache_ttl_max"`
|
||||
ResolveClients *bool `json:"resolve_clients"`
|
||||
LocalPTRUpstreams *[]string `json:"local_ptr_upstreams"`
|
||||
}
|
||||
|
||||
func (s *Server) getDNSConfig() dnsConfig {
|
||||
s.RLock()
|
||||
upstreams := stringArrayDup(s.conf.UpstreamDNS)
|
||||
defer s.RUnlock()
|
||||
|
||||
upstreams := aghstrings.CloneSliceOrEmpty(s.conf.UpstreamDNS)
|
||||
upstreamFile := s.conf.UpstreamDNSFileName
|
||||
bootstraps := stringArrayDup(s.conf.BootstrapDNS)
|
||||
bootstraps := aghstrings.CloneSliceOrEmpty(s.conf.BootstrapDNS)
|
||||
protectionEnabled := s.conf.ProtectionEnabled
|
||||
blockingMode := s.conf.BlockingMode
|
||||
BlockingIPv4 := s.conf.BlockingIPv4
|
||||
BlockingIPv6 := s.conf.BlockingIPv6
|
||||
Ratelimit := s.conf.Ratelimit
|
||||
EnableEDNSClientSubnet := s.conf.EnableEDNSClientSubnet
|
||||
EnableDNSSEC := s.conf.EnableDNSSEC
|
||||
AAAADisabled := s.conf.AAAADisabled
|
||||
CacheSize := s.conf.CacheSize
|
||||
CacheMinTTL := s.conf.CacheMinTTL
|
||||
CacheMaxTTL := s.conf.CacheMaxTTL
|
||||
blockingIPv4 := s.conf.BlockingIPv4
|
||||
blockingIPv6 := s.conf.BlockingIPv6
|
||||
ratelimit := s.conf.Ratelimit
|
||||
enableEDNSClientSubnet := s.conf.EnableEDNSClientSubnet
|
||||
enableDNSSEC := s.conf.EnableDNSSEC
|
||||
aaaaDisabled := s.conf.AAAADisabled
|
||||
cacheSize := s.conf.CacheSize
|
||||
cacheMinTTL := s.conf.CacheMinTTL
|
||||
cacheMaxTTL := s.conf.CacheMaxTTL
|
||||
resolveClients := s.conf.ResolveClients
|
||||
localPTRUpstreams := aghstrings.CloneSliceOrEmpty(s.conf.LocalPTRResolvers)
|
||||
var upstreamMode string
|
||||
if s.conf.FastestAddr {
|
||||
upstreamMode = "fastest_addr"
|
||||
} else if s.conf.AllServers {
|
||||
upstreamMode = "parallel"
|
||||
}
|
||||
s.RUnlock()
|
||||
|
||||
return dnsConfig{
|
||||
Upstreams: &upstreams,
|
||||
UpstreamsFile: &upstreamFile,
|
||||
Bootstraps: &bootstraps,
|
||||
ProtectionEnabled: &protectionEnabled,
|
||||
BlockingMode: &blockingMode,
|
||||
BlockingIPv4: BlockingIPv4,
|
||||
BlockingIPv6: BlockingIPv6,
|
||||
RateLimit: &Ratelimit,
|
||||
EDNSCSEnabled: &EnableEDNSClientSubnet,
|
||||
DNSSECEnabled: &EnableDNSSEC,
|
||||
DisableIPv6: &AAAADisabled,
|
||||
CacheSize: &CacheSize,
|
||||
CacheMinTTL: &CacheMinTTL,
|
||||
CacheMaxTTL: &CacheMaxTTL,
|
||||
BlockingIPv4: blockingIPv4,
|
||||
BlockingIPv6: blockingIPv6,
|
||||
RateLimit: &ratelimit,
|
||||
EDNSCSEnabled: &enableEDNSClientSubnet,
|
||||
DNSSECEnabled: &enableDNSSEC,
|
||||
DisableIPv6: &aaaaDisabled,
|
||||
CacheSize: &cacheSize,
|
||||
CacheMinTTL: &cacheMinTTL,
|
||||
CacheMaxTTL: &cacheMaxTTL,
|
||||
UpstreamMode: &upstreamMode,
|
||||
ResolveClients: &resolveClients,
|
||||
LocalPTRUpstreams: &localPTRUpstreams,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,6 +236,11 @@ func (s *Server) setConfigRestartable(dc dnsConfig) (restart bool) {
|
||||
restart = true
|
||||
}
|
||||
|
||||
if dc.LocalPTRUpstreams != nil {
|
||||
s.conf.LocalPTRResolvers = *dc.LocalPTRUpstreams
|
||||
restart = true
|
||||
}
|
||||
|
||||
if dc.UpstreamsFile != nil {
|
||||
s.conf.UpstreamDNSFileName = *dc.UpstreamsFile
|
||||
restart = true
|
||||
@@ -294,15 +308,24 @@ func (s *Server) setConfig(dc dnsConfig) (restart bool) {
|
||||
s.conf.FastestAddr = *dc.UpstreamMode == "fastest_addr"
|
||||
}
|
||||
|
||||
if dc.ResolveClients != nil {
|
||||
s.conf.ResolveClients = *dc.ResolveClients
|
||||
}
|
||||
|
||||
return s.setConfigRestartable(dc)
|
||||
}
|
||||
|
||||
// upstreamJSON is a request body for handleTestUpstreamDNS endpoint.
|
||||
type upstreamJSON struct {
|
||||
Upstreams []string `json:"upstream_dns"` // Upstreams
|
||||
BootstrapDNS []string `json:"bootstrap_dns"` // Bootstrap DNS
|
||||
Upstreams []string `json:"upstream_dns"`
|
||||
BootstrapDNS []string `json:"bootstrap_dns"`
|
||||
PrivateUpstreams []string `json:"private_upstream"`
|
||||
}
|
||||
|
||||
// ValidateUpstreams validates each upstream and returns an error if any upstream is invalid or if there are no default upstreams specified
|
||||
// ValidateUpstreams validates each upstream and returns an error if any
|
||||
// upstream is invalid or if there are no default upstreams specified.
|
||||
//
|
||||
// TODO(e.burkov): Move into aghnet or even into dnsproxy.
|
||||
func ValidateUpstreams(upstreams []string) (err error) {
|
||||
// No need to validate comments
|
||||
upstreams = filterOutComments(upstreams)
|
||||
@@ -428,52 +451,76 @@ func checkPlainDNS(upstream string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) {
|
||||
req := upstreamJSON{}
|
||||
err := json.NewDecoder(r.Body).Decode(&req)
|
||||
if err != nil {
|
||||
httpError(r, w, http.StatusBadRequest, "Failed to read request body: %s", err)
|
||||
return
|
||||
// excFunc is a signature of function to check if upstream exchanges correctly.
|
||||
type excFunc func(u upstream.Upstream) (err error)
|
||||
|
||||
// checkDNSUpstreamExc checks if the DNS upstream exchanges correctly.
|
||||
func checkDNSUpstreamExc(u upstream.Upstream) (err error) {
|
||||
req := &dns.Msg{
|
||||
MsgHdr: dns.MsgHdr{
|
||||
Id: dns.Id(),
|
||||
RecursionDesired: true,
|
||||
},
|
||||
Question: []dns.Question{{
|
||||
Name: "google-public-dns-a.google.com.",
|
||||
Qtype: dns.TypeA,
|
||||
Qclass: dns.ClassINET,
|
||||
}},
|
||||
}
|
||||
|
||||
result := map[string]string{}
|
||||
var reply *dns.Msg
|
||||
reply, err = u.Exchange(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't communicate with upstream: %w", err)
|
||||
}
|
||||
|
||||
for _, host := range req.Upstreams {
|
||||
err = checkDNS(host, req.BootstrapDNS)
|
||||
if err != nil {
|
||||
log.Info("%v", err)
|
||||
result[host] = err.Error()
|
||||
} else {
|
||||
result[host] = "OK"
|
||||
if len(reply.Answer) != 1 {
|
||||
return fmt.Errorf("wrong response")
|
||||
}
|
||||
|
||||
if t, ok := reply.Answer[0].(*dns.A); ok {
|
||||
if !net.IPv4(8, 8, 8, 8).Equal(t.A) {
|
||||
return fmt.Errorf("wrong response")
|
||||
}
|
||||
}
|
||||
|
||||
jsonVal, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
httpError(r, w, http.StatusInternalServerError, "Unable to marshal status json: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, err = w.Write(jsonVal)
|
||||
if err != nil {
|
||||
httpError(r, w, http.StatusInternalServerError, "Couldn't write body: %s", err)
|
||||
return
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkDNS(input string, bootstrap []string) error {
|
||||
// checkPrivateUpstreamExc checks if the upstream for resolving private
|
||||
// addresses exchanges correctly.
|
||||
func checkPrivateUpstreamExc(u upstream.Upstream) (err error) {
|
||||
req := &dns.Msg{
|
||||
MsgHdr: dns.MsgHdr{
|
||||
Id: dns.Id(),
|
||||
RecursionDesired: true,
|
||||
},
|
||||
Question: []dns.Question{{
|
||||
Name: "1.0.0.127.in-addr.arpa.",
|
||||
Qtype: dns.TypePTR,
|
||||
Qclass: dns.ClassINET,
|
||||
}},
|
||||
}
|
||||
|
||||
if _, err = u.Exchange(req); err != nil {
|
||||
return fmt.Errorf("couldn't communicate with upstream: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkDNS(input string, bootstrap []string, ef excFunc) (err error) {
|
||||
if !isUpstream(input) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// separate upstream from domains list
|
||||
input, useDefault, err := separateUpstream(input)
|
||||
if err != nil {
|
||||
// Separate upstream from domains list.
|
||||
var useDefault bool
|
||||
if input, useDefault, err = separateUpstream(input); err != nil {
|
||||
return fmt.Errorf("wrong upstream format: %w", err)
|
||||
}
|
||||
|
||||
// No need to check this DNS server
|
||||
// No need to check this DNS server.
|
||||
if !useDefault {
|
||||
return nil
|
||||
}
|
||||
@@ -486,35 +533,80 @@ func checkDNS(input string, bootstrap []string) error {
|
||||
bootstrap = defaultBootstrap
|
||||
}
|
||||
|
||||
log.Debug("checking if dns %s works...", input)
|
||||
u, err := upstream.AddressToUpstream(input, upstream.Options{Bootstrap: bootstrap, Timeout: DefaultTimeout})
|
||||
log.Debug("checking if dns server %q works...", input)
|
||||
var u upstream.Upstream
|
||||
u, err = upstream.AddressToUpstream(input, upstream.Options{
|
||||
Bootstrap: bootstrap,
|
||||
Timeout: DefaultTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to choose upstream for %s: %w", input, err)
|
||||
return fmt.Errorf("failed to choose upstream for %q: %w", input, err)
|
||||
}
|
||||
|
||||
req := dns.Msg{}
|
||||
req.Id = dns.Id()
|
||||
req.RecursionDesired = true
|
||||
req.Question = []dns.Question{
|
||||
{Name: "google-public-dns-a.google.com.", Qtype: dns.TypeA, Qclass: dns.ClassINET},
|
||||
}
|
||||
reply, err := u.Exchange(&req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't communicate with dns server %s: %w", input, err)
|
||||
}
|
||||
if len(reply.Answer) != 1 {
|
||||
return fmt.Errorf("dns server %s returned wrong answer", input)
|
||||
}
|
||||
if t, ok := reply.Answer[0].(*dns.A); ok {
|
||||
if !net.IPv4(8, 8, 8, 8).Equal(t.A) {
|
||||
return fmt.Errorf("dns server %s returned wrong answer: %v", input, t.A)
|
||||
}
|
||||
if err = ef(u); err != nil {
|
||||
return fmt.Errorf("upstream %q fails to exchange: %w", input, err)
|
||||
}
|
||||
|
||||
log.Debug("dns %s works OK", input)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) {
|
||||
req := &upstreamJSON{}
|
||||
err := json.NewDecoder(r.Body).Decode(req)
|
||||
if err != nil {
|
||||
httpError(r, w, http.StatusBadRequest, "Failed to read request body: %s", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
result := map[string]string{}
|
||||
bootstraps := req.BootstrapDNS
|
||||
|
||||
for _, host := range req.Upstreams {
|
||||
err = checkDNS(host, bootstraps, checkDNSUpstreamExc)
|
||||
if err != nil {
|
||||
log.Info("%v", err)
|
||||
result[host] = err.Error()
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
result[host] = "OK"
|
||||
}
|
||||
|
||||
for _, host := range req.PrivateUpstreams {
|
||||
err = checkDNS(host, bootstraps, checkPrivateUpstreamExc)
|
||||
if err != nil {
|
||||
log.Info("%v", err)
|
||||
// TODO(e.burkov): If passed upstream have already
|
||||
// written an error above, we rewriting the error for
|
||||
// it. These cases should be handled properly instead.
|
||||
result[host] = err.Error()
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
result[host] = "OK"
|
||||
}
|
||||
|
||||
jsonVal, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
httpError(r, w, http.StatusInternalServerError, "Unable to marshal status json: %s", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, err = w.Write(jsonVal)
|
||||
if err != nil {
|
||||
httpError(r, w, http.StatusInternalServerError, "Couldn't write body: %s", err)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Control flow:
|
||||
// web
|
||||
// -> dnsforward.handleDOH -> dnsforward.ServeHTTP
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package dnsforward
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
|
||||
@@ -13,6 +16,22 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func loadTestData(t *testing.T, casesFileName string, cases interface{}) {
|
||||
t.Helper()
|
||||
|
||||
var f *os.File
|
||||
f, err := os.Open(filepath.Join("testdata", casesFileName))
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
require.NoError(t, f.Close())
|
||||
})
|
||||
|
||||
err = json.NewDecoder(f).Decode(cases)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
const jsonExt = ".json"
|
||||
|
||||
func TestDNSForwardHTTTP_handleGetConfig(t *testing.T) {
|
||||
filterConf := &dnsfilter.Config{
|
||||
SafeBrowsingEnabled: true,
|
||||
@@ -42,36 +61,38 @@ func TestDNSForwardHTTTP_handleGetConfig(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
conf func() ServerConfig
|
||||
want string
|
||||
name string
|
||||
}{{
|
||||
name: "all_right",
|
||||
conf: func() ServerConfig {
|
||||
return defaultConf
|
||||
},
|
||||
want: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
name: "all_right",
|
||||
}, {
|
||||
name: "fastest_addr",
|
||||
conf: func() ServerConfig {
|
||||
conf := defaultConf
|
||||
conf.FastestAddr = true
|
||||
|
||||
return conf
|
||||
},
|
||||
want: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"fastest_addr\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
name: "fastest_addr",
|
||||
}, {
|
||||
name: "parallel",
|
||||
conf: func() ServerConfig {
|
||||
conf := defaultConf
|
||||
conf.AllServers = true
|
||||
|
||||
return conf
|
||||
},
|
||||
want: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"parallel\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
name: "parallel",
|
||||
}}
|
||||
|
||||
var data map[string]json.RawMessage
|
||||
loadTestData(t, t.Name()+jsonExt, &data)
|
||||
|
||||
for _, tc := range testCases {
|
||||
caseWant, ok := data[tc.name]
|
||||
require.True(t, ok)
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Cleanup(w.Body.Reset)
|
||||
|
||||
@@ -79,7 +100,7 @@ func TestDNSForwardHTTTP_handleGetConfig(t *testing.T) {
|
||||
s.handleGetConfig(w, nil)
|
||||
|
||||
assert.Equal(t, "application/json", w.Header().Get("Content-Type"))
|
||||
assert.Equal(t, tc.want, w.Body.String())
|
||||
assert.JSONEq(t, string(caseWant), w.Body.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -108,97 +129,81 @@ func TestDNSForwardHTTTP_handleSetConfig(t *testing.T) {
|
||||
|
||||
err := s.Start()
|
||||
assert.Nil(t, err)
|
||||
defer func() {
|
||||
t.Cleanup(func() {
|
||||
assert.Nil(t, s.Stop())
|
||||
}()
|
||||
})
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
const defaultConfJSON = "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n"
|
||||
testCases := []struct {
|
||||
name string
|
||||
req string
|
||||
wantSet string
|
||||
wantGet string
|
||||
}{{
|
||||
name: "upstream_dns",
|
||||
req: "{\"upstream_dns\":[\"8.8.8.8:77\",\"8.8.4.4:77\"]}",
|
||||
wantSet: "",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:77\",\"8.8.4.4:77\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
}, {
|
||||
name: "bootstraps",
|
||||
req: "{\"bootstrap_dns\":[\"9.9.9.10\"]}",
|
||||
wantSet: "",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
}, {
|
||||
name: "blocking_mode_good",
|
||||
req: "{\"blocking_mode\":\"refused\"}",
|
||||
wantSet: "",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"refused\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
}, {
|
||||
name: "blocking_mode_bad",
|
||||
req: "{\"blocking_mode\":\"custom_ip\"}",
|
||||
wantSet: "blocking_mode: incorrect value\n",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
}, {
|
||||
name: "ratelimit",
|
||||
req: "{\"ratelimit\":6}",
|
||||
wantSet: "",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":6,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
}, {
|
||||
name: "edns_cs_enabled",
|
||||
req: "{\"edns_cs_enabled\":true}",
|
||||
wantSet: "",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":true,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
}, {
|
||||
name: "dnssec_enabled",
|
||||
req: "{\"dnssec_enabled\":true}",
|
||||
wantSet: "",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":true,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
}, {
|
||||
name: "cache_size",
|
||||
req: "{\"cache_size\":1024}",
|
||||
wantSet: "",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":1024,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
}, {
|
||||
name: "upstream_mode_parallel",
|
||||
req: "{\"upstream_mode\":\"parallel\"}",
|
||||
wantSet: "",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"parallel\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
}, {
|
||||
name: "upstream_mode_fastest_addr",
|
||||
req: "{\"upstream_mode\":\"fastest_addr\"}",
|
||||
wantSet: "",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"fastest_addr\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
}, {
|
||||
name: "upstream_dns_bad",
|
||||
req: "{\"upstream_dns\":[\"\"]}",
|
||||
wantSet: "wrong upstreams specification: missing port in address\n",
|
||||
wantGet: defaultConfJSON,
|
||||
}, {
|
||||
name: "bootstraps_bad",
|
||||
req: "{\"bootstrap_dns\":[\"a\"]}",
|
||||
wantSet: "a can not be used as bootstrap dns cause: invalid bootstrap server address: Resolver a is not eligible to be a bootstrap DNS server\n",
|
||||
wantGet: defaultConfJSON,
|
||||
}, {
|
||||
name: "cache_bad_ttl",
|
||||
req: "{\"cache_ttl_min\":1024,\"cache_ttl_max\":512}",
|
||||
wantSet: "cache_ttl_min must be less or equal than cache_ttl_max\n",
|
||||
wantGet: defaultConfJSON,
|
||||
}, {
|
||||
name: "upstream_mode_bad",
|
||||
req: "{\"upstream_mode\":\"somethingelse\"}",
|
||||
wantSet: "upstream_mode: incorrect value\n",
|
||||
wantGet: defaultConfJSON,
|
||||
}, {
|
||||
name: "local_ptr_upstreams_good",
|
||||
wantSet: "",
|
||||
}, {
|
||||
name: "local_ptr_upstreams_null",
|
||||
wantSet: "",
|
||||
}}
|
||||
|
||||
var data map[string]struct {
|
||||
Req json.RawMessage `json:"req"`
|
||||
Want json.RawMessage `json:"want"`
|
||||
}
|
||||
loadTestData(t, t.Name()+jsonExt, &data)
|
||||
|
||||
for _, tc := range testCases {
|
||||
caseData, ok := data[tc.name]
|
||||
require.True(t, ok)
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
s.conf = defaultConf
|
||||
})
|
||||
|
||||
rBody := ioutil.NopCloser(strings.NewReader(tc.req))
|
||||
rBody := ioutil.NopCloser(bytes.NewReader(caseData.Req))
|
||||
var r *http.Request
|
||||
r, err = http.NewRequest(http.MethodPost, "http://example.com", rBody)
|
||||
require.Nil(t, err)
|
||||
@@ -208,7 +213,7 @@ func TestDNSForwardHTTTP_handleSetConfig(t *testing.T) {
|
||||
w.Body.Reset()
|
||||
|
||||
s.handleGetConfig(w, nil)
|
||||
assert.Equal(t, tc.wantGet, w.Body.String())
|
||||
assert.JSONEq(t, string(caseData.Want), w.Body.String())
|
||||
w.Body.Reset()
|
||||
})
|
||||
}
|
||||
|
||||
83
internal/dnsforward/testdata/TestDNSForwardHTTTP_handleGetConfig.json
vendored
Normal file
83
internal/dnsforward/testdata/TestDNSForwardHTTTP_handleGetConfig.json
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"all_right": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 0,
|
||||
"blocking_mode": "",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"resolve_clients": false,
|
||||
"local_ptr_upstreams": []
|
||||
},
|
||||
"fastest_addr": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 0,
|
||||
"blocking_mode": "",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "fastest_addr",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"resolve_clients": false,
|
||||
"local_ptr_upstreams": []
|
||||
},
|
||||
"parallel": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 0,
|
||||
"blocking_mode": "",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "parallel",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"resolve_clients": false,
|
||||
"local_ptr_upstreams": []
|
||||
}
|
||||
}
|
||||
525
internal/dnsforward/testdata/TestDNSForwardHTTTP_handleSetConfig.json
vendored
Normal file
525
internal/dnsforward/testdata/TestDNSForwardHTTTP_handleSetConfig.json
vendored
Normal file
@@ -0,0 +1,525 @@
|
||||
{
|
||||
"upstream_dns": {
|
||||
"req": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:77",
|
||||
"8.8.4.4:77"
|
||||
]
|
||||
},
|
||||
"want": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:77",
|
||||
"8.8.4.4:77"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 0,
|
||||
"blocking_mode": "",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"resolve_clients": false,
|
||||
"local_ptr_upstreams": []
|
||||
}
|
||||
},
|
||||
"bootstraps": {
|
||||
"req": {
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10"
|
||||
]
|
||||
},
|
||||
"want": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 0,
|
||||
"blocking_mode": "",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"resolve_clients": false,
|
||||
"local_ptr_upstreams": []
|
||||
}
|
||||
},
|
||||
"blocking_mode_good": {
|
||||
"req": {
|
||||
"blocking_mode": "refused"
|
||||
},
|
||||
"want": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 0,
|
||||
"blocking_mode": "refused",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"resolve_clients": false,
|
||||
"local_ptr_upstreams": []
|
||||
}
|
||||
},
|
||||
"blocking_mode_bad": {
|
||||
"req": {
|
||||
"blocking_mode": "custom_ip"
|
||||
},
|
||||
"want": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 0,
|
||||
"blocking_mode": "",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"resolve_clients": false,
|
||||
"local_ptr_upstreams": []
|
||||
}
|
||||
},
|
||||
"ratelimit": {
|
||||
"req": {
|
||||
"ratelimit": 6
|
||||
},
|
||||
"want": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 6,
|
||||
"blocking_mode": "",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"resolve_clients": false,
|
||||
"local_ptr_upstreams": []
|
||||
}
|
||||
},
|
||||
"edns_cs_enabled": {
|
||||
"req": {
|
||||
"edns_cs_enabled": true
|
||||
},
|
||||
"want": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 0,
|
||||
"blocking_mode": "",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": true,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"resolve_clients": false,
|
||||
"local_ptr_upstreams": []
|
||||
}
|
||||
},
|
||||
"dnssec_enabled": {
|
||||
"req": {
|
||||
"dnssec_enabled": true
|
||||
},
|
||||
"want": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 0,
|
||||
"blocking_mode": "",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": true,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"resolve_clients": false,
|
||||
"local_ptr_upstreams": []
|
||||
}
|
||||
},
|
||||
"cache_size": {
|
||||
"req": {
|
||||
"cache_size": 1024
|
||||
},
|
||||
"want": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 0,
|
||||
"blocking_mode": "",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "",
|
||||
"cache_size": 1024,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"resolve_clients": false,
|
||||
"local_ptr_upstreams": []
|
||||
}
|
||||
},
|
||||
"upstream_mode_parallel": {
|
||||
"req": {
|
||||
"upstream_mode": "parallel"
|
||||
},
|
||||
"want": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 0,
|
||||
"blocking_mode": "",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "parallel",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"resolve_clients": false,
|
||||
"local_ptr_upstreams": []
|
||||
}
|
||||
},
|
||||
"upstream_mode_fastest_addr": {
|
||||
"req": {
|
||||
"upstream_mode": "fastest_addr"
|
||||
},
|
||||
"want": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 0,
|
||||
"blocking_mode": "",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "fastest_addr",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"resolve_clients": false,
|
||||
"local_ptr_upstreams": []
|
||||
}
|
||||
},
|
||||
"upstream_dns_bad": {
|
||||
"req": {
|
||||
"upstream_dns": [
|
||||
""
|
||||
]
|
||||
},
|
||||
"want": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 0,
|
||||
"blocking_mode": "",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"resolve_clients": false,
|
||||
"local_ptr_upstreams": []
|
||||
}
|
||||
},
|
||||
"bootstraps_bad": {
|
||||
"req": {
|
||||
"bootstrap_dns": [
|
||||
"a"
|
||||
]
|
||||
},
|
||||
"want": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 0,
|
||||
"blocking_mode": "",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"resolve_clients": false,
|
||||
"local_ptr_upstreams": []
|
||||
}
|
||||
},
|
||||
"cache_bad_ttl": {
|
||||
"req": {
|
||||
"cache_ttl_min": 1024,
|
||||
"cache_ttl_max": 512
|
||||
},
|
||||
"want": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 0,
|
||||
"blocking_mode": "",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"resolve_clients": false,
|
||||
"local_ptr_upstreams": []
|
||||
}
|
||||
},
|
||||
"upstream_mode_bad": {
|
||||
"req": {
|
||||
"upstream_mode": "somethingelse"
|
||||
},
|
||||
"want": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 0,
|
||||
"blocking_mode": "",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"resolve_clients": false,
|
||||
"local_ptr_upstreams": []
|
||||
}
|
||||
},
|
||||
"local_ptr_upstreams_good": {
|
||||
"req": {
|
||||
"local_ptr_upstreams": [
|
||||
"123.123.123.123"
|
||||
]
|
||||
},
|
||||
"want": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 0,
|
||||
"blocking_mode": "",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"resolve_clients": false,
|
||||
"local_ptr_upstreams": [
|
||||
"123.123.123.123"
|
||||
]
|
||||
}
|
||||
},
|
||||
"local_ptr_upstreams_null": {
|
||||
"req": {
|
||||
"local_ptr_upstreams": null
|
||||
},
|
||||
"want": {
|
||||
"upstream_dns": [
|
||||
"8.8.8.8:53",
|
||||
"8.8.4.4:53"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 0,
|
||||
"blocking_mode": "",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "",
|
||||
"cache_size": 0,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0,
|
||||
"resolve_clients": false,
|
||||
"local_ptr_upstreams": []
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,12 +30,6 @@ func IPStringFromAddr(addr net.Addr) (ipStr string) {
|
||||
return ""
|
||||
}
|
||||
|
||||
func stringArrayDup(a []string) []string {
|
||||
a2 := make([]string, len(a))
|
||||
copy(a2, a)
|
||||
return a2
|
||||
}
|
||||
|
||||
// Find value in a sorted array
|
||||
func findSorted(ar []string, val string) int {
|
||||
i := sort.SearchStrings(ar, val)
|
||||
|
||||
Reference in New Issue
Block a user