// resolveCNAME is used to recursively resolve CNAME records func (d *DNSServer) resolveCNAME(name string) []dns.RR { // Do nothing if we don't have a recursor if len(d.recursors) == 0 { return nil } // Ask for any A records m := new(dns.Msg) m.SetQuestion(name, dns.TypeA) // Make a DNS lookup request c := &dns.Client{Net: "udp"} var r *dns.Msg var rtt time.Duration var err error for _, recursor := range d.recursors { r, rtt, err = c.Exchange(m, recursor) if err == nil { d.logger.Printf("[DEBUG] dns: cname recurse RTT for %v (%v)", name, rtt) return r.Answer } d.logger.Printf("[ERR] dns: cname recurse failed for %v: %v", name, err) } d.logger.Printf("[ERR] dns: all resolvers failed for %v", name) return nil }
func TestDNS_ServiceLookup_TagPeriod(t *testing.T) { dir, srv := makeDNSServer(t) defer os.RemoveAll(dir) defer srv.agent.Shutdown() testutil.WaitForLeader(t, srv.agent.RPC, "dc1") // Register node args := &structs.RegisterRequest{ Datacenter: "dc1", Node: "foo", Address: "127.0.0.1", Service: &structs.NodeService{ Service: "db", Tags: []string{"v1.master"}, Port: 12345, }, } var out struct{} if err := srv.agent.RPC("Catalog.Register", args, &out); err != nil { t.Fatalf("err: %v", err) } m := new(dns.Msg) m.SetQuestion("v1.master.db.service.consul.", dns.TypeSRV) c := new(dns.Client) addr, _ := srv.agent.config.ClientListener("", srv.agent.config.Ports.DNS) in, _, err := c.Exchange(m, addr.String()) if err != nil { t.Fatalf("err: %v", err) } if len(in.Answer) != 1 { t.Fatalf("Bad: %#v", in) } srvRec, ok := in.Answer[0].(*dns.SRV) if !ok { t.Fatalf("Bad: %#v", in.Answer[0]) } if srvRec.Port != 12345 { t.Fatalf("Bad: %#v", srvRec) } if srvRec.Target != "foo.node.dc1.consul." { t.Fatalf("Bad: %#v", srvRec) } aRec, ok := in.Extra[0].(*dns.A) if !ok { t.Fatalf("Bad: %#v", in.Extra[0]) } if aRec.Hdr.Name != "foo.node.dc1.consul." { t.Fatalf("Bad: %#v", in.Extra[0]) } if aRec.A.String() != "127.0.0.1" { t.Fatalf("Bad: %#v", in.Extra[0]) } }
func TestDNS_CaseInsensitiveNodeLookup(t *testing.T) { dir, srv := makeDNSServer(t) defer os.RemoveAll(dir) defer srv.agent.Shutdown() testutil.WaitForLeader(t, srv.agent.RPC, "dc1") // Register node args := &structs.RegisterRequest{ Datacenter: "dc1", Node: "Foo", Address: "127.0.0.1", } var out struct{} if err := srv.agent.RPC("Catalog.Register", args, &out); err != nil { t.Fatalf("err: %v", err) } m := new(dns.Msg) m.SetQuestion("fOO.node.dc1.consul.", dns.TypeANY) c := new(dns.Client) addr, _ := srv.agent.config.ClientListener("", srv.agent.config.Ports.DNS) in, _, err := c.Exchange(m, addr.String()) if err != nil { t.Fatalf("err: %v", err) } if len(in.Answer) != 1 { t.Fatalf("empty lookup: %#v", in) } }
func ExamplePrivateHandle() { dns.PrivateHandle("APAIR", TypeAPAIR, NewAPAIR) defer dns.PrivateHandleRemove(TypeAPAIR) rr, err := dns.NewRR("miek.nl. APAIR (1.2.3.4 1.2.3.5)") if err != nil { log.Fatal("could not parse APAIR record: ", err) } fmt.Println(rr) // Output: miek.nl. 3600 IN APAIR 1.2.3.4 1.2.3.5 m := new(dns.Msg) m.Id = 12345 m.SetQuestion("miek.nl.", TypeAPAIR) m.Answer = append(m.Answer, rr) fmt.Println(m) // ;; opcode: QUERY, status: NOERROR, id: 12345 // ;; flags: rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 // // ;; QUESTION SECTION: // ;miek.nl. IN APAIR // // ;; ANSWER SECTION: // miek.nl. 3600 IN APAIR 1.2.3.4 1.2.3.5 }
func TestDNS_IsAlive(t *testing.T) { dir, srv := makeDNSServer(t) defer os.RemoveAll(dir) defer srv.agent.Shutdown() m := new(dns.Msg) m.SetQuestion("_test.consul.", dns.TypeANY) c := new(dns.Client) addr, _ := srv.agent.config.ClientListener("", srv.agent.config.Ports.DNS) in, _, err := c.Exchange(m, addr.String()) if err != nil { t.Fatalf("err: %v", err) } if len(in.Answer) != 1 { t.Fatalf("Bad: %#v", in) } txt, ok := in.Answer[0].(*dns.TXT) if !ok { t.Fatalf("Bad: %#v", in.Answer[0]) } if txt.Txt[0] != "ok" { t.Fatalf("Bad: %#v", in.Answer[0]) } }
func TestDNS_ServiceLookup_CNAME(t *testing.T) { dir, srv := makeDNSServer(t) defer os.RemoveAll(dir) defer srv.agent.Shutdown() testutil.WaitForLeader(t, srv.agent.RPC, "dc1") // Register node args := &structs.RegisterRequest{ Datacenter: "dc1", Node: "google", Address: "www.google.com", Service: &structs.NodeService{ Service: "search", Port: 80, }, } var out struct{} if err := srv.agent.RPC("Catalog.Register", args, &out); err != nil { t.Fatalf("err: %v", err) } m := new(dns.Msg) m.SetQuestion("search.service.consul.", dns.TypeANY) c := new(dns.Client) addr, _ := srv.agent.config.ClientListener("", srv.agent.config.Ports.DNS) in, _, err := c.Exchange(m, addr.String()) if err != nil { t.Fatalf("err: %v", err) } if len(in.Answer) != 4 { t.Fatalf("Bad: %#v", in) } // Should have google CNAME cnRec, ok := in.Answer[0].(*dns.CNAME) if !ok { t.Fatalf("Bad: %#v", in.Answer[0]) } if cnRec.Target != "www.google.com." { t.Fatalf("Bad: %#v", in.Answer[0]) } // Check we recursively resolve for i := 1; i < 4; i++ { if _, ok := in.Answer[i].(*dns.A); !ok { t.Fatalf("Bad: %#v", in.Answer[i]) } } }
func TestDNS_NodeLookup_CNAME(t *testing.T) { dir, srv := makeDNSServer(t) defer os.RemoveAll(dir) defer srv.agent.Shutdown() testutil.WaitForLeader(t, srv.agent.RPC, "dc1") // Register node args := &structs.RegisterRequest{ Datacenter: "dc1", Node: "google", Address: "www.google.com", } var out struct{} if err := srv.agent.RPC("Catalog.Register", args, &out); err != nil { t.Fatalf("err: %v", err) } m := new(dns.Msg) m.SetQuestion("google.node.consul.", dns.TypeANY) c := new(dns.Client) addr, _ := srv.agent.config.ClientListener("", srv.agent.config.Ports.DNS) in, _, err := c.Exchange(m, addr.String()) if err != nil { t.Fatalf("err: %v", err) } // Should have the CNAME record + a few A records if len(in.Answer) < 2 { t.Fatalf("Bad: %#v", in) } cnRec, ok := in.Answer[0].(*dns.CNAME) if !ok { t.Fatalf("Bad: %#v", in.Answer[0]) } if cnRec.Target != "www.google.com." { t.Fatalf("Bad: %#v", in.Answer[0]) } if cnRec.Hdr.Ttl != 0 { t.Fatalf("Bad: %#v", in.Answer[0]) } }
func TestDNS_NodeLookup_AAAA(t *testing.T) { dir, srv := makeDNSServer(t) defer os.RemoveAll(dir) defer srv.agent.Shutdown() testutil.WaitForLeader(t, srv.agent.RPC, "dc1") // Register node args := &structs.RegisterRequest{ Datacenter: "dc1", Node: "bar", Address: "::4242:4242", } var out struct{} if err := srv.agent.RPC("Catalog.Register", args, &out); err != nil { t.Fatalf("err: %v", err) } m := new(dns.Msg) m.SetQuestion("bar.node.consul.", dns.TypeANY) c := new(dns.Client) addr, _ := srv.agent.config.ClientListener("", srv.agent.config.Ports.DNS) in, _, err := c.Exchange(m, addr.String()) if err != nil { t.Fatalf("err: %v", err) } if len(in.Answer) != 1 { t.Fatalf("Bad: %#v", in) } aRec, ok := in.Answer[0].(*dns.AAAA) if !ok { t.Fatalf("Bad: %#v", in.Answer[0]) } if aRec.AAAA.String() != "::4242:4242" { t.Fatalf("Bad: %#v", in.Answer[0]) } if aRec.Hdr.Ttl != 0 { t.Fatalf("Bad: %#v", in.Answer[0]) } }
// Retrieve the MX records for miek.nl. func ExampleMX() { config, _ := dns.ClientConfigFromFile("/etc/resolv.conf") c := new(dns.Client) m := new(dns.Msg) m.SetQuestion("miek.nl.", dns.TypeMX) m.RecursionDesired = true r, _, err := c.Exchange(m, config.Servers[0]+":"+config.Port) if err != nil { return } if r.Rcode != dns.RcodeSuccess { return } for _, a := range r.Answer { if mx, ok := a.(*dns.MX); ok { fmt.Printf("%s\n", mx.String()) } } }
func TestDNS_ReverseLookup_CustomDomain(t *testing.T) { dir, srv := makeDNSServer(t) defer os.RemoveAll(dir) defer srv.agent.Shutdown() srv.domain = dns.Fqdn("custom") testutil.WaitForLeader(t, srv.agent.RPC, "dc1") // Register node args := &structs.RegisterRequest{ Datacenter: "dc1", Node: "foo2", Address: "127.0.0.2", } var out struct{} if err := srv.agent.RPC("Catalog.Register", args, &out); err != nil { t.Fatalf("err: %v", err) } m := new(dns.Msg) m.SetQuestion("2.0.0.127.in-addr.arpa.", dns.TypeANY) c := new(dns.Client) addr, _ := srv.agent.config.ClientListener("", srv.agent.config.Ports.DNS) in, _, err := c.Exchange(m, addr.String()) if err != nil { t.Fatalf("err: %v", err) } if len(in.Answer) != 1 { t.Fatalf("Bad: %#v", in) } ptrRec, ok := in.Answer[0].(*dns.PTR) if !ok { t.Fatalf("Bad: %#v", in.Answer[0]) } if ptrRec.Ptr != "foo2.node.dc1.custom." { t.Fatalf("Bad: %#v", ptrRec) } }
func TestDNS_Recurse(t *testing.T) { dir, srv := makeDNSServer(t) defer os.RemoveAll(dir) defer srv.agent.Shutdown() m := new(dns.Msg) m.SetQuestion("apple.com.", dns.TypeANY) c := new(dns.Client) c.Net = "tcp" addr, _ := srv.agent.config.ClientListener("", srv.agent.config.Ports.DNS) in, _, err := c.Exchange(m, addr.String()) if err != nil { t.Fatalf("err: %v", err) } if len(in.Answer) == 0 { t.Fatalf("Bad: %#v", in) } if in.Rcode != dns.RcodeSuccess { t.Fatalf("Bad: %#v", in) } }
// Retrieve the DNSKEY records of a zone and convert them // to DS records for SHA1, SHA256 and SHA384. func ExampleDS(zone string) { config, _ := dns.ClientConfigFromFile("/etc/resolv.conf") c := new(dns.Client) m := new(dns.Msg) if zone == "" { zone = "miek.nl" } m.SetQuestion(dns.Fqdn(zone), dns.TypeDNSKEY) m.SetEdns0(4096, true) r, _, err := c.Exchange(m, config.Servers[0]+":"+config.Port) if err != nil { return } if r.Rcode != dns.RcodeSuccess { return } for _, k := range r.Answer { if key, ok := k.(*dns.DNSKEY); ok { for _, alg := range []uint8{dns.SHA1, dns.SHA256, dns.SHA384} { fmt.Printf("%s; %d\n", key.ToDS(alg).String(), key.Flags) } } } }
func TestDNS_ServiceLookup_OnlyPassing(t *testing.T) { dir, srv := makeDNSServerConfig(t, &DNSConfig{OnlyPassing: true}) defer os.RemoveAll(dir) defer srv.agent.Shutdown() testutil.WaitForLeader(t, srv.agent.RPC, "dc1") // Register nodes args := &structs.RegisterRequest{ Datacenter: "dc1", Node: "foo", Address: "127.0.0.1", Service: &structs.NodeService{ Service: "db", Tags: []string{"master"}, Port: 12345, }, Check: &structs.HealthCheck{ CheckID: "db", Name: "db", ServiceID: "db", Status: structs.HealthPassing, }, } var out struct{} if err := srv.agent.RPC("Catalog.Register", args, &out); err != nil { t.Fatalf("err: %v", err) } args2 := &structs.RegisterRequest{ Datacenter: "dc1", Node: "bar", Address: "127.0.0.2", Service: &structs.NodeService{ Service: "db", Tags: []string{"master"}, Port: 12345, }, Check: &structs.HealthCheck{ CheckID: "db", Name: "db", ServiceID: "db", Status: structs.HealthWarning, }, } if err := srv.agent.RPC("Catalog.Register", args2, &out); err != nil { t.Fatalf("err: %v", err) } args3 := &structs.RegisterRequest{ Datacenter: "dc1", Node: "baz", Address: "127.0.0.3", Service: &structs.NodeService{ Service: "db", Tags: []string{"master"}, Port: 12345, }, Check: &structs.HealthCheck{ CheckID: "db", Name: "db", ServiceID: "db", Status: structs.HealthCritical, }, } if err := srv.agent.RPC("Catalog.Register", args3, &out); err != nil { t.Fatalf("err: %v", err) } args4 := &structs.RegisterRequest{ Datacenter: "dc1", Node: "quux", Address: "127.0.0.4", Service: &structs.NodeService{ Service: "db", Tags: []string{"master"}, Port: 12345, }, Check: &structs.HealthCheck{ CheckID: "db", Name: "db", ServiceID: "db", Status: structs.HealthUnknown, }, } if err := srv.agent.RPC("Catalog.Register", args4, &out); err != nil { t.Fatalf("err: %v", err) } m := new(dns.Msg) m.SetQuestion("db.service.consul.", dns.TypeANY) c := new(dns.Client) addr, _ := srv.agent.config.ClientListener("", srv.agent.config.Ports.DNS) in, _, err := c.Exchange(m, addr.String()) if err != nil { t.Fatalf("err: %v", err) } // Only 1 is passing, so we should only get 1 answer if len(in.Answer) != 1 { t.Fatalf("Bad: %#v", in) } resp := in.Answer[0] aRec := resp.(*dns.A) if aRec.A.String() != "127.0.0.1" { t.Fatalf("Bad: %#v", in.Answer[0]) } }
func TestDNS_NodeLookup_TTL(t *testing.T) { config := &DNSConfig{ NodeTTL: 10 * time.Second, AllowStale: true, MaxStale: time.Second, } dir, srv := makeDNSServerConfig(t, config) defer os.RemoveAll(dir) defer srv.agent.Shutdown() testutil.WaitForLeader(t, srv.agent.RPC, "dc1") // Register node args := &structs.RegisterRequest{ Datacenter: "dc1", Node: "foo", Address: "127.0.0.1", } var out struct{} if err := srv.agent.RPC("Catalog.Register", args, &out); err != nil { t.Fatalf("err: %v", err) } m := new(dns.Msg) m.SetQuestion("foo.node.consul.", dns.TypeANY) c := new(dns.Client) addr, _ := srv.agent.config.ClientListener("", srv.agent.config.Ports.DNS) in, _, err := c.Exchange(m, addr.String()) if err != nil { t.Fatalf("err: %v", err) } if len(in.Answer) != 1 { t.Fatalf("Bad: %#v", in) } aRec, ok := in.Answer[0].(*dns.A) if !ok { t.Fatalf("Bad: %#v", in.Answer[0]) } if aRec.A.String() != "127.0.0.1" { t.Fatalf("Bad: %#v", in.Answer[0]) } if aRec.Hdr.Ttl != 10 { t.Fatalf("Bad: %#v", in.Answer[0]) } // Register node with IPv6 args = &structs.RegisterRequest{ Datacenter: "dc1", Node: "bar", Address: "::4242:4242", } if err := srv.agent.RPC("Catalog.Register", args, &out); err != nil { t.Fatalf("err: %v", err) } // Check an IPv6 record m = new(dns.Msg) m.SetQuestion("bar.node.consul.", dns.TypeANY) in, _, err = c.Exchange(m, addr.String()) if err != nil { t.Fatalf("err: %v", err) } if len(in.Answer) != 1 { t.Fatalf("Bad: %#v", in) } aaaaRec, ok := in.Answer[0].(*dns.AAAA) if !ok { t.Fatalf("Bad: %#v", in.Answer[0]) } if aaaaRec.AAAA.String() != "::4242:4242" { t.Fatalf("Bad: %#v", in.Answer[0]) } if aaaaRec.Hdr.Ttl != 10 { t.Fatalf("Bad: %#v", in.Answer[0]) } // Register node with CNAME args = &structs.RegisterRequest{ Datacenter: "dc1", Node: "google", Address: "www.google.com", } if err := srv.agent.RPC("Catalog.Register", args, &out); err != nil { t.Fatalf("err: %v", err) } m = new(dns.Msg) m.SetQuestion("google.node.consul.", dns.TypeANY) in, _, err = c.Exchange(m, addr.String()) if err != nil { t.Fatalf("err: %v", err) } // Should have the CNAME record + a few A records if len(in.Answer) < 2 { t.Fatalf("Bad: %#v", in) } cnRec, ok := in.Answer[0].(*dns.CNAME) if !ok { t.Fatalf("Bad: %#v", in.Answer[0]) } if cnRec.Target != "www.google.com." { t.Fatalf("Bad: %#v", in.Answer[0]) } if cnRec.Hdr.Ttl != 10 { t.Fatalf("Bad: %#v", in.Answer[0]) } }
func TestDNS_ServiceLookup_TTL(t *testing.T) { config := &DNSConfig{ ServiceTTL: map[string]time.Duration{ "db": 10 * time.Second, "*": 5 * time.Second, }, AllowStale: true, MaxStale: time.Second, } dir, srv := makeDNSServerConfig(t, config) defer os.RemoveAll(dir) defer srv.agent.Shutdown() testutil.WaitForLeader(t, srv.agent.RPC, "dc1") // Register node with 2 services args := &structs.RegisterRequest{ Datacenter: "dc1", Node: "foo", Address: "127.0.0.1", Service: &structs.NodeService{ Service: "db", Tags: []string{"master"}, Port: 12345, }, } var out struct{} if err := srv.agent.RPC("Catalog.Register", args, &out); err != nil { t.Fatalf("err: %v", err) } args = &structs.RegisterRequest{ Datacenter: "dc1", Node: "foo", Address: "127.0.0.1", Service: &structs.NodeService{ Service: "api", Port: 2222, }, } if err := srv.agent.RPC("Catalog.Register", args, &out); err != nil { t.Fatalf("err: %v", err) } m := new(dns.Msg) m.SetQuestion("db.service.consul.", dns.TypeSRV) c := new(dns.Client) addr, _ := srv.agent.config.ClientListener("", srv.agent.config.Ports.DNS) in, _, err := c.Exchange(m, addr.String()) if err != nil { t.Fatalf("err: %v", err) } if len(in.Answer) != 1 { t.Fatalf("Bad: %#v", in) } srvRec, ok := in.Answer[0].(*dns.SRV) if !ok { t.Fatalf("Bad: %#v", in.Answer[0]) } if srvRec.Hdr.Ttl != 10 { t.Fatalf("Bad: %#v", in.Answer[0]) } aRec, ok := in.Extra[0].(*dns.A) if !ok { t.Fatalf("Bad: %#v", in.Extra[0]) } if aRec.Hdr.Ttl != 10 { t.Fatalf("Bad: %#v", in.Extra[0]) } m = new(dns.Msg) m.SetQuestion("api.service.consul.", dns.TypeSRV) in, _, err = c.Exchange(m, addr.String()) if err != nil { t.Fatalf("err: %v", err) } if len(in.Answer) != 1 { t.Fatalf("Bad: %#v", in) } srvRec, ok = in.Answer[0].(*dns.SRV) if !ok { t.Fatalf("Bad: %#v", in.Answer[0]) } if srvRec.Hdr.Ttl != 5 { t.Fatalf("Bad: %#v", in.Answer[0]) } aRec, ok = in.Extra[0].(*dns.A) if !ok { t.Fatalf("Bad: %#v", in.Extra[0]) } if aRec.Hdr.Ttl != 5 { t.Fatalf("Bad: %#v", in.Extra[0]) } }
func TestDNS_ServiceLookup_Randomize(t *testing.T) { dir, srv := makeDNSServer(t) defer os.RemoveAll(dir) defer srv.agent.Shutdown() testutil.WaitForLeader(t, srv.agent.RPC, "dc1") // Register nodes for i := 0; i < 3*maxServiceResponses; i++ { args := &structs.RegisterRequest{ Datacenter: "dc1", Node: fmt.Sprintf("foo%d", i), Address: fmt.Sprintf("127.0.0.%d", i+1), Service: &structs.NodeService{ Service: "web", Port: 8000, }, } var out struct{} if err := srv.agent.RPC("Catalog.Register", args, &out); err != nil { t.Fatalf("err: %v", err) } } // Ensure the response is randomized each time. loops := 5 uniques := map[string]struct{}{} addr, _ := srv.agent.config.ClientListener("", srv.agent.config.Ports.DNS) for i := 0; i < loops; i++ { m := new(dns.Msg) m.SetQuestion("web.service.consul.", dns.TypeANY) c := new(dns.Client) in, _, err := c.Exchange(m, addr.String()) if err != nil { t.Fatalf("err: %v", err) } // Response length should be truncated // We should get an A record for each response if len(in.Answer) != maxServiceResponses { t.Fatalf("Bad: %#v", len(in.Answer)) } // Collect all the names var names []string for _, rec := range in.Answer { switch v := rec.(type) { case *dns.SRV: names = append(names, v.Target) case *dns.A: names = append(names, v.A.String()) } } nameS := strings.Join(names, "|") // Tally the results uniques[nameS] = struct{}{} } // Give some wiggle room. Since the responses are randomized and there // is a finite number of combinations, requiring 0 duplicates every // test run eventually gives us failures. if len(uniques) < (loops - 1) { t.Fatalf("unique response ratio too low: %d/%d\n%v", len(uniques), loops, uniques) } }
// NewDNSServer starts a new DNS server to provide an agent interface func NewDNSServer(agent *Agent, config *DNSConfig, logOutput io.Writer, domain string, bind string, recursors []string) (*DNSServer, error) { // Make sure domain is FQDN domain = dns.Fqdn(domain) // Construct the DNS components mux := dns.NewServeMux() // Setup the servers server := &dns.Server{ Addr: bind, Net: "udp", Handler: mux, UDPSize: 65535, } serverTCP := &dns.Server{ Addr: bind, Net: "tcp", Handler: mux, } // Create the server srv := &DNSServer{ agent: agent, config: config, dnsHandler: mux, dnsServer: server, dnsServerTCP: serverTCP, domain: domain, recursors: recursors, logger: log.New(logOutput, "", log.LstdFlags), } // Register mux handler, for reverse lookup mux.HandleFunc("arpa.", srv.handlePtr) // Register mux handlers, always handle "consul." mux.HandleFunc(domain, srv.handleQuery) if domain != consulDomain { mux.HandleFunc(consulDomain, srv.handleTest) } if len(recursors) > 0 { validatedRecursors := make([]string, len(recursors)) for idx, recursor := range recursors { recursor, err := recursorAddr(recursor) if err != nil { return nil, fmt.Errorf("Invalid recursor address: %v", err) } validatedRecursors[idx] = recursor } srv.recursors = validatedRecursors mux.HandleFunc(".", srv.handleRecurse) } // Async start the DNS Servers, handle a potential error errCh := make(chan error, 1) go func() { if err := server.ListenAndServe(); err != nil { srv.logger.Printf("[ERR] dns: error starting udp server: %v", err) errCh <- fmt.Errorf("dns udp setup failed: %v", err) } }() errChTCP := make(chan error, 1) go func() { if err := serverTCP.ListenAndServe(); err != nil { srv.logger.Printf("[ERR] dns: error starting tcp server: %v", err) errChTCP <- fmt.Errorf("dns tcp setup failed: %v", err) } }() // Check the server is running, do a test lookup checkCh := make(chan error, 1) go func() { // This is jank, but we have no way to edge trigger on // the start of our server, so we just wait and hope it is up. time.Sleep(50 * time.Millisecond) m := new(dns.Msg) m.SetQuestion(testQuery, dns.TypeANY) c := new(dns.Client) in, _, err := c.Exchange(m, bind) if err != nil { checkCh <- fmt.Errorf("dns test query failed: %v", err) return } if len(in.Answer) == 0 { checkCh <- fmt.Errorf("no response to test message") return } close(checkCh) }() // Wait for either the check, listen error, or timeout select { case e := <-errCh: return srv, e case e := <-errChTCP: return srv, e case e := <-checkCh: return srv, e case <-time.After(time.Second): return srv, fmt.Errorf("timeout setting up DNS server") } }
func TestDNS_ServiceLookup_FilterCritical(t *testing.T) { dir, srv := makeDNSServer(t) defer os.RemoveAll(dir) defer srv.agent.Shutdown() testutil.WaitForLeader(t, srv.agent.RPC, "dc1") // Register nodes args := &structs.RegisterRequest{ Datacenter: "dc1", Node: "foo", Address: "127.0.0.1", Service: &structs.NodeService{ Service: "db", Tags: []string{"master"}, Port: 12345, }, Check: &structs.HealthCheck{ CheckID: "serf", Name: "serf", Status: structs.HealthCritical, }, } var out struct{} if err := srv.agent.RPC("Catalog.Register", args, &out); err != nil { t.Fatalf("err: %v", err) } args2 := &structs.RegisterRequest{ Datacenter: "dc1", Node: "bar", Address: "127.0.0.2", Service: &structs.NodeService{ Service: "db", Tags: []string{"master"}, Port: 12345, }, Check: &structs.HealthCheck{ CheckID: "serf", Name: "serf", Status: structs.HealthCritical, }, } if err := srv.agent.RPC("Catalog.Register", args2, &out); err != nil { t.Fatalf("err: %v", err) } args3 := &structs.RegisterRequest{ Datacenter: "dc1", Node: "bar", Address: "127.0.0.2", Service: &structs.NodeService{ Service: "db", Tags: []string{"master"}, Port: 12345, }, Check: &structs.HealthCheck{ CheckID: "db", Name: "db", ServiceID: "db", Status: structs.HealthCritical, }, } if err := srv.agent.RPC("Catalog.Register", args3, &out); err != nil { t.Fatalf("err: %v", err) } args4 := &structs.RegisterRequest{ Datacenter: "dc1", Node: "baz", Address: "127.0.0.3", Service: &structs.NodeService{ Service: "db", Tags: []string{"master"}, Port: 12345, }, } if err := srv.agent.RPC("Catalog.Register", args4, &out); err != nil { t.Fatalf("err: %v", err) } args5 := &structs.RegisterRequest{ Datacenter: "dc1", Node: "quux", Address: "127.0.0.4", Service: &structs.NodeService{ Service: "db", Tags: []string{"master"}, Port: 12345, }, Check: &structs.HealthCheck{ CheckID: "db", Name: "db", ServiceID: "db", Status: structs.HealthWarning, }, } if err := srv.agent.RPC("Catalog.Register", args5, &out); err != nil { t.Fatalf("err: %v", err) } m := new(dns.Msg) m.SetQuestion("db.service.consul.", dns.TypeANY) c := new(dns.Client) addr, _ := srv.agent.config.ClientListener("", srv.agent.config.Ports.DNS) in, _, err := c.Exchange(m, addr.String()) if err != nil { t.Fatalf("err: %v", err) } // Only 4 and 5 are not failing, so we should get 2 answers if len(in.Answer) != 2 { t.Fatalf("Bad: %#v", in) } ips := make(map[string]bool) for _, resp := range in.Answer { aRec := resp.(*dns.A) ips[aRec.A.String()] = true } if !ips["127.0.0.3"] { t.Fatalf("Bad: %#v should contain 127.0.0.3 (state healthy)", in) } if !ips["127.0.0.4"] { t.Fatalf("Bad: %#v should contain 127.0.0.4 (state warning)", in) } }