Add notifies to master servers

This adds a bunch of supporting code to send notifies to a primary

name server.
This commit is contained in:
Miek Gieben 2016-04-03 07:37:41 +01:00
parent 4a2a95561f
commit 6ecbdef112
5 changed files with 60 additions and 12 deletions

View file

@ -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 {

View file

@ -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...]
}
~~~

View file

@ -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)
}

View file

@ -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
}

View file

@ -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)
}