mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-31 10:13:14 -04:00 
			
		
		
		
	plugin/template: fix CNAME upstream handling (#1886)
This commit is contained in:
		| @@ -149,7 +149,7 @@ func templateParse(c *caddy.Controller) (handler Handler, err error) { | |||||||
| 				if err != nil { | 				if err != nil { | ||||||
| 					return handler, err | 					return handler, err | ||||||
| 				} | 				} | ||||||
| 				t.upstream = u | 				t.upstream = &u | ||||||
| 			default: | 			default: | ||||||
| 				return handler, c.ArgErr() | 				return handler, c.ArgErr() | ||||||
| 			} | 			} | ||||||
|   | |||||||
| @@ -34,7 +34,7 @@ type template struct { | |||||||
| 	qclass     uint16 | 	qclass     uint16 | ||||||
| 	qtype      uint16 | 	qtype      uint16 | ||||||
| 	fall       fall.F | 	fall       fall.F | ||||||
| 	upstream   upstream.Upstream | 	upstream   *upstream.Upstream | ||||||
| } | } | ||||||
|  |  | ||||||
| type templateData struct { | type templateData struct { | ||||||
| @@ -84,8 +84,8 @@ func (h Handler) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) | |||||||
| 				return dns.RcodeServerFailure, err | 				return dns.RcodeServerFailure, err | ||||||
| 			} | 			} | ||||||
| 			msg.Answer = append(msg.Answer, rr) | 			msg.Answer = append(msg.Answer, rr) | ||||||
| 			if rr.Header().Rrtype == dns.TypeCNAME { | 			if template.upstream != nil && (state.QType() == dns.TypeA || state.QType() == dns.TypeAAAA) && rr.Header().Rrtype == dns.TypeCNAME { | ||||||
| 				up, _ := template.upstream.Lookup(state, rr.(*dns.CNAME).Target, dns.TypeA) | 				up, _ := template.upstream.Lookup(state, rr.(*dns.CNAME).Target, state.QType()) | ||||||
| 				msg.Answer = append(msg.Answer, up.Answer...) | 				msg.Answer = append(msg.Answer, up.Answer...) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -92,6 +92,14 @@ func TestHandler(t *testing.T) { | |||||||
| 		fall:      fall.Root, | 		fall:      fall.Root, | ||||||
| 		zones:     []string{"."}, | 		zones:     []string{"."}, | ||||||
| 	} | 	} | ||||||
|  | 	cnameTemplate := template{ | ||||||
|  | 		regex:  []*regexp.Regexp{regexp.MustCompile("example[.]net[.]")}, | ||||||
|  | 		answer: []*gotmpl.Template{gotmpl.Must(gotmpl.New("answer").Parse("example.net 60 IN CNAME target.example.com"))}, | ||||||
|  | 		qclass: dns.ClassANY, | ||||||
|  | 		qtype:  dns.TypeANY, | ||||||
|  | 		fall:   fall.Root, | ||||||
|  | 		zones:  []string{"."}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	tests := []struct { | 	tests := []struct { | ||||||
| 		tmpl           template | 		tmpl           template | ||||||
| @@ -254,6 +262,20 @@ func TestHandler(t *testing.T) { | |||||||
| 				return nil | 				return nil | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name:         "CNAMEWithoutUpstream", | ||||||
|  | 			tmpl:         cnameTemplate, | ||||||
|  | 			qclass:       dns.ClassINET, | ||||||
|  | 			qtype:        dns.TypeA, | ||||||
|  | 			qname:        "example.net.", | ||||||
|  | 			expectedCode: dns.RcodeSuccess, | ||||||
|  | 			verifyResponse: func(r *dns.Msg) error { | ||||||
|  | 				if len(r.Answer) != 1 { | ||||||
|  | 					return fmt.Errorf("expected 1 answer, got %v", len(r.Answer)) | ||||||
|  | 				} | ||||||
|  | 				return nil | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	ctx := context.TODO() | 	ctx := context.TODO() | ||||||
|   | |||||||
							
								
								
									
										71
									
								
								test/template_upstream_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								test/template_upstream_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | |||||||
|  | package test | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  |  | ||||||
|  | 	"github.com/miekg/dns" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func TestTemplateUpstream(t *testing.T) { | ||||||
|  | 	corefile := `.:0 { | ||||||
|  |  		# CNAME | ||||||
|  | 		template IN ANY cname.example.net. { | ||||||
|  | 			match ".*" | ||||||
|  | 			answer "cname.example.net. 60 IN CNAME target.example.net." | ||||||
|  | 			upstream | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		# Target | ||||||
|  | 		template IN A target.example.net. { | ||||||
|  | 			match ".*" | ||||||
|  | 			answer "target.example.net. 60 IN A 1.2.3.4" | ||||||
|  | 		} | ||||||
|  | } | ||||||
|  | ` | ||||||
|  | 	i, udp, _, err := CoreDNSServerAndPorts(corefile) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("Could not get CoreDNS serving instance: %s", err) | ||||||
|  | 	} | ||||||
|  | 	defer i.Stop() | ||||||
|  |  | ||||||
|  | 	// Test that an A query returns a CNAME and an A record | ||||||
|  | 	m := new(dns.Msg) | ||||||
|  | 	m.SetQuestion("cname.example.net.", dns.TypeA) | ||||||
|  | 	m.SetEdns0(4096, true) // need this? | ||||||
|  |  | ||||||
|  | 	r, err := dns.Exchange(m, udp) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("Could not send msg: %s", err) | ||||||
|  | 	} | ||||||
|  | 	if r.Rcode == dns.RcodeServerFailure { | ||||||
|  | 		t.Fatalf("Rcode should not be dns.RcodeServerFailure") | ||||||
|  | 	} | ||||||
|  | 	if len(r.Answer) < 2 { | ||||||
|  | 		t.Fatalf("Expected 2 answers, got %v", len(r.Answer)) | ||||||
|  | 	} | ||||||
|  | 	if x := r.Answer[0].(*dns.CNAME).Target; x != "target.example.net." { | ||||||
|  | 		t.Fatalf("Failed to get address for CNAME, expected target.example.net. got %s", x) | ||||||
|  | 	} | ||||||
|  | 	if x := r.Answer[1].(*dns.A).A.String(); x != "1.2.3.4" { | ||||||
|  | 		t.Fatalf("Failed to get address for CNAME, expected 1.2.3.4 got %s", x) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Test that a CNAME query only returns a CNAME | ||||||
|  | 	m = new(dns.Msg) | ||||||
|  | 	m.SetQuestion("cname.example.net.", dns.TypeCNAME) | ||||||
|  | 	m.SetEdns0(4096, true) // need this? | ||||||
|  |  | ||||||
|  | 	r, err = dns.Exchange(m, udp) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("Could not send msg: %s", err) | ||||||
|  | 	} | ||||||
|  | 	if r.Rcode == dns.RcodeServerFailure { | ||||||
|  | 		t.Fatalf("Rcode should not be dns.RcodeServerFailure") | ||||||
|  | 	} | ||||||
|  | 	if len(r.Answer) < 1 { | ||||||
|  | 		t.Fatalf("Expected 1 answer, got %v", len(r.Answer)) | ||||||
|  | 	} | ||||||
|  | 	if x := r.Answer[0].(*dns.CNAME).Target; x != "target.example.net." { | ||||||
|  | 		t.Fatalf("Failed to get address for CNAME, expected target.example.net. got %s", x) | ||||||
|  | 	} | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user