middleware/{file, auto}: resolve external CNAMEs
Do the same thing as in etcd and give the option of externally resolving CNAME. This is needed when CoreDNS is a proxy as well is serving zones.
This commit is contained in:
parent
a8287bb04d
commit
0919216d3c
10 changed files with 125 additions and 7 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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, false, 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 {
|
||||
|
|
|
@ -35,8 +35,8 @@ etcd [ZONES...] {
|
|||
under the *first* zone specified.
|
||||
* **PATH** the path inside etcd. Defaults to "/skydns".
|
||||
* **ENDPOINT** the etcd endpoints. Defaults to "http://localhost:2397".
|
||||
* `upstream` upstream resolvers to be used resolve external names found in etcd (think CNAMEs)
|
||||
pointing to external names. If you want CoreDNS to act as a proxy for clients, you'll need to add
|
||||
* `upstream` defines upstream resolvers to be used resolve external names found (think CNAMEs)
|
||||
pointing to external names. If you want CoreDNS also to act as a proxy for clients, you'll need to add
|
||||
the proxy middleware.
|
||||
* `tls` followed the cert, key and the CA's cert filenames.
|
||||
* `debug` allows for debug queries. Prefix the name with `o-o.debug.` to retrieve extra information in the
|
||||
|
|
|
@ -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,59 @@ 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(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."),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const dbExampleCNAME = `
|
||||
$TTL 30M
|
||||
$ORIGIN example.org.
|
||||
|
@ -95,4 +155,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.`
|
||||
|
|
|
@ -2,6 +2,7 @@ package file
|
|||
|
||||
import (
|
||||
"github.com/miekg/coredns/middleware/file/tree"
|
||||
"github.com/miekg/coredns/request"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
@ -118,7 +119,7 @@ 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)
|
||||
}
|
||||
|
@ -260,8 +261,16 @@ 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)
|
||||
println(targetName)
|
||||
if elem == nil {
|
||||
if !dns.IsSubDomain(z.origin, targetName) {
|
||||
println(targetName, "is not a child of", z.origin)
|
||||
}
|
||||
st := request.Request{}
|
||||
z.Proxy.Lookup(st, targetName, qtype)
|
||||
|
||||
return rrs, nil, nil, Success
|
||||
}
|
||||
|
||||
|
@ -279,8 +288,12 @@ 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) {
|
||||
println(targetName, "is not a child of", z.origin)
|
||||
}
|
||||
return rrs, nil, nil, Success
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/miekg/coredns/core/dnsserver"
|
||||
"github.com/miekg/coredns/middleware"
|
||||
"github.com/miekg/coredns/middleware/proxy"
|
||||
|
||||
"github.com/mholt/caddy"
|
||||
)
|
||||
|
@ -90,6 +91,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 +100,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 +120,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.
|
||||
|
|
Loading…
Add table
Reference in a new issue