From 6ecbdef112b3bf0759a60914d0eb08540c5274ed Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Sun, 3 Apr 2016 07:37:41 +0100 Subject: [PATCH] Add notifies to master servers This adds a bunch of supporting code to send notifies to a primary name server. --- core/setup/file.go | 4 +++- middleware/file/README.md | 4 +++- middleware/file/notify.go | 39 +++++++++++++++++++++++++++++++++++---- middleware/file/zone.go | 3 +-- middleware/host.go | 22 ++++++++++++++++++---- 5 files changed, 60 insertions(+), 12 deletions(-) diff --git a/core/setup/file.go b/core/setup/file.go index 7128b77aa..aca9f8f9f 100644 --- a/core/setup/file.go +++ b/core/setup/file.go @@ -13,6 +13,8 @@ func File(c *Controller) (middleware.Middleware, error) { if err != nil { return nil, err } + // Set start function is transfer is specified + return func(next middleware.Handler) middleware.Handler { return file.File{Next: next, Zones: zones} }, nil @@ -35,7 +37,7 @@ func fileParse(c *Controller) (file.Zones, error) { origin = c.Val() } // normalize this origin - origin = middleware.Host(origin).StandardHost() + origin = middleware.Host(origin).Standard() reader, err := os.Open(fileName) if err != nil { diff --git a/middleware/file/README.md b/middleware/file/README.md index bd9a24d1e..407c1119c 100644 --- a/middleware/file/README.md +++ b/middleware/file/README.md @@ -17,9 +17,11 @@ 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. + ~~~ file dbfile [zones... ] { - transfer in|out + transfer out [address...] } ~~~ diff --git a/middleware/file/notify.go b/middleware/file/notify.go index cb61cc050..58cc66e79 100644 --- a/middleware/file/notify.go +++ b/middleware/file/notify.go @@ -1,8 +1,39 @@ package file -// Notify sends notifies to the configured remotes. It will try up to three times -// before giving up on a specific remote. -func Notify(remotes []string) error { - return nil +import ( + "fmt" + "github.com/miekg/coredns/middleware" + "github.com/miekg/dns" +) + +// Notify will send notifies to all configured IP addresses. +func (z *Zone) Notify() { + go notify(z.name, z.Peers) +} + +// 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 +// until they all have replied (or have 3 failed attempts). +func notify(zone string, remotes []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()) + } + return nil +} + +func notifyRemote(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 + } + return fmt.Errorf("failed to send notify for zone '%s' to '%s'", m.Question[0].Name, s) } diff --git a/middleware/file/zone.go b/middleware/file/zone.go index 1547a23b4..8c56b6bf9 100644 --- a/middleware/file/zone.go +++ b/middleware/file/zone.go @@ -10,7 +10,6 @@ import ( type Transfer struct { Out bool In bool - // more later? } type Zone struct { @@ -18,7 +17,7 @@ type Zone struct { SIG []dns.RR name string *tree.Tree - Masters []string + Peers []string Transfer *Transfer } diff --git a/middleware/host.go b/middleware/host.go index 17ecedb5f..7b9b9a42a 100644 --- a/middleware/host.go +++ b/middleware/host.go @@ -7,12 +7,15 @@ import ( "github.com/miekg/dns" ) -// Host represents a host from the Caddyfile, may contain port. -type Host string +// Host represents a host from the Corefile, may contain port. +type ( + Host string + Addr string +) -// Standard host will return the host portion of host, stripping +// Standard will return the host portion of host, stripping // of any port. The host will also be fully qualified and lowercased. -func (h Host) StandardHost() string { +func (h Host) Standard() string { // separate host and port host, _, err := net.SplitHostPort(string(h)) if err != nil { @@ -20,3 +23,14 @@ func (h Host) StandardHost() string { } return strings.ToLower(dns.Fqdn(host)) } + +// Standard will return a normalized address, if not port is specified +// port 53 is added, otherwise the port will be left as is. +func (a Addr) Standard() string { + // separate host and port + addr, port, err := net.SplitHostPort(string(a)) + if err != nil { + addr, port, _ = net.SplitHostPort(string(a) + ":53") + } + return net.JoinHostPort(addr, port) +}