From 79306cb48afec50336ac654fa3810d682848139c Mon Sep 17 00:00:00 2001
From: Ainar Garipov <a.garipov@adguard.com>
Date: Thu, 27 Jul 2023 21:06:51 +0300
Subject: [PATCH] Pull request 1944: 6049-block-ns-root

Updates #6049.

Squashed commit of the following:

commit 288a486b741b4dc57769bd5a0bdd67b4d75cc8c0
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Jul 27 20:59:14 2023 +0300

    dnsforward: fix blocking of ns root
---
 CHANGELOG.md                       |  5 +++++
 internal/dnsforward/access.go      |  2 +-
 internal/dnsforward/access_test.go |  6 ++++++
 internal/dnsforward/filter.go      | 14 ++++++++++----
 4 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 190d1235..1046812f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,10 +25,15 @@ NOTE: Add new changes BELOW THIS COMMENT.
 
 ### Fixed
 
+- Inability to block queries for the root domain, such as `NS .` queries, using
+  the *Disallowed domains* feature on the *DNS settings* page ([#6049]).  Users
+  who want to block `.` queries should use the `|.^` AdBlock rule or a similar
+  regular expression.
 - Client hostnames not resolving when upstream server responds with zero-TTL
   records ([#6046]).
 
 [#6046]: https://github.com/AdguardTeam/AdGuardHome/issues/6046
+[#6049]: https://github.com/AdguardTeam/AdGuardHome/issues/6049
 
 <!--
 NOTE: Add new changes ABOVE THIS COMMENT.
diff --git a/internal/dnsforward/access.go b/internal/dnsforward/access.go
index 12f5f3c7..c367d05b 100644
--- a/internal/dnsforward/access.go
+++ b/internal/dnsforward/access.go
@@ -90,7 +90,7 @@ func newAccessCtx(allowed, blocked, blockedHosts []string) (a *accessManager, er
 
 	lists := []filterlist.RuleList{
 		&filterlist.StringRuleList{
-			ID:             int(0),
+			ID:             0,
 			RulesText:      b.String(),
 			IgnoreCosmetic: true,
 		},
diff --git a/internal/dnsforward/access_test.go b/internal/dnsforward/access_test.go
index d5d7da26..9ca8013b 100644
--- a/internal/dnsforward/access_test.go
+++ b/internal/dnsforward/access_test.go
@@ -31,6 +31,7 @@ func TestIsBlockedHost(t *testing.T) {
 		"*.host.com",
 		"||host3.com^",
 		"||*^$dnstype=HTTPS",
+		"|.^",
 	})
 	require.NoError(t, err)
 
@@ -94,6 +95,11 @@ func TestIsBlockedHost(t *testing.T) {
 		name: "by_qtype_other",
 		host: "site-with-https-record.example",
 		qt:   dns.TypeA,
+	}, {
+		want: assert.True,
+		name: "ns_root",
+		host: ".",
+		qt:   dns.TypeNS,
 	}}
 
 	for _, tc := range testCases {
diff --git a/internal/dnsforward/filter.go b/internal/dnsforward/filter.go
index 3f35afc2..4dee0c07 100644
--- a/internal/dnsforward/filter.go
+++ b/internal/dnsforward/filter.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"strings"
 
+	"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
 	"github.com/AdguardTeam/AdGuardHome/internal/filtering"
 	"github.com/AdguardTeam/dnsproxy/proxy"
 	"github.com/AdguardTeam/golibs/log"
@@ -33,9 +34,9 @@ func (s *Server) beforeRequestHandler(
 	if len(pctx.Req.Question) == 1 {
 		q := pctx.Req.Question[0]
 		qt := q.Qtype
-		host := strings.TrimSuffix(q.Name, ".")
+		host := aghnet.NormalizeDomain(q.Name)
 		if s.access.isBlockedHost(host, qt) {
-			log.Debug("request %s %s is in access blocklist", dns.Type(qt), host)
+			log.Debug("access: request %s %s is in access blocklist", dns.Type(qt), host)
 
 			return s.preBlockedResponse(pctx)
 		}
@@ -79,7 +80,12 @@ func (s *Server) filterDNSRequest(dctx *dnsContext) (res *filtering.Result, err
 	res = &resVal
 	switch {
 	case res.IsFiltered:
-		log.Tracef("host %q is filtered, reason %q, rule: %q", host, res.Reason, res.Rules[0].Text)
+		log.Debug(
+			"dnsforward: host %q is filtered, reason: %q; rule: %q",
+			host,
+			res.Reason,
+			res.Rules[0].Text,
+		)
 		pctx.Res = s.genDNSFilterMessage(pctx, res)
 	case res.Reason.In(filtering.Rewritten, filtering.RewrittenRule) &&
 		res.CanonName != "" &&
@@ -189,7 +195,7 @@ func (s *Server) filterDNSResponse(
 			continue
 		} else if res.IsFiltered {
 			pctx.Res = s.genDNSFilterMessage(pctx, res)
-			log.Debug("DNSFwd: Matched %s by response: %s", pctx.Req.Question[0].Name, host)
+			log.Debug("dnsforward: matched %q by response: %q", pctx.Req.Question[0].Name, host)
 
 			return res, nil
 		}