From 37db83e5b726e7248bd86e48783bb1fe6b4f5729 Mon Sep 17 00:00:00 2001
From: Ward Vandewege <cure@users.noreply.github.com>
Date: Thu, 7 Feb 2019 02:16:33 -0500
Subject: [PATCH] Respond case insensitively to A and SOA requests (#152)

* When appending the SOA for authoritative NXDOMAIN responses, it needs to go in
the Authoritative section, not the Answer section.

This fixes the acme-dns validation for the lego Let's Encrypt client.

* Respond case-insensitively to A and SOA requests. Add corresponding tests.

This fixes the autocert feature with Let's Encrypt, because Let's Encrypt does
a lookup for the A record with a deliberately mangled case.
---
 dns.go      |  6 +++---
 dns_test.go | 24 ++++++++++++++++++++++++
 2 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/dns.go b/dns.go
index 3ca0753..baf54a8 100644
--- a/dns.go
+++ b/dns.go
@@ -113,7 +113,7 @@ func (d *DNSServer) readQuery(m *dns.Msg) {
 func (d *DNSServer) getRecord(q dns.Question) ([]dns.RR, error) {
 	var rr []dns.RR
 	var cnames []dns.RR
-	domain, ok := d.Domains[q.Name]
+	domain, ok := d.Domains[strings.ToLower(q.Name)]
 	if !ok {
 		return rr, fmt.Errorf("No records for domain %s", q.Name)
 	}
@@ -133,7 +133,7 @@ func (d *DNSServer) getRecord(q dns.Question) ([]dns.RR, error) {
 
 // answeringForDomain checks if we have any records for a domain
 func (d *DNSServer) answeringForDomain(name string) bool {
-	_, ok := d.Domains[name]
+	_, ok := d.Domains[strings.ToLower(name)]
 	return ok
 }
 
@@ -141,7 +141,7 @@ func (d *DNSServer) isAuthoritative(q dns.Question) bool {
 	if d.answeringForDomain(q.Name) {
 		return true
 	}
-	domainParts := strings.Split(q.Name, ".")
+	domainParts := strings.Split(strings.ToLower(q.Name), ".")
 	for i := range domainParts {
 		if d.answeringForDomain(strings.Join(domainParts[i:], ".")) {
 			return true
diff --git a/dns_test.go b/dns_test.go
index 044e9a0..83723f8 100644
--- a/dns_test.go
+++ b/dns_test.go
@@ -218,3 +218,27 @@ func TestResolveTXT(t *testing.T) {
 		}
 	}
 }
+
+func TestCaseInsensitiveResolveA(t *testing.T) {
+  resolv := resolver{server: "127.0.0.1:15353"}
+  answer, err := resolv.lookup("aUtH.eXAmpLe.org", dns.TypeA)
+  if err != nil {
+    t.Errorf("%v", err)
+  }
+
+  if len(answer.Answer) == 0 {
+    t.Error("No answer for DNS query")
+  }
+}
+
+func TestCaseInsensitiveResolveSOA(t *testing.T) {
+  resolv := resolver{server: "127.0.0.1:15353"}
+  answer, _ := resolv.lookup("doesnotexist.aUtH.eXAmpLe.org", dns.TypeSOA)
+  if answer.Rcode != dns.RcodeNameError {
+    t.Errorf("Was expecing NXDOMAIN rcode, but got [%s] instead.", dns.RcodeToString[answer.Rcode])
+  }
+
+  if len(answer.Ns) == 0 {
+    t.Error("No SOA answer for DNS query")
+  }
+}
-- 
GitLab