aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--middleware/file/README.md3
-rw-r--r--middleware/file/notify.go11
-rw-r--r--middleware/file/secondary.go7
-rw-r--r--middleware/file/xfr.go2
-rw-r--r--middleware/file/zone.go14
-rw-r--r--middleware/secondary/README.md6
-rw-r--r--middleware/secondary/setup.go14
-rw-r--r--test/secondary_net_test.go126
8 files changed, 171 insertions, 12 deletions
diff --git a/middleware/file/README.md b/middleware/file/README.md
index 283986945..30391ed47 100644
--- a/middleware/file/README.md
+++ b/middleware/file/README.md
@@ -38,7 +38,8 @@ file DBFILE [ZONES... ] {
* `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.
+ pointing to external names. This is only really useful when CoreDNS is configured as a proxy, for
+ normal authoritative serving you don't need *or* want to use this.
## Examples
diff --git a/middleware/file/notify.go b/middleware/file/notify.go
index 90dfdc521..e8f518d25 100644
--- a/middleware/file/notify.go
+++ b/middleware/file/notify.go
@@ -3,8 +3,8 @@ package file
import (
"fmt"
"log"
+ "net"
- "github.com/coredns/coredns/middleware"
"github.com/coredns/coredns/middleware/pkg/rcode"
"github.com/coredns/coredns/request"
@@ -21,8 +21,13 @@ func (z *Zone) isNotify(state request.Request) bool {
if len(z.TransferFrom) == 0 {
return false
}
- remote := middleware.Addr(state.IP()).Normalize()
- for _, from := range z.TransferFrom {
+ // If remote IP matches we accept.
+ remote := state.IP()
+ for _, f := range z.TransferFrom {
+ from, _, err := net.SplitHostPort(f)
+ if err != nil {
+ continue
+ }
if from == remote {
return true
}
diff --git a/middleware/file/secondary.go b/middleware/file/secondary.go
index 70ec217f7..e371600e9 100644
--- a/middleware/file/secondary.go
+++ b/middleware/file/secondary.go
@@ -26,19 +26,19 @@ Transfer:
t := new(dns.Transfer)
c, err := t.In(m, tr)
if err != nil {
- log.Printf("[ERROR] Failed to setup transfer `%s' with `%s': %v", z.origin, tr, err)
+ log.Printf("[ERROR] Failed to setup transfer `%s' with `%q': %v", z.origin, tr, err)
Err = err
continue Transfer
}
for env := range c {
if env.Error != nil {
- log.Printf("[ERROR] Failed to parse transfer `%s': %v", z.origin, env.Error)
+ log.Printf("[ERROR] Failed to transfer `%s' from %q: %v", z.origin, tr, env.Error)
Err = env.Error
continue Transfer
}
for _, rr := range env.RR {
if err := z1.Insert(rr); err != nil {
- log.Printf("[ERROR] Failed to parse transfer `%s': %v", z.origin, err)
+ log.Printf("[ERROR] Failed to parse transfer `%s' from: %q: %v", z.origin, tr, err)
Err = err
continue Transfer
}
@@ -48,7 +48,6 @@ Transfer:
break
}
if Err != nil {
- log.Printf("[ERROR] Failed to transfer %s: %s", z.origin, Err)
return Err
}
diff --git a/middleware/file/xfr.go b/middleware/file/xfr.go
index 4d7f07a48..54f7b71f8 100644
--- a/middleware/file/xfr.go
+++ b/middleware/file/xfr.go
@@ -57,6 +57,6 @@ func (x Xfr) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (in
}
// Name implements the middleware.Hander interface.
-func (x Xfr) Name() string { return "xfr" } // Or should we return "file" here?
+func (x Xfr) Name() string { return "xfr" }
const transferLength = 1000 // Start a new envelop after message reaches this size in bytes. Intentionally small to test multi envelope parsing.
diff --git a/middleware/file/zone.go b/middleware/file/zone.go
index 7592798f0..a216f8af8 100644
--- a/middleware/file/zone.go
+++ b/middleware/file/zone.go
@@ -2,6 +2,7 @@ package file
import (
"fmt"
+ "net"
"path"
"strings"
"sync"
@@ -55,12 +56,12 @@ func NewZone(name, file string) *Zone {
return z
}
-// Copy copies a zone *without* copying the zone's content. It is not a deep copy.
func (z *Zone) Copy() *Zone {
z1 := NewZone(z.origin, z.file)
z1.TransferTo = z.TransferTo
z1.TransferFrom = z.TransferFrom
z1.Expired = z.Expired
+
z1.Apex = z.Apex
return z1
}
@@ -113,11 +114,20 @@ func (z *Zone) Insert(r dns.RR) error {
func (z *Zone) Delete(r dns.RR) { z.Tree.Delete(r) }
// TransferAllowed checks if incoming request for transferring the zone is allowed according to the ACLs.
-func (z *Zone) TransferAllowed(req request.Request) bool {
+func (z *Zone) TransferAllowed(state request.Request) bool {
for _, t := range z.TransferTo {
if t == "*" {
return true
}
+ // If remote IP matches we accept.
+ remote := state.IP()
+ to, _, err := net.SplitHostPort(t)
+ if err != nil {
+ continue
+ }
+ if to == remote {
+ return true
+ }
}
// TODO(miek): future matching against IP/CIDR notations
return false
diff --git a/middleware/secondary/README.md b/middleware/secondary/README.md
index 559a06717..e37555211 100644
--- a/middleware/secondary/README.md
+++ b/middleware/secondary/README.md
@@ -16,13 +16,17 @@ A working syntax would be:
~~~
secondary [zones...] {
transfer from ADDRESS
- [transfer to ADDRESS]
+ transfer to ADDRESS
+ upstream ADDRESS...
}
~~~
* `transfer from` specifies from which address to fetch the zone. It can be specified multiple times;
if one does not work, another will be tried.
* `transfer to` can be enabled to allow this secondary zone to be transferred again.
+* `upstream` defines upstream resolvers to be used resolve external names found (think CNAMEs)
+ pointing to external names. This is only really useful when CoreDNS is configured as a proxy, for
+ normal authoritative serving you don't need *or* want to use this.
## Examples
diff --git a/middleware/secondary/setup.go b/middleware/secondary/setup.go
index 8a40a6710..901e76699 100644
--- a/middleware/secondary/setup.go
+++ b/middleware/secondary/setup.go
@@ -4,6 +4,8 @@ import (
"github.com/coredns/coredns/core/dnsserver"
"github.com/coredns/coredns/middleware"
"github.com/coredns/coredns/middleware/file"
+ "github.com/coredns/coredns/middleware/pkg/dnsutil"
+ "github.com/coredns/coredns/middleware/proxy"
"github.com/mholt/caddy"
)
@@ -47,6 +49,7 @@ func secondaryParse(c *caddy.Controller) (file.Zones, error) {
z := make(map[string]*file.Zone)
names := []string{}
origins := []string{}
+ prxy := proxy.Proxy{}
for c.Next() {
if c.Val() == "secondary" {
@@ -74,6 +77,16 @@ func secondaryParse(c *caddy.Controller) (file.Zones, error) {
if e != nil {
return file.Zones{}, e
}
+ case "upstream":
+ args := c.RemainingArgs()
+ if len(args) == 0 {
+ return file.Zones{}, c.ArgErr()
+ }
+ ups, err := dnsutil.ParseHostPortOrFile(args...)
+ if err != nil {
+ return file.Zones{}, err
+ }
+ prxy = proxy.NewLookup(ups)
}
for _, origin := range origins {
@@ -83,6 +96,7 @@ func secondaryParse(c *caddy.Controller) (file.Zones, error) {
if f != nil {
z[origin].TransferFrom = append(z[origin].TransferFrom, f...)
}
+ z[origin].Proxy = prxy
}
}
}
diff --git a/test/secondary_net_test.go b/test/secondary_net_test.go
new file mode 100644
index 000000000..451195442
--- /dev/null
+++ b/test/secondary_net_test.go
@@ -0,0 +1,126 @@
+// +build net
+
+package test
+
+import (
+ "testing"
+
+ "github.com/miekg/dns"
+)
+
+func TestSecondaryZoneTransfer(t *testing.T) {
+ /*
+ Test will only work when there is a CoreDNS running on part 32054
+ with example.com and willing to transfer
+ coredns -conf Corefile -dns.port 32054
+ Corefile:
+ example.com {
+ file example.com {
+ transfer to 127.0.0.1:32053
+ }
+ }
+ example.com:
+ example.com. 3600 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2017042730 7200 3600 1209600 3600
+
+ example.com. 65118 IN NS a.iana-servers.net.
+ example.com. 65118 IN NS b.iana-servers.net.
+ cname.example.com. 434334 IN CNAME a.miek.nl.
+ */
+
+ corefile := `example.com:32053 {
+ secondary {
+ transfer from 127.0.0.1:32054
+ }
+ }
+ `
+
+ sec, err := CoreDNSServer(corefile)
+ if err != nil {
+ t.Fatalf("Could not get CoreDNS serving instance: %s", err)
+ }
+
+ defer sec.Stop()
+
+ m := new(dns.Msg)
+ m.SetQuestion("cname.example.com.", dns.TypeCNAME)
+
+ r, err := dns.Exchange(m, "127.0.0.1:32053")
+ if err != nil {
+ t.Fatalf("Expected to receive reply, but didn't: %s", err)
+ }
+
+ if len(r.Answer) == 0 {
+ t.Fatalf("Expected answer section")
+ }
+
+ if r.Answer[0].(*dns.CNAME).Target != "a.miek.nl." {
+ t.Fatalf("Expected target of %s, got %s", "a.miek.nl.", r.Answer[0].(*dns.CNAME).Target)
+ }
+
+ m = new(dns.Msg)
+ m.SetQuestion("example.com.", dns.TypeSOA)
+ r, err = dns.Exchange(m, "127.0.0.1:32053")
+ if err != nil {
+ t.Fatalf("Expected to receive reply, but didn't: %s", err)
+ }
+ if len(r.Answer) == 0 {
+ t.Fatalf("Expected answer section")
+ }
+ if r.Answer[0].(*dns.SOA).Serial != 2017042730 {
+ t.Fatalf("Expected serial of %d, got %d", 2017042730, r.Answer[0].(*dns.SOA).Serial)
+ }
+}
+
+func TestSecondaryZoneTransferUpstream(t *testing.T) {
+ /*
+ Test will only work when there is a CoreDNS running on part 32054
+ with example.com and willing to transfer
+ coredns -conf Corefile -dns.port 32054
+ Corefile:
+ example.com {
+ file example.com {
+ transfer to 127.0.0.1:32053
+ }
+ }
+ example.com:
+ example.com. 3600 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2017042730 7200 3600 1209600 3600
+
+ example.com. 65118 IN NS a.iana-servers.net.
+ example.com. 65118 IN NS b.iana-servers.net.
+ cname.example.com. 434334 IN CNAME a.miek.nl.
+ */
+
+ corefile := `example.com:32053 {
+ secondary {
+ transfer from 127.0.0.1:32054
+ upstream 8.8.8.8
+ }
+ }
+ `
+
+ sec, err := CoreDNSServer(corefile)
+ if err != nil {
+ t.Fatalf("Could not get CoreDNS serving instance: %s", err)
+ }
+
+ defer sec.Stop()
+
+ m := new(dns.Msg)
+ m.SetQuestion("cname.example.com.", dns.TypeA)
+
+ r, err := dns.Exchange(m, "127.0.0.1:32053")
+ if err != nil {
+ t.Fatalf("Expected to receive reply, but didn't: %s", err)
+ }
+
+ if len(r.Answer) != 2 {
+ t.Fatalf("Expected answer section, with 2 records, got %d", len(r.Answer))
+ }
+
+ if r.Answer[0].(*dns.CNAME).Target != "a.miek.nl." {
+ t.Fatalf("Expected target of %s, got %s", "a.miek.nl.", r.Answer[0].(*dns.CNAME).Target)
+ }
+ if r.Answer[1].Header().Name != "a.miek.nl." {
+ t.Fatalf("Expected name of %s, got %s", "a.miek.nl.", r.Answer[1].Header().Name)
+ }
+}