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>
This commit is contained in:
Arko Dasgupta 2019-06-14 15:37:38 -07:00
parent a926e65406
commit 313d2b8a74
3 changed files with 29 additions and 20 deletions

View File

@ -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 {

View File

@ -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)

View File

@ -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)