diff --git a/README.md b/README.md index f3e2d046..b95abcc1 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ example.com. 0 CH HINFO "Host" "IPv6:[2001:500:8f::53]:53 rtt:147ms health:[GOO example.com. 0 CH HINFO "Host" "IPv6:[2001:500:8d::53]:53 rtt:148ms health:[GOOD]" ``` -## Configuration (v1.3.3) +## Configuration (v1.3.6) | Key | Description | | -------------------- | ------------------------------------------------------------------------------------------------------------------- | @@ -143,12 +143,13 @@ example.com. 0 CH HINFO "Host" "IPv6:[2001:500:8d::53]:53 rtt:148ms health:[GOO | **outboundip6s** | Outbound IPv6 addresses (randomly chosen if multiple entries provided) | | **rootservers** | DNS Root IPv4 servers | | **root6servers** | DNS Root IPv6 servers | +| **dnssec** | DNSSEC validation on signed zones, off for disabled. | | **rootkeys** | Trusted DNSSEC anchors | | **fallbackservers** | Failover resolver IPv4 or IPv6 addresses with port (leave blank to disable) Example: "8.8.8.8:53" | | **forwarderservers** | Forwarder resolver IPv4 or IPv6 addresses with port (leave blank to disable) Example: "8.8.8.8:53" | | **api** | HTTP API server binding address (leave blank to disable) | | **blocklists** | Remote blocklist address list (downloaded to the blocklist folder) | -| **blocklistdir** | \[DEPRECATED] Directory creation is automated in the working directory | +| **blocklistdir** | \[DEPRECATED] Directory creation is automated in the working directory | | **loglevel** | Log verbosity level (crit, error, warn, info, debug) | | **accesslog** | Location of the access log file (leave blank to disable) Default: Common Log Format | | **nullroute** | IPv4 address for forwarding blocked queries | @@ -168,7 +169,7 @@ example.com. 0 CH HINFO "Host" "IPv6:[2001:500:8d::53]:53 rtt:148ms health:[GOO | **cookiesecret** | DNS cookie secret (RFC 7873) - auto-generated if not set | | **nsid** | DNS server identifier (RFC 5001) - useful for operating multiple sdns instances (leave blank to disable) | | **chaos** | Enable responses to version.server, version.bind, hostname.bind and id.server chaos txt queries | -| **qname\_min\_level** | Qname minimize level (0 to disable - higher values increase complexity and impact response performance) | +| **qname\_min\_level** | Qname minimize level (0 to disable - higher values increase complexity and impact response performance) | | **emptyzones** | Enable response to RFC 1918 zone queries. For details, see http://as112.net/ | ## Plugin Configuration diff --git a/config/config.go b/config/config.go index 44e2cfd6..18ca7228 100644 --- a/config/config.go +++ b/config/config.go @@ -17,7 +17,7 @@ import ( "github.com/semihalev/log" ) -const configver = "1.3.3" +const configver = "1.3.6" // Config type type Config struct { @@ -27,6 +27,7 @@ type Config struct { BlockListDir string RootServers []string Root6Servers []string + DNSSEC string RootKeys []string FallbackServers []string ForwarderServers []string @@ -158,7 +159,10 @@ root6servers = [ "[2001:dc3::35]:53" ] -# Trusted anchors for DNSSEC +# DNSSEC validation on signed zones, off for disabled. +dnssec = "on" + +# Trusted anchors for DNSSEC. rootkeys = [ ". 172800 IN DNSKEY 257 3 8 AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTOiW1vkIbzxeF3+/4RgWOq7HrxRixHlFlExOLAJr5emLvN7SWXgnLh4+B5xQlNVz8Og8kvArMtNROxVQuCaSnIDdD5LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF0jLHwVN8efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7pr+eoZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLYA4/ilBmSVIzuDWfdRUfhHdY6+cn8HFRm+2hM8AnXGXws9555KrUB5qihylGa8subX2Nn6UwNR1AkUTV74bU=" ] @@ -325,6 +329,10 @@ func Load(cfgfile, version string) (*Config, error) { config.sVersion = version + if config.DNSSEC == "" || config.DNSSEC != "off" { + config.DNSSEC = "on" + } + if config.CookieSecret == "" { var v uint64 diff --git a/middleware/edns/edns.go b/middleware/edns/edns.go index 55a5c7e3..db235a5e 100644 --- a/middleware/edns/edns.go +++ b/middleware/edns/edns.go @@ -65,6 +65,10 @@ func (e *EDNS) ServeDNS(ctx context.Context, ch *middleware.Chain) { size = dns.MaxMsgSize } + if noedns { + size = dns.MinMsgSize + } + ch.Writer = &ResponseWriter{ ResponseWriter: w, EDNS: e, diff --git a/middleware/failover/failover.go b/middleware/failover/failover.go index 0d7c8ed3..4f531d08 100644 --- a/middleware/failover/failover.go +++ b/middleware/failover/failover.go @@ -80,7 +80,7 @@ func (w *ResponseWriter) WriteMsg(m *dns.Msg) error { defer cancel() resp, err := dnsutil.Exchange(ctx, req, server, "udp") if err != nil { - log.Warn("Failover query failed", "query", formatQuestion(req.Question[0]), "error", err.Error()) + log.Info("Failover query failed", "query", formatQuestion(req.Question[0]), "error", err.Error()) continue } diff --git a/middleware/forwarder/forwarder.go b/middleware/forwarder/forwarder.go index dc3b0398..6b289af3 100644 --- a/middleware/forwarder/forwarder.go +++ b/middleware/forwarder/forwarder.go @@ -20,6 +20,7 @@ type server struct { // Forwarder type type Forwarder struct { servers []*server + dnssec bool } // New return forwarder @@ -46,7 +47,7 @@ func New(cfg *config.Config) *Forwarder { } } - return &Forwarder{servers: forwarderservers} + return &Forwarder{servers: forwarderservers, dnssec: cfg.DNSSEC == "on"} } // Name return middleware name @@ -61,20 +62,21 @@ func (f *Forwarder) ServeDNS(ctx context.Context, ch *middleware.Chain) { return } - fReq := new(dns.Msg) - fReq.SetQuestion(req.Question[0].Name, req.Question[0].Qtype) - fReq.Question[0].Qclass = req.Question[0].Qclass - fReq.SetEdns0(dnsutil.DefaultMsgSize, true) - fReq.CheckingDisabled = req.CheckingDisabled + if !req.CheckingDisabled { + req.CheckingDisabled = !f.dnssec + } for _, server := range f.servers { resp, err := dnsutil.Exchange(ctx, req, server.Addr, server.Proto) if err != nil { - log.Warn("forwarder query failed", "query", formatQuestion(req.Question[0]), "error", err.Error()) + log.Info("forwarder query failed", "query", formatQuestion(req.Question[0]), "error", err.Error()) continue } resp.Id = req.Id + if !f.dnssec { + resp.CheckingDisabled = false + } _ = w.WriteMsg(resp) return diff --git a/middleware/resolver/handler.go b/middleware/resolver/handler.go index b9cf461a..b256bf6d 100644 --- a/middleware/resolver/handler.go +++ b/middleware/resolver/handler.go @@ -106,11 +106,23 @@ func (h *DNSHandler) handle(ctx context.Context, req *dns.Msg) *dns.Msg { req.RecursionDesired = false req.AuthenticatedData = false + if !req.CheckingDisabled { + req.CheckingDisabled = !h.resolver.dnssec + } + ctx, cancel := context.WithDeadline(ctx, time.Now().Add(h.cfg.QueryTimeout.Duration)) defer cancel() depth := h.cfg.Maxdepth resp, err := h.resolver.Resolve(ctx, req, h.resolver.rootservers, true, depth, 0, false, nil, q.Name == rootzone) + + if !h.resolver.dnssec { + req.CheckingDisabled = false + if resp != nil { + resp.CheckingDisabled = false + } + } + if err != nil { log.Info("Resolve query failed", "query", formatQuestion(q), "error", err.Error()) diff --git a/middleware/resolver/handler_test.go b/middleware/resolver/handler_test.go index d8de9aee..3ae8514f 100644 --- a/middleware/resolver/handler_test.go +++ b/middleware/resolver/handler_test.go @@ -33,6 +33,7 @@ func makeTestConfig() *config.Config { cfg.Timeout.Duration = 2 * time.Second cfg.Directory = filepath.Join(os.TempDir(), "sdns_temp") cfg.IPv6Access = true + cfg.DNSSEC = "on" if !middleware.Ready() { middleware.Register("edns", func(cfg *config.Config) middleware.Handler { return edns.New(cfg) }) diff --git a/middleware/resolver/resolver.go b/middleware/resolver/resolver.go index 33bfd466..7164cae4 100644 --- a/middleware/resolver/resolver.go +++ b/middleware/resolver/resolver.go @@ -37,6 +37,7 @@ type Resolver struct { ipv4cache *cache.Cache ipv6cache *cache.Cache + dnssec bool rootkeys []dns.RR qnameMinLevel int @@ -73,6 +74,8 @@ func NewResolver(cfg *config.Config) *Resolver { ipv4cache: cache.New(defaultCacheSize), + dnssec: cfg.DNSSEC == "on", + qnameMinLevel: cfg.QnameMinLevel, netTimeout: defaultTimeout, } @@ -1533,6 +1536,7 @@ func (r *Resolver) checkPriming() { req := new(dns.Msg) req.SetQuestion(rootzone, dns.TypeNS) req.SetEdns0(dnsutil.DefaultMsgSize, true) + req.CheckingDisabled = !r.dnssec ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(r.netTimeout)) defer cancel() @@ -1547,7 +1551,7 @@ func (r *Resolver) checkPriming() { return } - if !resp.AuthenticatedData { + if r.dnssec && !resp.AuthenticatedData { log.Error("Root servers update failed", "error", "not authenticated") return } @@ -1611,12 +1615,16 @@ func (r *Resolver) run() { } r.checkPriming() - r.AutoTA() + if r.dnssec { + r.AutoTA() + } ticker := time.NewTicker(12 * time.Hour) for range ticker.C { r.checkPriming() - r.AutoTA() + if r.dnssec { + r.AutoTA() + } } } diff --git a/sdns.go b/sdns.go index 952e95e2..b6a474e3 100644 --- a/sdns.go +++ b/sdns.go @@ -19,7 +19,7 @@ import ( "github.com/semihalev/sdns/server" ) -const version = "1.3.5" +const version = "1.3.6" var ( flagcfgpath string