mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-30 17:53:21 -04:00 
			
		
		
		
	plugin/file: Use NXDOMAIN response if CNAME target is NXDOMAIN (#4303)
* pass through nxdomain results Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * return srvfail and nodata results Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * add test Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * cover more response cases Signed-off-by: Chris O'Haver <cohaver@infoblox.com>
This commit is contained in:
		| @@ -307,8 +307,9 @@ func (z *Zone) externalLookup(ctx context.Context, state request.Request, elem * | ||||
| 	targetName := rrs[0].(*dns.CNAME).Target | ||||
| 	elem, _ = z.Tree.Search(targetName) | ||||
| 	if elem == nil { | ||||
| 		rrs = append(rrs, z.doLookup(ctx, state, targetName, qtype)...) | ||||
| 		return rrs, z.Apex.ns(do), nil, Success | ||||
| 		lookupRRs, result := z.doLookup(ctx, state, targetName, qtype) | ||||
| 		rrs = append(rrs, lookupRRs...) | ||||
| 		return rrs, z.Apex.ns(do), nil, result | ||||
| 	} | ||||
|  | ||||
| 	i := 0 | ||||
| @@ -326,8 +327,9 @@ Redo: | ||||
| 		targetName := cname[0].(*dns.CNAME).Target | ||||
| 		elem, _ = z.Tree.Search(targetName) | ||||
| 		if elem == nil { | ||||
| 			rrs = append(rrs, z.doLookup(ctx, state, targetName, qtype)...) | ||||
| 			return rrs, z.Apex.ns(do), nil, Success | ||||
| 			lookupRRs, result := z.doLookup(ctx, state, targetName, qtype) | ||||
| 			rrs = append(rrs, lookupRRs...) | ||||
| 			return rrs, z.Apex.ns(do), nil, result | ||||
| 		} | ||||
|  | ||||
| 		i++ | ||||
| @@ -352,15 +354,24 @@ Redo: | ||||
| 	return rrs, z.Apex.ns(do), nil, Success | ||||
| } | ||||
|  | ||||
| func (z *Zone) doLookup(ctx context.Context, state request.Request, target string, qtype uint16) []dns.RR { | ||||
| func (z *Zone) doLookup(ctx context.Context, state request.Request, target string, qtype uint16) ([]dns.RR, Result) { | ||||
| 	m, e := z.Upstream.Lookup(ctx, state, target, qtype) | ||||
| 	if e != nil { | ||||
| 		return nil | ||||
| 		return nil, Success | ||||
| 	} | ||||
| 	if m == nil { | ||||
| 		return nil | ||||
| 		return nil, Success | ||||
| 	} | ||||
| 	return m.Answer | ||||
| 	if m.Rcode == dns.RcodeNameError { | ||||
| 		return m.Answer, NameError | ||||
| 	} | ||||
| 	if m.Rcode == dns.RcodeServerFailure { | ||||
| 		return m.Answer, ServerFailure | ||||
| 	} | ||||
| 	if m.Rcode == dns.RcodeSuccess && len(m.Answer) == 0 { | ||||
| 		return m.Answer, NoData | ||||
| 	} | ||||
| 	return m.Answer, Success | ||||
| } | ||||
|  | ||||
| // additionalProcessing checks the current answer section and retrieves A or AAAA records | ||||
|   | ||||
| @@ -58,6 +58,113 @@ www 3600 IN CNAME www.example.net. | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestFileUpstreamError(t *testing.T) { | ||||
| 	cases := map[string]test.Case{ | ||||
| 		"nxdomain": { | ||||
| 			Qname: "nxdomain.example.org.", Qtype: dns.TypeA, | ||||
| 			Answer: []dns.RR{ | ||||
| 				test.CNAME("nxdomain.example.org.	3600	IN	CNAME	nxdomain.example.net"), | ||||
| 			}, | ||||
| 			Rcode: dns.RcodeNameError, | ||||
| 		}, | ||||
| 		"nxdomain-chain": { | ||||
| 			Qname: "chain1.example.org.", Qtype: dns.TypeA, | ||||
| 			Answer: []dns.RR{ | ||||
| 				test.CNAME("chain1.example.org.	3600	IN	CNAME	nxdomain.example.org"), | ||||
| 				test.CNAME("nxdomain.example.org.	3600	IN	CNAME	nxdomain.example.net"), | ||||
| 			}, | ||||
| 			Rcode: dns.RcodeNameError, | ||||
| 		}, | ||||
| 		"srvfail": { | ||||
| 			Qname: "srvfail.example.org.", Qtype: dns.TypeA, | ||||
| 			Rcode: dns.RcodeServerFailure, | ||||
| 		}, | ||||
| 		"srvfail-chain": { | ||||
| 			Qname: "chain2.example.org.", Qtype: dns.TypeA, | ||||
| 			Rcode: dns.RcodeServerFailure, | ||||
| 		}, | ||||
| 		"nodata": { | ||||
| 			Qname: "nodata.example.org.", Qtype: dns.TypeA, | ||||
| 			Answer: []dns.RR{ | ||||
| 				test.CNAME("nodata.example.org.	3600	IN	CNAME	nodata.example.net"), | ||||
| 			}, | ||||
| 			Rcode: dns.RcodeSuccess, | ||||
| 		}, | ||||
| 		"nodata-chain": { | ||||
| 			Qname: "chain3.example.org.", Qtype: dns.TypeA, | ||||
| 			Answer: []dns.RR{ | ||||
| 				test.CNAME("chain3.example.org.	3600	IN	CNAME	nodata.example.org"), | ||||
| 				test.CNAME("nodata.example.org.	3600	IN	CNAME	nodata.example.net"), | ||||
| 			}, | ||||
| 			Rcode: dns.RcodeSuccess, | ||||
| 		}, | ||||
| 	} | ||||
| 	name, rm, err := test.TempFile(".", `$ORIGIN example.org. | ||||
| @	3600 IN	SOA   sns.dns.icann.org. noc.dns.icann.org. ( | ||||
|         2017042745 ; serial | ||||
|         7200       ; refresh (2 hours) | ||||
|         3600       ; retry (1 hour) | ||||
|         1209600    ; expire (2 weeks) | ||||
|         3600       ; minimum (1 hour) | ||||
| ) | ||||
|  | ||||
|     3600 IN NS    a.iana-servers.net. | ||||
|     3600 IN NS    b.iana-servers.net. | ||||
|  | ||||
| chain1   3600 IN CNAME nxdomain | ||||
| nxdomain 3600 IN CNAME nxdomain.example.net. | ||||
| chain2   3600 IN CNAME srvfail | ||||
| srvfail  3600 IN CNAME srvfail.example.net. | ||||
| chain3   3600 IN CNAME nodata | ||||
| nodata   3600 IN CNAME nodata.example.net. | ||||
|  | ||||
| `) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Failed to create zone: %s", err) | ||||
| 	} | ||||
| 	defer rm() | ||||
|  | ||||
| 	corefile := `.:0 { | ||||
| 	template ANY A nxdomain.example.net. { | ||||
| 		rcode NXDOMAIN | ||||
| 	} | ||||
| 	template ANY A srvfail.example.net. { | ||||
| 		rcode SERVFAIL | ||||
| 	} | ||||
| 	template ANY A nodata.example.net. { | ||||
| 	} | ||||
| 	file ` + name + ` example.org | ||||
| }` | ||||
|  | ||||
| 	i, udp, _, err := CoreDNSServerAndPorts(corefile) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Could not get CoreDNS serving instance: %s", err) | ||||
| 	} | ||||
| 	defer i.Stop() | ||||
|  | ||||
| 	for n, tc := range cases { | ||||
| 		t.Run(n, func(t *testing.T) { | ||||
| 			m := new(dns.Msg) | ||||
| 			m.SetQuestion(tc.Qname, tc.Qtype) | ||||
| 			m.SetEdns0(4096, true) | ||||
|  | ||||
| 			r, err := dns.Exchange(m, udp) | ||||
| 			if err != nil { | ||||
| 				t.Fatalf("Could not exchange msg: %s", err) | ||||
| 			} | ||||
| 			if r.Rcode != tc.Rcode { | ||||
| 				t.Fatalf("expected rcode %v, got %v", tc.Rcode, r.Rcode) | ||||
| 			} | ||||
| 			if n := len(r.Answer); n != len(tc.Answer) { | ||||
| 				t.Fatalf("Expected %v answers, got %v", len(tc.Answer), n) | ||||
| 			} | ||||
| 			if err := test.Section(tc, test.Answer, r.Answer); err != nil { | ||||
| 				t.Error(err) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // TestFileUpstreamAdditional runs two CoreDNS servers that serve example.org and foo.example.org. | ||||
| // example.org contains a cname to foo.example.org; this should be resolved via upstream.Self. | ||||
| func TestFileUpstreamAdditional(t *testing.T) { | ||||
|   | ||||
							
								
								
									
										19
									
								
								test/go-test-tmpfile565156097
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								test/go-test-tmpfile565156097
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| $ORIGIN example.org. | ||||
| @	3600 IN	SOA   sns.dns.icann.org. noc.dns.icann.org. ( | ||||
|         2017042745 ; serial | ||||
|         7200       ; refresh (2 hours) | ||||
|         3600       ; retry (1 hour) | ||||
|         1209600    ; expire (2 weeks) | ||||
|         3600       ; minimum (1 hour) | ||||
| ) | ||||
|  | ||||
|     3600 IN NS    a.iana-servers.net. | ||||
|     3600 IN NS    b.iana-servers.net. | ||||
|  | ||||
| chain1   3600 IN CNAME nxdomain | ||||
| nxdomain 3600 IN CNAME nxdomain.example.net. | ||||
| chain2   3600 IN CNAME srvfail | ||||
| srvfail  3600 IN CNAME srvfail.example.net. | ||||
| chain3   3600 IN CNAME nodata | ||||
| nodata   3600 IN CNAME nodata.example.net. | ||||
|  | ||||
		Reference in New Issue
	
	Block a user