diff options
Diffstat (limited to 'core/dnsserver')
-rw-r--r-- | core/dnsserver/address.go | 16 | ||||
-rw-r--r-- | core/dnsserver/address_test.go | 45 | ||||
-rw-r--r-- | core/dnsserver/config.go | 24 | ||||
-rw-r--r-- | core/dnsserver/register.go | 20 | ||||
-rw-r--r-- | core/dnsserver/register_test.go | 90 | ||||
-rw-r--r-- | core/dnsserver/server.go | 18 | ||||
-rw-r--r-- | core/dnsserver/server_test.go | 10 |
7 files changed, 204 insertions, 19 deletions
diff --git a/core/dnsserver/address.go b/core/dnsserver/address.go index e17c9c706..eb2d0f049 100644 --- a/core/dnsserver/address.go +++ b/core/dnsserver/address.go @@ -1,6 +1,7 @@ package dnsserver import ( + "fmt" "net" "strings" @@ -72,6 +73,21 @@ func normalizeZone(str string) (zoneAddr, error) { return zoneAddr{Zone: dns.Fqdn(host), Port: port, Transport: trans, IPNet: ipnet}, nil } +// SplitProtocolHostPort - split a full formed address like "dns://[::1}:53" into parts +func SplitProtocolHostPort(address string) (protocol string, ip string, port string, err error) { + parts := strings.Split(address, "://") + switch len(parts) { + case 1: + ip, port, err := net.SplitHostPort(parts[0]) + return "", ip, port, err + case 2: + ip, port, err := net.SplitHostPort(parts[1]) + return parts[0], ip, port, err + default: + return "", "", "", fmt.Errorf("provided value is not in an address format : %s", address) + } +} + // Supported transports. const ( TransportDNS = "dns" diff --git a/core/dnsserver/address_test.go b/core/dnsserver/address_test.go index 39e4e0501..33b8fd898 100644 --- a/core/dnsserver/address_test.go +++ b/core/dnsserver/address_test.go @@ -63,3 +63,48 @@ func TestNormalizeZoneReverse(t *testing.T) { } } } + +func TestSplitProtocolHostPort(t *testing.T) { + for i, test := range []struct { + input string + proto string + ip string + port string + shouldErr bool + }{ + {"dns://:53", "dns", "", "53", false}, + {"dns://127.0.0.1:4005", "dns", "127.0.0.1", "4005", false}, + {"[ffe0:34ab:1]:4005", "", "ffe0:34ab:1", "4005", false}, + + // port part is mandatory + {"dns://", "dns", "", "", true}, + {"dns://127.0.0.1", "dns", "127.0.0.1", "", true}, + // cannot be empty + {"", "", "", "", true}, + // invalid format with twice :// + {"dns://127.0.0.1://53", "", "", "", true}, + } { + proto, ip, port, err := SplitProtocolHostPort(test.input) + if test.shouldErr && err == nil { + t.Errorf("Test %d: (address = %s) expected error, but there wasn't any", i, test.input) + continue + } + if !test.shouldErr && err != nil { + t.Errorf("Test %d: (address = %s) expected no error, but there was one: %v", i, test.input, err) + continue + } + if err == nil || test.shouldErr { + continue + } + if proto != test.proto { + t.Errorf("Test %d: (address = %s) expected protocol with value %s but got %s", i, test.input, test.proto, proto) + } + if ip != test.ip { + t.Errorf("Test %d: (address = %s) expected ip with value %s but got %s", i, test.input, test.ip, ip) + } + if port != test.port { + t.Errorf("Test %d: (address = %s) expected port with value %s but got %s", i, test.input, test.port, port) + } + + } +} diff --git a/core/dnsserver/config.go b/core/dnsserver/config.go index 0f75a7f86..1e952b153 100644 --- a/core/dnsserver/config.go +++ b/core/dnsserver/config.go @@ -2,6 +2,7 @@ package dnsserver import ( "crypto/tls" + "net" "github.com/coredns/coredns/plugin" @@ -13,8 +14,9 @@ type Config struct { // The zone of the site. Zone string - // The hostname to bind listener to, defaults to the wildcard address - ListenHost string + // one or several hostnames to bind the server to. + // defaults to a single empty string that denote the wildcard address + ListenHosts []string // The port to listen on. Port string @@ -50,6 +52,22 @@ type Config struct { registry map[string]plugin.Handler } +//HostAddresses builds a representation of the addresses of this Config +//after server is started ONLY, can be used as a Key for identifing that config +// :53 or 127.0.0.1:53 or 127.0.0.1:53/::1:53 +func (c *Config) HostAddresses() string { + all := "" + for _, h := range c.ListenHosts { + addr := net.JoinHostPort(h, c.Port) + if all == "" { + all = addr + continue + } + all = all + "/" + addr + } + return all +} + // GetConfig gets the Config that corresponds to c. // If none exist nil is returned. func GetConfig(c *caddy.Controller) *Config { @@ -60,6 +78,6 @@ func GetConfig(c *caddy.Controller) *Config { // we should only get here during tests because directive // actions typically skip the server blocks where we make // the configs. - ctx.saveConfig(c.Key, &Config{}) + ctx.saveConfig(c.Key, &Config{ListenHosts: []string{""}}) return GetConfig(c) } diff --git a/core/dnsserver/register.go b/core/dnsserver/register.go index 558d20f68..058ed1079 100644 --- a/core/dnsserver/register.go +++ b/core/dnsserver/register.go @@ -70,9 +70,10 @@ func (h *dnsContext) InspectServerBlocks(sourceFile string, serverBlocks []caddy // Save the config to our master list, and key it for lookups. cfg := &Config{ - Zone: za.Zone, - Port: za.Port, - Transport: za.Transport, + Zone: za.Zone, + Port: za.Port, + Transport: za.Transport, + ListenHosts: []string{""}, } if za.IPNet == nil { h.saveConfig(za.String(), cfg) @@ -191,14 +192,15 @@ func groupConfigsByListenAddr(configs []*Config) (map[string][]*Config, error) { groups := make(map[string][]*Config) for _, conf := range configs { - addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(conf.ListenHost, conf.Port)) - if err != nil { - return nil, err + for _, h := range conf.ListenHosts { + addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(h, conf.Port)) + if err != nil { + return nil, err + } + addrstr := conf.Transport + "://" + addr.String() + groups[addrstr] = append(groups[addrstr], conf) } - addrstr := conf.Transport + "://" + addr.String() - groups[addrstr] = append(groups[addrstr], conf) } - return groups, nil } diff --git a/core/dnsserver/register_test.go b/core/dnsserver/register_test.go index d01b90622..626fdc710 100644 --- a/core/dnsserver/register_test.go +++ b/core/dnsserver/register_test.go @@ -29,3 +29,93 @@ func TestHandlers(t *testing.T) { t.Errorf("Expected [testPlugin] from Handlers, got %v", hs) } } + +func TestGroupingServers(t *testing.T) { + for i, test := range []struct { + configs []*Config + expectedGroups []string + failing bool + }{ + // single config -> one group + {configs: []*Config{ + {Transport: "dns", Zone: ".", Port: "53", ListenHosts: []string{""}}, + }, + expectedGroups: []string{"dns://:53"}, + failing: false}, + + // 2 configs on different port -> 2 groups + {configs: []*Config{ + {Transport: "dns", Zone: ".", Port: "53", ListenHosts: []string{""}}, + {Transport: "dns", Zone: ".", Port: "54", ListenHosts: []string{""}}, + }, + expectedGroups: []string{"dns://:53", "dns://:54"}, + failing: false}, + + // 2 configs on same port, same broadcast address, diff zones -> 1 group + {configs: []*Config{ + {Transport: "dns", Zone: ".", Port: "53", ListenHosts: []string{""}}, + {Transport: "dns", Zone: "com.", Port: "53", ListenHosts: []string{""}}, + }, + expectedGroups: []string{"dns://:53"}, + failing: false}, + + // 2 configs on same port, same address, diff zones -> 1 group + {configs: []*Config{ + {Transport: "dns", Zone: ".", Port: "53", ListenHosts: []string{"127.0.0.1"}}, + {Transport: "dns", Zone: ".", Port: "54", ListenHosts: []string{""}}, + }, + expectedGroups: []string{"dns://127.0.0.1:53", "dns://:54"}, + failing: false}, + + // 2 configs on diff ports, 3 different address, diff zones -> 3 group + {configs: []*Config{ + {Transport: "dns", Zone: ".", Port: "53", ListenHosts: []string{"127.0.0.1", "::1"}}, + {Transport: "dns", Zone: ".", Port: "54", ListenHosts: []string{""}}}, + expectedGroups: []string{"dns://127.0.0.1:53", "dns://[::1]:53", "dns://:54"}, + failing: false}, + + // 2 configs on same port, same unicast address, diff zones -> 1 group + {configs: []*Config{ + {Transport: "dns", Zone: ".", Port: "53", ListenHosts: []string{"127.0.0.1", "::1"}}, + {Transport: "dns", Zone: "com.", Port: "53", ListenHosts: []string{"127.0.0.1", "::1"}}, + }, + expectedGroups: []string{"dns://127.0.0.1:53", "dns://[::1]:53"}, + failing: false}, + + // 2 configs on same port, total 2 diff addresses, diff zones -> 2 groups + {configs: []*Config{ + {Transport: "dns", Zone: ".", Port: "53", ListenHosts: []string{"127.0.0.1"}}, + {Transport: "dns", Zone: "com.", Port: "53", ListenHosts: []string{"::1"}}, + }, + expectedGroups: []string{"dns://127.0.0.1:53", "dns://[::1]:53"}, + failing: false}, + + // 2 configs on same port, total 3 diff addresses, diff zones -> 3 groups + {configs: []*Config{ + {Transport: "dns", Zone: ".", Port: "53", ListenHosts: []string{"127.0.0.1", "::1"}}, + {Transport: "dns", Zone: "com.", Port: "53", ListenHosts: []string{""}}}, + expectedGroups: []string{"dns://127.0.0.1:53", "dns://[::1]:53", "dns://:53"}, + failing: false}, + } { + groups, err := groupConfigsByListenAddr(test.configs) + if err != nil { + if !test.failing { + t.Fatalf("test %d, expected no errors, but got: %v", i, err) + } + continue + } + if test.failing { + t.Fatalf("test %d, expected to failed but did not, returned values", i) + } + if len(groups) != len(test.expectedGroups) { + t.Errorf("test %d : expected the group's size to be %d, was %d", i, len(test.expectedGroups), len(groups)) + continue + } + for _, v := range test.expectedGroups { + if _, ok := groups[v]; !ok { + t.Errorf("test %d : expected value %v to be in the group, was not", i, v) + + } + } + } +} diff --git a/core/dnsserver/server.go b/core/dnsserver/server.go index db5ef88b4..a08802204 100644 --- a/core/dnsserver/server.go +++ b/core/dnsserver/server.go @@ -287,8 +287,22 @@ func (s *Server) OnStartupComplete() { return } - for zone, config := range s.zones { - fmt.Println(zone + ":" + config.Port) + for zone := range s.zones { + // split addr into protocol, IP and Port + _, ip, port, err := SplitProtocolHostPort(s.Addr) + + if err != nil { + // this should not happen, but we need to take care of it anyway + fmt.Println(zone + ":" + s.Addr) + return + } + if ip == "" { + fmt.Println(zone + ":" + port) + return + } + // if the server is listening on a specific address let's make it visible in the log, + // so one can differentiate between all active listeners + fmt.Println(zone + ":" + port + " on " + ip) } } diff --git a/core/dnsserver/server_test.go b/core/dnsserver/server_test.go index 75f5b98f7..a7e663399 100644 --- a/core/dnsserver/server_test.go +++ b/core/dnsserver/server_test.go @@ -20,11 +20,11 @@ func (tp testPlugin) Name() string { return "testplugin" } func testConfig(transport string, p plugin.Handler) *Config { c := &Config{ - Zone: "example.com.", - Transport: transport, - ListenHost: "127.0.0.1", - Port: "53", - Debug: false, + Zone: "example.com.", + Transport: transport, + ListenHosts: []string{"127.0.0.1"}, + Port: "53", + Debug: false, } c.AddPlugin(func(next plugin.Handler) plugin.Handler { return p }) |