aboutsummaryrefslogtreecommitdiff
path: root/middleware
diff options
context:
space:
mode:
Diffstat (limited to 'middleware')
-rw-r--r--middleware/file/README.md23
-rw-r--r--middleware/file/file.go6
-rw-r--r--middleware/file/lookup_test.go9
-rw-r--r--middleware/file/notify.go16
-rw-r--r--middleware/file/secondary.go63
-rw-r--r--middleware/file/xfr.go4
-rw-r--r--middleware/file/zone.go27
-rw-r--r--middleware/secondary/README.md34
-rw-r--r--middleware/secondary/secondary.go7
9 files changed, 159 insertions, 30 deletions
diff --git a/middleware/file/README.md b/middleware/file/README.md
index 407c1119c..36b76a1aa 100644
--- a/middleware/file/README.md
+++ b/middleware/file/README.md
@@ -1,9 +1,9 @@
# file
-`file` enabled reading zone data from a RFC-1035 styled file.
+`file` enables serving zone data from a RFC-1035 styled file.
-The etcd middleware makes extensive use of the proxy middleware to forward and query
-other servers in the network.
+The file middleware is used for "old-style" DNS server. It serves from a preloaded file that exists
+on disk.
## Syntax
@@ -17,15 +17,26 @@ file dbfile [zones...]
If you want to round robin A and AAAA responses look at the `loadbalance` middleware.
-TSIG key configuration is TODO; directive format will change.
+TSIG key configuration is TODO; directive format for transfer will probably be extended with
+TSIG key information, something like `transfer out [address] key [name] [base64]`
~~~
file dbfile [zones... ] {
transfer out [address...]
+ transfer to [address]
}
~~~
-* `transfer` enable zone transfers, for now only `transfer out` does something. It enables outgoing
- zone transfers when defined.
+* `transfer` enables zone transfers. It may be specified multiples times. *To* or *from* signals
+ the direction. Address must be denoted in CIDR notation (127.0.0.1/32 etc.). The special
+ wildcard "*" means: the entire internet.
## Examples
+
+Load the `miek.nl` zone from `miek.nl.signed` and allow transfers to the internet.
+
+~~~
+file miek.nl.signed miek.nl {
+ transfer to *
+}
+~~~
diff --git a/middleware/file/file.go b/middleware/file/file.go
index c005b41cc..caf0c5fbc 100644
--- a/middleware/file/file.go
+++ b/middleware/file/file.go
@@ -33,6 +33,12 @@ func (f File) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
if !ok {
return f.Next.ServeDNS(ctx, w, r)
}
+ if z == nil {
+ return dns.RcodeServerFailure, nil
+ }
+ if z.Expired != nil && *z.Expired {
+ return dns.RcodeServerFailure, nil
+ }
if state.Proto() != "udp" && state.QType() == dns.TypeAXFR {
xfr := Xfr{z}
diff --git a/middleware/file/lookup_test.go b/middleware/file/lookup_test.go
index df65d0150..11ec5bab0 100644
--- a/middleware/file/lookup_test.go
+++ b/middleware/file/lookup_test.go
@@ -107,6 +107,15 @@ func TestLookup(t *testing.T) {
}
}
+func TestLookupNil(t *testing.T) {
+ fm := File{Next: coretest.ErrorHandler(), Zones: Zones{Z: map[string]*Zone{testzone: nil}, Names: []string{testzone}}}
+ ctx := context.TODO()
+
+ m := dnsTestCases[0].Msg()
+ rec := middleware.NewResponseRecorder(&middleware.TestResponseWriter{})
+ fm.ServeDNS(ctx, rec, m)
+}
+
func BenchmarkLookup(b *testing.B) {
zone, err := Parse(strings.NewReader(dbMiekNL), testzone, "stdin")
if err != nil {
diff --git a/middleware/file/notify.go b/middleware/file/notify.go
index cc8f493e4..bbdafe022 100644
--- a/middleware/file/notify.go
+++ b/middleware/file/notify.go
@@ -10,31 +10,31 @@ import (
// Notify will send notifies to all configured IP addresses.
func (z *Zone) Notify() {
- go notify(z.name, z.Peers)
+ go notify(z.name, z.TransferTo)
}
-// notify sends notifies to the configured remotes. It will try up to three times
-// before giving up on a specific remote. We will sequentially loop through the remotes
+// notify sends notifies to the configured remote servers. It will try up to three times
+// before giving up on a specific remote. We will sequentially loop through "to"
// until they all have replied (or have 3 failed attempts).
-func notify(zone string, remotes []string) error {
+func notify(zone string, to []string) error {
m := new(dns.Msg)
m.SetNotify(zone)
c := new(dns.Client)
// TODO(miek): error handling? Run this in a goroutine?
- for _, remote := range remotes {
- notifyRemote(c, m, middleware.Addr(remote).Standard())
+ for _, t := range to {
+ notifyAddr(c, m, t)
}
return nil
}
-func notifyRemote(c *dns.Client, m *dns.Msg, s string) error {
+func notifyAddr(c *dns.Client, m *dns.Msg, s string) error {
for i := 0; i < 3; i++ {
ret, err := middleware.Exchange(c, m, s)
if err == nil && ret.Rcode == dns.RcodeSuccess || ret.Rcode == dns.RcodeNotImplemented {
return nil
}
- // timeout? mean don't want it. should stop sending as well
+ // timeout? mean don't want it. should stop sending as well?
}
return fmt.Errorf("failed to send notify for zone '%s' to '%s'", m.Question[0].Name, s)
}
diff --git a/middleware/file/secondary.go b/middleware/file/secondary.go
new file mode 100644
index 000000000..95c063a9b
--- /dev/null
+++ b/middleware/file/secondary.go
@@ -0,0 +1,63 @@
+package file
+
+import (
+ "log"
+
+ "github.com/miekg/dns"
+)
+
+// TransferIn retrieves the zone from the masters, parses it and sets it live.
+func (z *Zone) TransferIn() error {
+ if len(z.TransferFrom) == 0 {
+ return nil
+ }
+ t := new(dns.Transfer)
+ m := new(dns.Msg)
+ m.SetAxfr(z.name)
+ /*
+ t.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
+ m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
+ */
+
+ var Err error
+Transfer:
+ for _, tr := range z.TransferFrom {
+ c, err := t.In(m, tr)
+ if err != nil {
+ log.Printf("[ERROR] failed to setup transfer %s with %s: %v", z.name, z.TransferFrom[0], err)
+ Err = err
+ continue Transfer
+ }
+ for env := range c {
+ if env.Error != nil {
+ log.Printf("[ERROR] failed to parse transfer %s: %v", z.name, env.Error)
+ Err = env.Error
+ continue Transfer
+ }
+ for _, rr := range env.RR {
+ if rr.Header().Rrtype == dns.TypeSOA {
+ z.SOA = rr.(*dns.SOA)
+ continue
+ }
+ if rr.Header().Rrtype == dns.TypeRRSIG {
+ if x, ok := rr.(*dns.RRSIG); ok && x.TypeCovered == dns.TypeSOA {
+ z.SIG = append(z.SIG, x)
+ }
+ }
+ z.Insert(rr)
+ }
+ }
+ }
+ return Err
+}
+
+/*
+
+ 28800 ; refresh (8 hours)
+ 7200 ; retry (2 hours)
+ 604800 ; expire (1 week)
+ 3600 ; minimum (1 hour)
+// Check SOA
+// Just check every refresh hours, if fail set to retry until succeeds
+// expire is need: to give SERVFAIL.
+*/
diff --git a/middleware/file/xfr.go b/middleware/file/xfr.go
index 297de2fc5..5ef205f6e 100644
--- a/middleware/file/xfr.go
+++ b/middleware/file/xfr.go
@@ -22,7 +22,7 @@ func (x Xfr) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (in
return dns.RcodeServerFailure, nil
}
if state.QType() != dns.TypeAXFR {
- return 0, fmt.Errorf("file: xfr called with non xfr type: %d", state.QType())
+ return 0, fmt.Errorf("file: xfr called with non transfer type: %d", state.QType())
}
if state.Proto() == "udp" {
return 0, fmt.Errorf("file: xfr called with udp")
@@ -39,7 +39,7 @@ func (x Xfr) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (in
go tr.Out(w, r, ch)
j, l := 0, 0
- records = append(records, records[0])
+ records = append(records, records[0]) // add closing SOA to the end
for i, r := range records {
l += dns.Len(r)
if l > transferLength {
diff --git a/middleware/file/zone.go b/middleware/file/zone.go
index 8c56b6bf9..c3567b45f 100644
--- a/middleware/file/zone.go
+++ b/middleware/file/zone.go
@@ -7,23 +7,22 @@ import (
"github.com/miekg/dns"
)
-type Transfer struct {
- Out bool
- In bool
-}
-
type Zone struct {
SOA *dns.SOA
SIG []dns.RR
name string
*tree.Tree
- Peers []string
- Transfer *Transfer
+
+ TransferTo []string
+ TransferFrom []string
+ Expired *bool
}
// NewZone returns a new zone.
func NewZone(name string) *Zone {
- return &Zone{name: dns.Fqdn(name), Tree: &tree.Tree{}, Transfer: &Transfer{}}
+ z := &Zone{name: dns.Fqdn(name), Tree: &tree.Tree{}, Expired: new(bool)}
+ *z.Expired = false
+ return z
}
// Insert inserts r into z.
@@ -32,12 +31,14 @@ func (z *Zone) Insert(r dns.RR) { z.Tree.Insert(r) }
// Delete deletes r from z.
func (z *Zone) Delete(r dns.RR) { z.Tree.Delete(r) }
-// It the transfer request allowed.
+// TransferAllowed checks if incoming request for transferring the zone is allowed according to the ACLs.
func (z *Zone) TransferAllowed(state middleware.State) bool {
- if z.Transfer == nil {
- return false
+ for _, t := range z.TransferTo {
+ if t == "*" {
+ return true
+ }
}
- return z.Transfer.Out
+ return false
}
// All returns all records from the zone, the first record will be the SOA record,
@@ -54,5 +55,3 @@ func (z *Zone) All() []dns.RR {
}
return append([]dns.RR{z.SOA}, records...)
}
-
-// Apex function?
diff --git a/middleware/secondary/README.md b/middleware/secondary/README.md
new file mode 100644
index 000000000..c2b1366e7
--- /dev/null
+++ b/middleware/secondary/README.md
@@ -0,0 +1,34 @@
+# secondary
+
+`secondary` enables serving a zone retrieved from a primary server.
+
+## Syntax
+
+~~~
+secondary [zones...]
+~~~
+
+* `zones` zones it should be authoritative for. If empty, the zones from the configuration block
+ are used. Not that with an remote address to *get* the zone the above is not that useful.
+
+A working syntax would be:
+
+~~~
+secondary [zones...] {
+ transfer from address
+ [transfer to address]
+}
+~~~
+
+* `transfer from` tell from which address to fetch the zone. It can be specified multiple time,
+ if one does not work another will be tried.
+* `transfer to` can be enabled to allow this secondary zone to be transfered again.
+
+## Examples
+
+~~~
+secondary [zones...] {
+ transfer from 10.0.1.1
+ transfer from 10.1.2.1
+}
+~~~
diff --git a/middleware/secondary/secondary.go b/middleware/secondary/secondary.go
new file mode 100644
index 000000000..60006b69c
--- /dev/null
+++ b/middleware/secondary/secondary.go
@@ -0,0 +1,7 @@
+package secondary
+
+import "github.com/miekg/coredns/middleware/file"
+
+type Secondary struct {
+ file.File
+}