aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Miek Gieben <miek@miek.nl> 2016-11-24 21:51:38 +0100
committerGravatar Miek Gieben <miek@miek.nl> 2016-11-24 21:51:38 +0100
commita951fee29119eea54bc12113737849731d1a7b82 (patch)
treef6d20f592c73e113d5ef38e2efbc3b0e8af3f3bd
parent4a8db8a4cebce229fc46d331b68c850e8ba9b717 (diff)
parent8dd47dd9327428fdd845c0935b6168af5101edd1 (diff)
downloadcoredns-a951fee29119eea54bc12113737849731d1a7b82.tar.gz
coredns-a951fee29119eea54bc12113737849731d1a7b82.tar.zst
coredns-a951fee29119eea54bc12113737849731d1a7b82.zip
merge conflict fixed
-rw-r--r--middleware/auto/README.md6
-rw-r--r--middleware/auto/auto.go4
-rw-r--r--middleware/auto/setup.go15
-rw-r--r--middleware/auto/setup_test.go1
-rw-r--r--middleware/auto/walk.go1
-rw-r--r--middleware/etcd/setup_test.go2
-rw-r--r--middleware/file/README.md3
-rw-r--r--middleware/file/cname_test.go65
-rw-r--r--middleware/file/file.go2
-rw-r--r--middleware/file/lookup.go42
-rw-r--r--middleware/file/reload_test.go11
-rw-r--r--middleware/file/setup.go17
-rw-r--r--middleware/file/zone.go2
13 files changed, 158 insertions, 13 deletions
diff --git a/middleware/auto/README.md b/middleware/auto/README.md
index 94a606708..64807b821 100644
--- a/middleware/auto/README.md
+++ b/middleware/auto/README.md
@@ -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:
diff --git a/middleware/auto/auto.go b/middleware/auto/auto.go
index eaff7fd18..115e86dea 100644
--- a/middleware/auto/auto.go
+++ b/middleware/auto/auto.go
@@ -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)
diff --git a/middleware/auto/setup.go b/middleware/auto/setup.go
index 7681ea957..bf72f4549 100644
--- a/middleware/auto/setup.go
+++ b/middleware/auto/setup.go
@@ -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 {
diff --git a/middleware/auto/setup_test.go b/middleware/auto/setup_test.go
index f0368ff6e..3d65a4a86 100644
--- a/middleware/auto/setup_test.go
+++ b/middleware/auto/setup_test.go
@@ -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"},
},
diff --git a/middleware/auto/walk.go b/middleware/auto/walk.go
index a66259728..faea1b74a 100644
--- a/middleware/auto/walk.go
+++ b/middleware/auto/walk.go
@@ -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)
diff --git a/middleware/etcd/setup_test.go b/middleware/etcd/setup_test.go
index 6e1eabdcd..c1e33109c 100644
--- a/middleware/etcd/setup_test.go
+++ b/middleware/etcd/setup_test.go
@@ -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"
)
diff --git a/middleware/file/README.md b/middleware/file/README.md
index 4cc27e2de..283986945 100644
--- a/middleware/file/README.md
+++ b/middleware/file/README.md
@@ -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
diff --git a/middleware/file/cname_test.go b/middleware/file/cname_test.go
index 800020068..2eb7e073f 100644
--- a/middleware/file/cname_test.go
+++ b/middleware/file/cname_test.go
@@ -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"
@@ -69,6 +70,12 @@ var cnameTestCases = []test.Case{
},
},
{
+ 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{
test.A("a.example.org. 1800 IN A 127.0.0.1"),
@@ -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.`
diff --git a/middleware/file/file.go b/middleware/file/file.go
index 3f16a956e..6a171740f 100644
--- a/middleware/file/file.go
+++ b/middleware/file/file.go
@@ -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)
diff --git a/middleware/file/lookup.go b/middleware/file/lookup.go
index c47f1f5fa..c3dc8ad1c 100644
--- a/middleware/file/lookup.go
+++ b/middleware/file/lookup.go
@@ -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{}
diff --git a/middleware/file/reload_test.go b/middleware/file/reload_test.go
index c46dc3e20..caa81b536 100644
--- a/middleware/file/reload_test.go
+++ b/middleware/file/reload_test.go
@@ -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)
}
diff --git a/middleware/file/setup.go b/middleware/file/setup.go
index e358558e0..6ae6fc8c4 100644
--- a/middleware/file/setup.go
+++ b/middleware/file/setup.go
@@ -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
}
}
}
diff --git a/middleware/file/zone.go b/middleware/file/zone.go
index 21571287d..0c0df1a1f 100644
--- a/middleware/file/zone.go
+++ b/middleware/file/zone.go
@@ -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.