Example #1
0
func TestRRShuffling(t *testing.T) {
	rr := rrstore.New()
	recs := []string{"10.0.0.1", "10.0.0.2", "10.0.0.3"}
	rr.Set(map[uint16]map[string][]string{
		dns.TypeA: {"a.domain.": []string{"10.0.0.1", "10.0.0.2", "10.0.0.3"}}})

	srv, ready := testServer(t, rr)
	<-ready
	defer srv.Shutdown()

	n := 50
	same := true
	for i := 0; i < n; i++ {
		r, err := query(srv.Addr, "a.domain.", dns.TypeA)
		if err != nil {
			t.Fatal(err)
		}
		as := make([]string, len(r.Answer))
		for i, _ := range r.Answer {
			as[i] = r.Answer[i].(*dns.A).A.String()
			if len(as) != len(recs) {
				t.Fatalf("wrong answer count: %d", len(as))
			}
		}
		if !reflect.DeepEqual(as, recs) {
			same = false
			break
		}
	}
	if same {
		t.Fatalf("same RR ordering occurred even after %d requests", n)
	}
}
Example #2
0
// serve starts the DNS server and blocks.
func serve(opt *Options) {
	dockerTLS, err := tlsConfig(opt.tlsDir, opt.tlsVerify)
	if err != nil {
		log.Fatalf("Error establishing TLS config: %v", err)
	}

	rrs := rrstore.New()
	cluster, err := swarm.New(opt.swarmAddr, dockerTLS)
	if err != nil {
		log.Fatalf("Error initializing Swarm: %v", err)
	}
	dns := clusterdns.New(opt.domain, rrs, cluster)

	cancel := make(chan struct{})
	defer close(cancel)
	errCh, okCh := dns.StartRefreshing(opt.refreshInterval, opt.refreshTimeout,
		cancel)

	go func() {
		var lastSuccess time.Time
		var start = time.Now()
		var errs = 0
		var ok = 0

		for {
			// Exit if records are stale. Here we prefer consistency over
			// liveliness/availability.
			if (ok > 0 && time.Since(lastSuccess) > opt.stalenessPeriod) ||
				(ok == 0 && time.Since(start) > opt.stalenessPeriod) {
				close(cancel)

				var last string
				if lastSuccess.IsZero() {
					last = "never"
				} else {
					last = lastSuccess.String()
				}
				log.Fatalf("Fatal: exiting rather than serving stale records. Staleness period: %v, last success: %s", opt.stalenessPeriod, last)
			}

			select {
			case err := <-errCh:
				errs++
				log.Printf("Refresh error (#%d): %v ", errs, err)
			case <-okCh:
				errs = 0 // reset errs
				ok++
				lastSuccess = time.Now()
				log.Printf("Successfully refreshed records.")
			case <-cancel:
				log.Fatal("Fatal: Refreshing records cancelled.")
			}
		}
	}()

	srv := server.New(opt.domain, opt.bindAddr, rrs, opt.recurse, opt.nameservers)
	log.Fatal(srv.ListenAndServe())
}
Example #3
0
// testServerExternal gives a test server capable of serving only external
// requests.
func testServerExternal(t *testing.T) (*DnsServer, <-chan struct{}) {
	ns := []string{"8.8.8.8:53", "8.8.4.4:53"}
	srv := New("dontcare", ":8053", rrstore.New(), true, ns)
	ready := make(chan struct{}, 1)
	srv.NotifyStartedFunc = func() {
		close(ready)
	}
	go srv.ListenAndServe()
	return srv, ready
}
Example #4
0
func TestHandleExternalOff(t *testing.T) {
	srv, ready := testServer(t, rrstore.New())
	<-ready
	defer srv.Shutdown()

	if r, err := query(srv.Addr, "example.com", dns.TypeA); err != nil {
		t.Fatalf("exchange failed: %v", err)
	} else if r.Rcode != dns.RcodeServerFailure {
		t.Fatalf("unexpected rcode. expected=%s got=%s",
			dns.TypeToString[dns.RcodeServerFailure],
			dns.TypeToString[uint16(r.Rcode)])
	}
}
Example #5
0
func TestHandleDomain(t *testing.T) {
	rr := rrstore.New()
	rr.Set(map[uint16]map[string][]string{
		dns.TypeA: {
			"api.domain.":  []string{"10.0.0.1", "10.0.0.2"},
			"blog.domain.": []string{"10.0.1.1", "10.0.1.2", "10.0.1.3"},
		},
		dns.TypeSRV: {
			"_web._tcp.domain.": []string{"10.0.0.1:80"},
			"_web._udp.domain.": []string{"10.0.0.1:5001",
				"10.0.0.2:5002",
				"10.0.0.3:5003"},
		},
	})

	srv, ready := testServer(t, rr)
	<-ready
	defer srv.Shutdown()

	cases := []struct {
		fqdn            string
		qType           uint16
		expectedRCode   int
		expectedAnswers int
	}{
		// List all test cases for all possible DNS questions here within the
		// domain.
		{"nonexistent.domain.", dns.TypeA, dns.RcodeNameError, 0},
		{"nonexistent.domain.", dns.TypeSRV, dns.RcodeNameError, 0},
		{"api.domain", dns.TypeA, dns.RcodeSuccess, 2},
		{"_web._tcp.domain", dns.TypeSRV, dns.RcodeSuccess, 1},
		{"_WEB._UDP.domain", dns.TypeSRV, dns.RcodeSuccess, 3},
	}

	for _, c := range cases {
		q := fmt.Sprintf("%s %s", dns.TypeToString[c.qType], c.fqdn)

		if r, err := query(srv.Addr, c.fqdn, c.qType); err != nil {
			t.Fatalf("exchange failed (%s): %v", q, err)
		} else if r.Rcode != c.expectedRCode {
			t.Fatalf("unexpected rcode (%s). expected=%s got=%s", q,
				dns.RcodeToString[c.expectedRCode], dns.RcodeToString[r.Rcode])
		} else if len(r.Answer) != c.expectedAnswers {
			t.Fatalf("unexpected answers count. expected=%d got=%d", q,
				len(r.Answer), c.expectedAnswers)
		}
	}
}