소스 검색

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 <arko.dasgupta@docker.com>
Arko Dasgupta 6 년 전
부모
커밋
313d2b8a74
3개의 변경된 파일29개의 추가작업 그리고 20개의 파일을 삭제
  1. 7 2
      libnetwork/network.go
  2. 1 1
      libnetwork/resolver.go
  3. 21 17
      libnetwork/resolver_test.go

+ 7 - 2
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 {

+ 1 - 1
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)

+ 21 - 17
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)