mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-27 08:14:18 -04:00 
			
		
		
		
	merge conflict fixed
This commit is contained in:
		| @@ -13,6 +13,8 @@ zonefile. New zones or changed zone are automatically picked up from disk. | ||||
| ~~~ | ||||
| auto [ZONES...] { | ||||
|     directory DIR [REGEXP ORIGIN_TEMPLATE [TIMEOUT]] | ||||
|     no_reload | ||||
|     upstream ADDRESS... | ||||
| } | ||||
| ~~~ | ||||
|  | ||||
| @@ -26,6 +28,10 @@ are used. | ||||
|   name `db.example.com`, the extracted origin will be `example.com`. **TIMEOUT** specifies how often | ||||
|   CoreDNS should scan the directory, the default is every 60 seconds. This value is in seconds. | ||||
|   The minimum value is 1 second. | ||||
| * `no_reload` by default CoreDNS will reload a zone from disk whenever it detects a change to the | ||||
|   file. This option disables that behavior. | ||||
| * `upstream` defines upstream resolvers to be used resolve external names found (think CNAMEs) | ||||
|   pointing to external names. | ||||
|  | ||||
| All directives from the *file* middleware are supported. Note that *auto* will load all zones found, | ||||
| even though the directive might only receive queries for a specific zone. I.e: | ||||
|   | ||||
| @@ -9,6 +9,7 @@ import ( | ||||
| 	"github.com/miekg/coredns/middleware" | ||||
| 	"github.com/miekg/coredns/middleware/file" | ||||
| 	"github.com/miekg/coredns/middleware/metrics" | ||||
| 	"github.com/miekg/coredns/middleware/proxy" | ||||
| 	"github.com/miekg/coredns/request" | ||||
|  | ||||
| 	"github.com/miekg/dns" | ||||
| @@ -33,6 +34,7 @@ type ( | ||||
| 		// In the future this should be something like ZoneMeta that contains all this stuff. | ||||
| 		transferTo []string | ||||
| 		noReload   bool | ||||
| 		proxy      proxy.Proxy // Proxy for looking up names during the resolution process | ||||
|  | ||||
| 		duration time.Duration | ||||
| 	} | ||||
| @@ -73,7 +75,7 @@ func (a Auto) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i | ||||
| 		return xfr.ServeDNS(ctx, w, r) | ||||
| 	} | ||||
|  | ||||
| 	answer, ns, extra, result := z.Lookup(qname, state.QType(), state.Do()) | ||||
| 	answer, ns, extra, result := z.Lookup(state, qname) | ||||
|  | ||||
| 	m := new(dns.Msg) | ||||
| 	m.SetReply(r) | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package auto | ||||
|  | ||||
| import ( | ||||
| 	"log" | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"regexp" | ||||
| @@ -12,6 +13,7 @@ import ( | ||||
| 	"github.com/miekg/coredns/middleware" | ||||
| 	"github.com/miekg/coredns/middleware/file" | ||||
| 	"github.com/miekg/coredns/middleware/metrics" | ||||
| 	"github.com/miekg/coredns/middleware/proxy" | ||||
|  | ||||
| 	"github.com/mholt/caddy" | ||||
| ) | ||||
| @@ -142,6 +144,19 @@ func autoParse(c *caddy.Controller) (Auto, error) { | ||||
| 				case "no_reload": | ||||
| 					a.loader.noReload = true | ||||
|  | ||||
| 				case "upstream": | ||||
| 					args := c.RemainingArgs() | ||||
| 					if len(args) == 0 { | ||||
| 						return a, c.ArgErr() | ||||
| 					} | ||||
| 					for i := 0; i < len(args); i++ { | ||||
| 						h, p, e := net.SplitHostPort(args[i]) | ||||
| 						if e != nil && p == "" { | ||||
| 							args[i] = h + ":53" | ||||
| 						} | ||||
| 					} | ||||
| 					a.loader.proxy = proxy.New(args) | ||||
|  | ||||
| 				default: | ||||
| 					t, _, e := file.TransferParse(c, false) | ||||
| 					if e != nil { | ||||
|   | ||||
| @@ -39,6 +39,7 @@ func TestAutoParse(t *testing.T) { | ||||
| 				directory /tmp (.*) bliep | ||||
| 				transfer to 127.0.0.1 | ||||
| 				transfer to 127.0.0.2 | ||||
| 				upstream 8.8.8.8 | ||||
| 			}`, | ||||
| 			false, "/tmp", "bliep", `(.*)`, []string{"127.0.0.1:53", "127.0.0.2:53"}, | ||||
| 		}, | ||||
|   | ||||
| @@ -52,6 +52,7 @@ func (a Auto) Walk() error { | ||||
| 		} | ||||
|  | ||||
| 		zo.NoReload = a.loader.noReload | ||||
| 		zo.Proxy = a.loader.proxy | ||||
| 		zo.TransferTo = a.loader.transferTo | ||||
|  | ||||
| 		a.Zones.Add(zo, origin) | ||||
|   | ||||
| @@ -9,7 +9,6 @@ import ( | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/mholt/caddy" | ||||
| 	"github.com/miekg/coredns/middleware/etcd/msg" | ||||
| 	"github.com/miekg/coredns/middleware/pkg/dnsrecorder" | ||||
| 	"github.com/miekg/coredns/middleware/pkg/singleflight" | ||||
| @@ -17,6 +16,7 @@ import ( | ||||
| 	"github.com/miekg/coredns/middleware/test" | ||||
|  | ||||
| 	etcdc "github.com/coreos/etcd/client" | ||||
| 	"github.com/mholt/caddy" | ||||
| 	"github.com/miekg/dns" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
|   | ||||
| @@ -27,6 +27,7 @@ TSIG key information, something like `transfer out [ADDRESS...] key [NAME[:ALG]] | ||||
| file DBFILE [ZONES... ] { | ||||
|     transfer to ADDRESS... | ||||
|     no_reload | ||||
|     upstream ADDRESS... | ||||
| } | ||||
| ~~~ | ||||
|  | ||||
| @@ -36,6 +37,8 @@ file DBFILE [ZONES... ] { | ||||
|   When an address is specified a notify message will be send whenever the zone is reloaded. | ||||
| * `no_reload` by default CoreDNS will reload a zone from disk whenever it detects a change to the | ||||
|   file. This option disables that behavior. | ||||
| * `upstream` defines upstream resolvers to be used resolve external names found (think CNAMEs) | ||||
|   pointing to external names. | ||||
|  | ||||
| ## Examples | ||||
|  | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/miekg/coredns/middleware/pkg/dnsrecorder" | ||||
| 	"github.com/miekg/coredns/middleware/proxy" | ||||
| 	"github.com/miekg/coredns/middleware/test" | ||||
|  | ||||
| 	"github.com/miekg/dns" | ||||
| @@ -68,6 +69,12 @@ var cnameTestCases = []test.Case{ | ||||
| 			test.CNAME("www3.example.org. 1800	IN	CNAME www2.example.org."), | ||||
| 		}, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Qname: "dangling.example.org.", Qtype: dns.TypeA, | ||||
| 		Answer: []dns.RR{ | ||||
| 			test.CNAME("dangling.example.org. 1800	IN	CNAME foo.example.org."), | ||||
| 		}, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Qname: "www3.example.org.", Qtype: dns.TypeA, | ||||
| 		Answer: []dns.RR{ | ||||
| @@ -80,6 +87,61 @@ var cnameTestCases = []test.Case{ | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func TestLookupCNAMEExternal(t *testing.T) { | ||||
| 	name := "example.org." | ||||
| 	zone, err := Parse(strings.NewReader(dbExampleCNAME), name, "stdin") | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Expected no error when reading zone, got %q", err) | ||||
| 	} | ||||
| 	zone.Proxy = proxy.New([]string{"8.8.8.8:53"}) // TODO(miek): point to local instance | ||||
|  | ||||
| 	fm := File{Next: test.ErrorHandler(), Zones: Zones{Z: map[string]*Zone{name: zone}, Names: []string{name}}} | ||||
| 	ctx := context.TODO() | ||||
|  | ||||
| 	for _, tc := range exernalTestCases { | ||||
| 		m := tc.Msg() | ||||
|  | ||||
| 		rec := dnsrecorder.New(&test.ResponseWriter{}) | ||||
| 		_, err := fm.ServeDNS(ctx, rec, m) | ||||
| 		if err != nil { | ||||
| 			t.Errorf("Expected no error, got %v\n", err) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		resp := rec.Msg | ||||
| 		sort.Sort(test.RRSet(resp.Answer)) | ||||
| 		sort.Sort(test.RRSet(resp.Ns)) | ||||
| 		sort.Sort(test.RRSet(resp.Extra)) | ||||
|  | ||||
| 		if !test.Header(t, tc, resp) { | ||||
| 			t.Logf("%v\n", resp) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if !test.Section(t, tc, test.Answer, resp.Answer) { | ||||
| 			t.Logf("%v\n", resp) | ||||
| 		} | ||||
| 		if !test.Section(t, tc, test.Ns, resp.Ns) { | ||||
| 			t.Logf("%v\n", resp) | ||||
|  | ||||
| 		} | ||||
| 		if !test.Section(t, tc, test.Extra, resp.Extra) { | ||||
| 			t.Logf("%v\n", resp) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var exernalTestCases = []test.Case{ | ||||
| 	{ | ||||
| 		Qname: "external.example.org.", Qtype: dns.TypeA, | ||||
| 		Answer: []dns.RR{ | ||||
| 			test.CNAME("external.example.org. 1800	CNAME	www.example.net."), | ||||
| 			// magic 303 TTL that says: don't check TTL. | ||||
| 			test.A("www.example.net.	303	IN	A	93.184.216.34"), | ||||
| 		}, | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| const dbExampleCNAME = ` | ||||
| $TTL    30M | ||||
| $ORIGIN example.org. | ||||
| @@ -95,4 +157,5 @@ www3            IN      CNAME   www2 | ||||
| www2            IN      CNAME   www1 | ||||
| www1            IN      CNAME   www | ||||
| www             IN      CNAME   a | ||||
| dangling        IN      CNAME   foo` | ||||
| dangling        IN      CNAME   foo | ||||
| external        IN      CNAME   www.example.net.` | ||||
|   | ||||
| @@ -84,7 +84,7 @@ func (f File) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i | ||||
| 		return xfr.ServeDNS(ctx, w, r) | ||||
| 	} | ||||
|  | ||||
| 	answer, ns, extra, result := z.Lookup(qname, state.QType(), state.Do()) | ||||
| 	answer, ns, extra, result := z.Lookup(state, qname) | ||||
|  | ||||
| 	m := new(dns.Msg) | ||||
| 	m.SetReply(r) | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package file | ||||
|  | ||||
| import ( | ||||
| 	"github.com/miekg/coredns/middleware/file/tree" | ||||
| 	"github.com/miekg/coredns/request" | ||||
|  | ||||
| 	"github.com/miekg/dns" | ||||
| ) | ||||
| @@ -24,7 +25,11 @@ const ( | ||||
|  | ||||
| // Lookup looks up qname and qtype in the zone. When do is true DNSSEC records are included. | ||||
| // Three sets of records are returned, one for the answer, one for authority  and one for the additional section. | ||||
| func (z *Zone) Lookup(qname string, qtype uint16, do bool) ([]dns.RR, []dns.RR, []dns.RR, Result) { | ||||
| func (z *Zone) Lookup(state request.Request, qname string) ([]dns.RR, []dns.RR, []dns.RR, Result) { | ||||
|  | ||||
| 	qtype := state.QType() | ||||
| 	do := state.Do() | ||||
|  | ||||
| 	if !z.NoReload { | ||||
| 		z.reloadMu.RLock() | ||||
| 	} | ||||
| @@ -118,9 +123,9 @@ func (z *Zone) Lookup(qname string, qtype uint16, do bool) ([]dns.RR, []dns.RR, | ||||
| 	// Found entire name. | ||||
| 	if found && shot { | ||||
|  | ||||
| 		// DNAME... | ||||
| 		// DNAME...? | ||||
| 		if rrs := elem.Types(dns.TypeCNAME); len(rrs) > 0 && qtype != dns.TypeCNAME { | ||||
| 			return z.searchCNAME(elem, rrs, qtype, do) | ||||
| 			return z.searchCNAME(state, elem, rrs) | ||||
| 		} | ||||
|  | ||||
| 		rrs := elem.Types(qtype, qname) | ||||
| @@ -152,7 +157,7 @@ func (z *Zone) Lookup(qname string, qtype uint16, do bool) ([]dns.RR, []dns.RR, | ||||
| 		auth := []dns.RR{} | ||||
|  | ||||
| 		if rrs := wildElem.Types(dns.TypeCNAME, qname); len(rrs) > 0 { | ||||
| 			return z.searchCNAME(wildElem, rrs, qtype, do) | ||||
| 			return z.searchCNAME(state, wildElem, rrs) | ||||
| 		} | ||||
|  | ||||
| 		rrs := wildElem.Types(qtype, qname) | ||||
| @@ -251,7 +256,11 @@ func (z *Zone) ns(do bool) []dns.RR { | ||||
| 	return z.Apex.NS | ||||
| } | ||||
|  | ||||
| func (z *Zone) searchCNAME(elem *tree.Elem, rrs []dns.RR, qtype uint16, do bool) ([]dns.RR, []dns.RR, []dns.RR, Result) { | ||||
| func (z *Zone) searchCNAME(state request.Request, elem *tree.Elem, rrs []dns.RR) ([]dns.RR, []dns.RR, []dns.RR, Result) { | ||||
|  | ||||
| 	qtype := state.QType() | ||||
| 	do := state.Do() | ||||
|  | ||||
| 	if do { | ||||
| 		sigs := elem.Types(dns.TypeRRSIG) | ||||
| 		sigs = signatureForSubType(sigs, dns.TypeCNAME) | ||||
| @@ -260,8 +269,12 @@ func (z *Zone) searchCNAME(elem *tree.Elem, rrs []dns.RR, qtype uint16, do bool) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	elem, _ = z.Tree.Search(rrs[0].(*dns.CNAME).Target) | ||||
| 	targetName := rrs[0].(*dns.CNAME).Target | ||||
| 	elem, _ = z.Tree.Search(targetName) | ||||
| 	if elem == nil { | ||||
| 		if !dns.IsSubDomain(z.origin, targetName) { | ||||
| 			rrs = append(rrs, z.externalLookup(state, targetName, qtype)...) | ||||
| 		} | ||||
| 		return rrs, nil, nil, Success | ||||
| 	} | ||||
|  | ||||
| @@ -279,8 +292,14 @@ Redo: | ||||
| 				rrs = append(rrs, sigs...) | ||||
| 			} | ||||
| 		} | ||||
| 		elem, _ = z.Tree.Search(cname[0].(*dns.CNAME).Target) | ||||
| 		targetName := cname[0].(*dns.CNAME).Target | ||||
| 		elem, _ = z.Tree.Search(targetName) | ||||
| 		if elem == nil { | ||||
| 			if !dns.IsSubDomain(z.origin, targetName) { | ||||
| 				if !dns.IsSubDomain(z.origin, targetName) { | ||||
| 					rrs = append(rrs, z.externalLookup(state, targetName, qtype)...) | ||||
| 				} | ||||
| 			} | ||||
| 			return rrs, nil, nil, Success | ||||
| 		} | ||||
|  | ||||
| @@ -318,6 +337,15 @@ func cnameForType(targets []dns.RR, origQtype uint16) []dns.RR { | ||||
| 	return ret | ||||
| } | ||||
|  | ||||
| func (z *Zone) externalLookup(state request.Request, target string, qtype uint16) []dns.RR { | ||||
| 	m, e := z.Proxy.Lookup(state, target, qtype) | ||||
| 	if e != nil { | ||||
| 		// TODO(miek): debugMsg for this as well? Log? | ||||
| 		return nil | ||||
| 	} | ||||
| 	return m.Answer | ||||
| } | ||||
|  | ||||
| // signatureForSubType range through the signature and return the correct ones for the subtype. | ||||
| func signatureForSubType(rrs []dns.RR, subtype uint16) []dns.RR { | ||||
| 	sigs := []dns.RR{} | ||||
|   | ||||
| @@ -8,6 +8,7 @@ import ( | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/miekg/coredns/middleware/test" | ||||
| 	"github.com/miekg/coredns/request" | ||||
|  | ||||
| 	"github.com/miekg/dns" | ||||
| ) | ||||
| @@ -31,11 +32,17 @@ func TestZoneReload(t *testing.T) { | ||||
|  | ||||
| 	z.Reload() | ||||
|  | ||||
| 	if _, _, _, res := z.Lookup("miek.nl.", dns.TypeSOA, false); res != Success { | ||||
| 	r := new(dns.Msg) | ||||
| 	r.SetQuestion("miek.nl", dns.TypeSOA) | ||||
| 	state := request.Request{W: &test.ResponseWriter{}, Req: r} | ||||
| 	if _, _, _, res := z.Lookup(state, "miek.nl."); res != Success { | ||||
| 		t.Fatalf("failed to lookup, got %d", res) | ||||
| 	} | ||||
|  | ||||
| 	if _, _, _, res := z.Lookup("miek.nl.", dns.TypeNS, false); res != Success { | ||||
| 	r = new(dns.Msg) | ||||
| 	r.SetQuestion("miek.nl", dns.TypeNS) | ||||
| 	state = request.Request{W: &test.ResponseWriter{}, Req: r} | ||||
| 	if _, _, _, res := z.Lookup(state, "miek.nl."); res != Success { | ||||
| 		t.Fatalf("failed to lookup, got %d", res) | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -2,12 +2,14 @@ package file | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"path" | ||||
|  | ||||
| 	"github.com/miekg/coredns/core/dnsserver" | ||||
| 	"github.com/miekg/coredns/middleware" | ||||
| 	"github.com/miekg/coredns/middleware/pkg/dnsutil" | ||||
| 	"github.com/miekg/coredns/middleware/proxy" | ||||
|  | ||||
| 	"github.com/mholt/caddy" | ||||
| ) | ||||
| @@ -90,6 +92,7 @@ func fileParse(c *caddy.Controller) (Zones, error) { | ||||
| 			} | ||||
|  | ||||
| 			noReload := false | ||||
| 			prxy := proxy.Proxy{} | ||||
| 			for c.NextBlock() { | ||||
| 				t, _, e := TransferParse(c, false) | ||||
| 				if e != nil { | ||||
| @@ -98,6 +101,19 @@ func fileParse(c *caddy.Controller) (Zones, error) { | ||||
| 				switch c.Val() { | ||||
| 				case "no_reload": | ||||
| 					noReload = true | ||||
|  | ||||
| 				case "upstream": | ||||
| 					args := c.RemainingArgs() | ||||
| 					if len(args) == 0 { | ||||
| 						return Zones{}, c.ArgErr() | ||||
| 					} | ||||
| 					for i := 0; i < len(args); i++ { | ||||
| 						h, p, e := net.SplitHostPort(args[i]) | ||||
| 						if e != nil && p == "" { | ||||
| 							args[i] = h + ":53" | ||||
| 						} | ||||
| 					} | ||||
| 					prxy = proxy.New(args) | ||||
| 				} | ||||
|  | ||||
| 				for _, origin := range origins { | ||||
| @@ -105,6 +121,7 @@ func fileParse(c *caddy.Controller) (Zones, error) { | ||||
| 						z[origin].TransferTo = append(z[origin].TransferTo, t...) | ||||
| 					} | ||||
| 					z[origin].NoReload = noReload | ||||
| 					z[origin].Proxy = prxy | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|   | ||||
| @@ -9,6 +9,7 @@ import ( | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/miekg/coredns/middleware/file/tree" | ||||
| 	"github.com/miekg/coredns/middleware/proxy" | ||||
| 	"github.com/miekg/coredns/request" | ||||
|  | ||||
| 	"github.com/fsnotify/fsnotify" | ||||
| @@ -31,6 +32,7 @@ type Zone struct { | ||||
| 	NoReload       bool | ||||
| 	reloadMu       sync.RWMutex | ||||
| 	ReloadShutdown chan bool | ||||
| 	Proxy          proxy.Proxy // Proxy for looking up names during the resolution process | ||||
| } | ||||
|  | ||||
| // Apex contains the apex records of a zone: SOA, NS and their potential signatures. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user