package dnsserver import ( "testing" "github.com/coredns/caddy/caddyfile" ) func TestHandler(t *testing.T) { tp := testPlugin{} c := testConfig("dns", tp) if _, err := NewServer("127.0.0.1:53", []*Config{c}); err != nil { t.Errorf("Expected no error for NewServer, got %s", err) } if h := c.Handler("local"); h != tp { t.Errorf("Expected testPlugin from Handler, got %T", h) } if h := c.Handler("nothing"); h != nil { t.Errorf("Expected nil from Handler, got %T", h) } } func TestHandlers(t *testing.T) { tp := testPlugin{} c := testConfig("dns", tp) if _, err := NewServer("127.0.0.1:53", []*Config{c}); err != nil { t.Errorf("Expected no error for NewServer, got %s", err) } hs := c.Handlers() if len(hs) != 1 || hs[0] != tp { 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, both not using bind, 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, one addressed - one not using bind, 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 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) } } } } func TestInspectServerBlocks(t *testing.T) { tests := []struct { name string serverBlocks []caddyfile.ServerBlock expectedServerBlocks []caddyfile.ServerBlock expectedConfigsLen int expectedZoneAddrs map[string]zoneAddr wantErr bool }{ { name: "simple dns", serverBlocks: []caddyfile.ServerBlock{ {Keys: []string{"example.org"}}, }, expectedServerBlocks: []caddyfile.ServerBlock{ {Keys: []string{"dns://example.org.:53"}}, }, expectedConfigsLen: 1, expectedZoneAddrs: map[string]zoneAddr{ "dns://example.org.:53": {Zone: "example.org.", Port: "53", Transport: "dns"}, }, }, { name: "dns with port", serverBlocks: []caddyfile.ServerBlock{ {Keys: []string{"example.org:1053"}}, }, expectedServerBlocks: []caddyfile.ServerBlock{ {Keys: []string{"dns://example.org.:1053"}}, }, expectedConfigsLen: 1, expectedZoneAddrs: map[string]zoneAddr{ "dns://example.org.:1053": {Zone: "example.org.", Port: "1053", Transport: "dns"}, }, }, { name: "tls", serverBlocks: []caddyfile.ServerBlock{ {Keys: []string{"tls://example.org"}}, }, expectedServerBlocks: []caddyfile.ServerBlock{ {Keys: []string{"tls://example.org.:853"}}, }, expectedConfigsLen: 1, expectedZoneAddrs: map[string]zoneAddr{ "tls://example.org.:853": {Zone: "example.org.", Port: "853", Transport: "tls"}, }, }, { name: "quic", serverBlocks: []caddyfile.ServerBlock{ {Keys: []string{"quic://example.org"}}, }, expectedServerBlocks: []caddyfile.ServerBlock{ {Keys: []string{"quic://example.org.:853"}}, }, expectedConfigsLen: 1, expectedZoneAddrs: map[string]zoneAddr{ "quic://example.org.:853": {Zone: "example.org.", Port: "853", Transport: "quic"}, }, }, { name: "grpc", serverBlocks: []caddyfile.ServerBlock{ {Keys: []string{"grpc://example.org"}}, }, expectedServerBlocks: []caddyfile.ServerBlock{ {Keys: []string{"grpc://example.org.:443"}}, }, expectedConfigsLen: 1, expectedZoneAddrs: map[string]zoneAddr{ "grpc://example.org.:443": {Zone: "example.org.", Port: "443", Transport: "grpc"}, }, }, { name: "https", serverBlocks: []caddyfile.ServerBlock{ {Keys: []string{"https://example.org."}}, }, expectedServerBlocks: []caddyfile.ServerBlock{ {Keys: []string{"https://example.org.:443"}}, }, expectedConfigsLen: 1, expectedZoneAddrs: map[string]zoneAddr{ "https://example.org.:443": {Zone: "example.org.", Port: "443", Transport: "https"}, }, }, { name: "multiple hosts same key", serverBlocks: []caddyfile.ServerBlock{ {Keys: []string{"example.org,example.com:1053"}}, }, expectedServerBlocks: []caddyfile.ServerBlock{ {Keys: []string{"dns://example.org,example.com.:1053"}}, }, expectedConfigsLen: 1, expectedZoneAddrs: map[string]zoneAddr{ "dns://example.org,example.com.:1053": {Zone: "example.org,example.com.", Port: "1053", Transport: "dns"}, }, }, { name: "multiple keys", serverBlocks: []caddyfile.ServerBlock{ {Keys: []string{"example.org", "example.com:1053"}}, }, expectedServerBlocks: []caddyfile.ServerBlock{ {Keys: []string{"dns://example.org.:53", "dns://example.com.:1053"}}, }, expectedConfigsLen: 2, expectedZoneAddrs: map[string]zoneAddr{ "dns://example.org.:53": {Zone: "example.org.", Port: "53", Transport: "dns"}, "dns://example.com.:1053": {Zone: "example.com.", Port: "1053", Transport: "dns"}, }, }, { name: "fqdn input", serverBlocks: []caddyfile.ServerBlock{ {Keys: []string{"example.org."}}, }, expectedServerBlocks: []caddyfile.ServerBlock{ {Keys: []string{"dns://example.org.:53"}}, }, expectedConfigsLen: 1, expectedZoneAddrs: map[string]zoneAddr{ "dns://example.org.:53": {Zone: "example.org.", Port: "53", Transport: "dns"}, }, }, { name: "multiple server blocks", serverBlocks: []caddyfile.ServerBlock{ {Keys: []string{"example.org"}}, {Keys: []string{"sub.example.org:1054"}}, }, expectedServerBlocks: []caddyfile.ServerBlock{ {Keys: []string{"dns://example.org.:53"}}, {Keys: []string{"dns://sub.example.org.:1054"}}, }, expectedConfigsLen: 2, expectedZoneAddrs: map[string]zoneAddr{ "dns://example.org.:53": {Zone: "example.org.", Port: "53", Transport: "dns"}, "dns://sub.example.org.:1054": {Zone: "sub.example.org.", Port: "1054", Transport: "dns"}, }, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { ctx := newContext(nil).(*dnsContext) processedBlocks, err := ctx.InspectServerBlocks("TestInspectServerBlocks", tc.serverBlocks) if (err != nil) != tc.wantErr { t.Fatalf("InspectServerBlocks() error = %v, wantErr %v", err, tc.wantErr) } if tc.wantErr { return } if len(processedBlocks) != len(tc.expectedServerBlocks) { t.Fatalf("Expected %d processed blocks, got %d", len(tc.expectedServerBlocks), len(processedBlocks)) } for i, block := range processedBlocks { expectedBlock := tc.expectedServerBlocks[i] if len(block.Keys) != len(expectedBlock.Keys) { t.Errorf("Block %d: expected %d keys, got %d. Expected: %v, Got: %v", i, len(expectedBlock.Keys), len(block.Keys), expectedBlock.Keys, block.Keys) continue } for j, key := range block.Keys { if key != expectedBlock.Keys[j] { t.Errorf("Block %d, Key %d: expected key '%s', got '%s'", i, j, expectedBlock.Keys[j], key) } } } if len(ctx.configs) != tc.expectedConfigsLen { t.Errorf("Expected %d configs to be created, got %d", tc.expectedConfigsLen, len(ctx.configs)) } if tc.expectedZoneAddrs != nil { configIndex := 0 for ib := range processedBlocks { for ik, key := range processedBlocks[ib].Keys { if configIndex >= len(ctx.configs) { t.Fatalf("Not enough configs stored, expected at least %d, processed block %d key %d", configIndex+1, ib, ik) } cfg := ctx.configs[configIndex] expectedZa, ok := tc.expectedZoneAddrs[key] if !ok { t.Errorf("No expected zoneAddr for processed key '%s'", key) continue } if cfg.Zone != expectedZa.Zone { t.Errorf("Config for key '%s': expected Zone '%s', got '%s'", key, expectedZa.Zone, cfg.Zone) } if cfg.Port != expectedZa.Port { t.Errorf("Config for key '%s': expected Port '%s', got '%s'", key, expectedZa.Port, cfg.Port) } if cfg.Transport != expectedZa.Transport { t.Errorf("Config for key '%s': expected Transport '%s', got '%s'", key, expectedZa.Transport, cfg.Transport) } if len(cfg.ListenHosts) != 1 || cfg.ListenHosts[0] != "" { t.Errorf("Config for key '%s': expected ListenHosts [''], got %v", key, cfg.ListenHosts) } configIndex++ } } } }) } }