From 313d2b8a742e97fa0ac182e721f54bf9d02c691c Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Fri, 14 Jun 2019 15:37:38 -0700 Subject: [PATCH] Make DNS records and queries case-insensitive RFC434 states that DNS Servers should be case insensitive This commit makes sure that all DNS queries will be translated to lower ASCII characters and all svcRecords will be saved in lower case to abide by the RFC Relates to https://github.com/moby/moby/issues/21169 Signed-off-by: Arko Dasgupta --- libnetwork/network.go | 9 +++++++-- libnetwork/resolver.go | 2 +- libnetwork/resolver_test.go | 38 ++++++++++++++++++++----------------- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/libnetwork/network.go b/libnetwork/network.go index f128cac785..b08916303b 100644 --- a/libnetwork/network.go +++ b/libnetwork/network.go @@ -1381,14 +1381,18 @@ func delIPToName(ipMap setmatrix.SetMatrix, name, serviceID string, ip net.IP) { } func addNameToIP(svcMap setmatrix.SetMatrix, name, serviceID string, epIP net.IP) { - svcMap.Insert(name, svcMapEntry{ + // Since DNS name resolution is case-insensitive, Use the lower-case form + // of the name as the key into svcMap + lowerCaseName := strings.ToLower(name) + svcMap.Insert(lowerCaseName, svcMapEntry{ ip: epIP.String(), serviceID: serviceID, }) } func delNameToIP(svcMap setmatrix.SetMatrix, name, serviceID string, epIP net.IP) { - svcMap.Remove(name, svcMapEntry{ + lowerCaseName := strings.ToLower(name) + svcMap.Remove(lowerCaseName, svcMapEntry{ ip: epIP.String(), serviceID: serviceID, }) @@ -1956,6 +1960,7 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) { } req = strings.TrimSuffix(req, ".") + req = strings.ToLower(req) ipSet, ok := sr.svcMap.Get(req) if ipType == types.IPv6 { diff --git a/libnetwork/resolver.go b/libnetwork/resolver.go index 4f5f71897c..8e3158e559 100644 --- a/libnetwork/resolver.go +++ b/libnetwork/resolver.go @@ -366,8 +366,8 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { if query == nil || len(query.Question) == 0 { return } - name := query.Question[0].Name + name := query.Question[0].Name switch query.Question[0].Qtype { case dns.TypeA: resp, err = r.handleIPQuery(name, query, types.IPv4) diff --git a/libnetwork/resolver_test.go b/libnetwork/resolver_test.go index 8e5755bccb..970255f984 100644 --- a/libnetwork/resolver_test.go +++ b/libnetwork/resolver_test.go @@ -126,29 +126,33 @@ func TestDNSIPQuery(t *testing.T) { r := NewResolver(resolverIPSandbox, false, sb.Key(), sb.(*sandbox)) // test name1's IP is resolved correctly with the default A type query - q := new(dns.Msg) - q.SetQuestion("name1", dns.TypeA) - r.(*resolver).ServeDNS(w, q) - resp := w.GetResponse() - checkNonNullResponse(t, resp) - t.Log("Response: ", resp.String()) - checkDNSResponseCode(t, resp, dns.RcodeSuccess) - checkDNSAnswersCount(t, resp, 1) - checkDNSRRType(t, resp.Answer[0].Header().Rrtype, dns.TypeA) - if answer, ok := resp.Answer[0].(*dns.A); ok { - if !bytes.Equal(answer.A, net.ParseIP("192.168.0.1")) { - t.Fatalf("IP response in Answer %v does not match 192.168.0.1", answer.A) + // Also make sure DNS lookups are case insensitive + names := []string{"name1", "NaMe1"} + for _, name := range names { + q := new(dns.Msg) + q.SetQuestion(name, dns.TypeA) + r.(*resolver).ServeDNS(w, q) + resp := w.GetResponse() + checkNonNullResponse(t, resp) + t.Log("Response: ", resp.String()) + checkDNSResponseCode(t, resp, dns.RcodeSuccess) + checkDNSAnswersCount(t, resp, 1) + checkDNSRRType(t, resp.Answer[0].Header().Rrtype, dns.TypeA) + if answer, ok := resp.Answer[0].(*dns.A); ok { + if !bytes.Equal(answer.A, net.ParseIP("192.168.0.1")) { + t.Fatalf("IP response in Answer %v does not match 192.168.0.1", answer.A) + } + } else { + t.Fatal("Answer of type A not found") } - } else { - t.Fatal("Answer of type A not found") + w.ClearResponse() } - w.ClearResponse() // test MX query with name1 results in Success response with 0 answer records - q = new(dns.Msg) + q := new(dns.Msg) q.SetQuestion("name1", dns.TypeMX) r.(*resolver).ServeDNS(w, q) - resp = w.GetResponse() + resp := w.GetResponse() checkNonNullResponse(t, resp) t.Log("Response: ", resp.String()) checkDNSResponseCode(t, resp, dns.RcodeSuccess)