Make the TTL returned for local answers configurable.

This commit is contained in:
Alvaro Saurin committed 2015-05-29 12:50:18 +02:00
1 parent db217cd56f
commit 858a6dd253
12 files changed
+74 -47

No files matched your search

+2
View File
@@ -22,6 +22,8 @@ var (
)
const (
DefaultCacheNegLocalTTL = 30 // Default TTL for negative local resolutions
defPendingTimeout int = 5 // timeout for a resolution
)
+13 -13
View File
@@ -36,7 +36,7 @@ func TestCacheLength(t *testing.T) {
ip := net.ParseIP(fmt.Sprintf("10.0.1.%d", i))
records := []ZoneRecord{Record{name, ip, 0, 0, 0}}
reply := makeAddressReply(questionMsg, question, records)
reply := makeAddressReply(questionMsg, question, records, DefaultLocalTTL)
reply.Answer[0].Header().Ttl = uint32(i)
l.Put(questionMsg, reply, 0, 0)
@@ -89,7 +89,7 @@ func TestCacheEntries(t *testing.T) {
t.Logf("Inserting the reply")
records := []ZoneRecord{Record{"some.name", net.ParseIP("10.0.1.1"), 0, 0, 0}}
reply1 := makeAddressReply(questionMsg, question, records)
reply1 := makeAddressReply(questionMsg, question, records, DefaultLocalTTL)
l.Put(questionMsg, reply1, nullTTL, 0)
t.Logf("Checking we can Get() the reply now")
@@ -110,8 +110,8 @@ func TestCacheEntries(t *testing.T) {
ttlGet2 := resp.Answer[0].Header().Ttl
wt.AssertEqualInt(t, int(ttlGet1-ttlGet2), 1, "TTL difference")
clk.Add(time.Duration(localTTL) * time.Second)
t.Logf("Checking that a third Get(), after %d second, gets no result", localTTL)
clk.Add(time.Duration(DefaultLocalTTL) * time.Second)
t.Logf("Checking that a third Get(), after %d second, gets no result", DefaultLocalTTL)
resp, err = l.Get(questionMsg, minUDPSize)
wt.AssertNoErr(t, err)
if resp != nil {
@@ -121,7 +121,7 @@ func TestCacheEntries(t *testing.T) {
t.Logf("Checking that an Remove() results in Get() returning nothing")
records = []ZoneRecord{Record{"some.name", net.ParseIP("10.0.9.9"), 0, 0, 0}}
replyTemp := makeAddressReply(questionMsg, question, records)
replyTemp := makeAddressReply(questionMsg, question, records, DefaultLocalTTL)
l.Put(questionMsg, replyTemp, nullTTL, 0)
lenBefore := l.Len()
l.Remove(question)
@@ -135,11 +135,11 @@ func TestCacheEntries(t *testing.T) {
t.Logf("Inserting a two replies for the same query")
records = []ZoneRecord{Record{"some.name", net.ParseIP("10.0.1.2"), 0, 0, 0}}
reply2 := makeAddressReply(questionMsg, question, records)
reply2 := makeAddressReply(questionMsg, question, records, DefaultLocalTTL)
l.Put(questionMsg, reply2, nullTTL, 0)
clk.Add(time.Duration(1) * time.Second)
records = []ZoneRecord{Record{"some.name", net.ParseIP("10.0.1.3"), 0, 0, 0}}
reply3 := makeAddressReply(questionMsg, question, records)
reply3 := makeAddressReply(questionMsg, question, records, DefaultLocalTTL)
l.Put(questionMsg, reply3, nullTTL, 0)
t.Logf("Checking we get the last one...")
@@ -149,9 +149,9 @@ func TestCacheEntries(t *testing.T) {
t.Logf("Received '%s'", resp.Answer[0])
wt.AssertType(t, resp.Answer[0], (*dns.A)(nil), "DNS record")
wt.AssertEqualString(t, resp.Answer[0].(*dns.A).A.String(), "10.0.1.3", "IP address")
wt.AssertEqualInt(t, int(resp.Answer[0].Header().Ttl), int(localTTL), "TTL")
wt.AssertEqualInt(t, int(resp.Answer[0].Header().Ttl), int(DefaultLocalTTL), "TTL")
clk.Add(time.Duration(localTTL-1) * time.Second)
clk.Add(time.Duration(DefaultLocalTTL-1) * time.Second)
resp, err = l.Get(questionMsg, minUDPSize)
wt.AssertNoErr(t, err)
wt.AssertTrue(t, resp != nil, "reponse from the Get()")
@@ -162,7 +162,7 @@ func TestCacheEntries(t *testing.T) {
t.Logf("Checking we get empty replies when they are expired...")
lenBefore = l.Len()
clk.Add(time.Duration(localTTL) * time.Second)
clk.Add(time.Duration(DefaultLocalTTL) * time.Second)
resp, err = l.Get(questionMsg, minUDPSize)
wt.AssertNoErr(t, err)
if resp != nil {
@@ -183,7 +183,7 @@ func TestCacheEntries(t *testing.T) {
t.Logf("Checking that an Remove() between Get() and Put() does not break things")
records = []ZoneRecord{Record{"some.name", net.ParseIP("10.0.9.9"), 0, 0, 0}}
replyTemp2 := makeAddressReply(questionMsg2, question2, records)
replyTemp2 := makeAddressReply(questionMsg2, question2, records, DefaultLocalTTL)
l.Remove(question2)
l.Put(questionMsg2, replyTemp2, nullTTL, 0)
resp, err = l.Get(questionMsg2, minUDPSize)
@@ -201,8 +201,8 @@ func TestCacheEntries(t *testing.T) {
wt.AssertNil(t, resp, "Get() response with CacheNoLocalReplies")
wt.AssertNotNil(t, err, "Get() error with CacheNoLocalReplies")
clk.Add(time.Second * time.Duration(negLocalTTL+1))
t.Logf("Checking that we get an expired response after %d seconds", negLocalTTL)
clk.Add(time.Second * time.Duration(DefaultCacheNegLocalTTL+1))
t.Logf("Checking that we get an expired response after %d seconds", DefaultCacheNegLocalTTL)
resp, err = l.Get(questionMsg3, minUDPSize)
wt.AssertNil(t, resp, "expired Get() response with CacheNoLocalReplies")
wt.AssertNil(t, err, "expired Get() error with CacheNoLocalReplies")
+13 -12
View File
@@ -8,16 +8,17 @@ import (
)
const (
localTTL uint32 = 30 // somewhat arbitrary; we don't expect anyone downstream to cache results
negLocalTTL = 30 // TTL for negative local resolutions
minUDPSize = 512
maxUDPSize = 65535
minUDPSize = 512
maxUDPSize = 65535
)
func makeHeader(r *dns.Msg, q *dns.Question) *dns.RR_Header {
func makeHeader(r *dns.Msg, q *dns.Question, ttl int) *dns.RR_Header {
return &dns.RR_Header{
Name: q.Name, Rrtype: q.Qtype,
Class: dns.ClassINET, Ttl: localTTL}
Name: q.Name,
Rrtype: q.Qtype,
Class: dns.ClassINET,
Ttl: uint32(ttl),
}
}
func makeReply(r *dns.Msg, as []dns.RR) *dns.Msg {
@@ -36,11 +37,11 @@ func makeTruncatedReply(r *dns.Msg) *dns.Msg {
return reply
}
type DNSResponseBuilder func(r *dns.Msg, q *dns.Question, addrs []ZoneRecord) *dns.Msg
type DNSResponseBuilder func(r *dns.Msg, q *dns.Question, addrs []ZoneRecord, ttl int) *dns.Msg
func makeAddressReply(r *dns.Msg, q *dns.Question, addrs []ZoneRecord) *dns.Msg {
func makeAddressReply(r *dns.Msg, q *dns.Question, addrs []ZoneRecord, ttl int) *dns.Msg {
answers := make([]dns.RR, len(addrs))
header := makeHeader(r, q)
header := makeHeader(r, q, ttl)
count := 0
for _, addr := range addrs {
ip := addr.IP()
@@ -62,9 +63,9 @@ func makeAddressReply(r *dns.Msg, q *dns.Question, addrs []ZoneRecord) *dns.Msg
return makeReply(r, answers[:count])
}
func makePTRReply(r *dns.Msg, q *dns.Question, names []ZoneRecord) *dns.Msg {
func makePTRReply(r *dns.Msg, q *dns.Question, names []ZoneRecord, ttl int) *dns.Msg {
answers := make([]dns.RR, len(names))
header := makeHeader(r, q)
header := makeHeader(r, q, ttl)
for i, name := range names {
answers[i] = &dns.PTR{Hdr: *header, Ptr: name.Name()}
}
+2 -2
View File
@@ -25,8 +25,8 @@ func TestPrune(t *testing.T) {
Record{"name", net.ParseIP("10.0.1.4"), 0, 0, 0},
}
reply := makeAddressReply(questionMsg, question, records)
reply.Answer[0].Header().Ttl = localTTL
reply := makeAddressReply(questionMsg, question, records, DefaultLocalTTL)
reply.Answer[0].Header().Ttl = DefaultLocalTTL
pruned := pruneAnswers(reply.Answer, 1)
wt.AssertEqualInt(t, len(pruned), 1, "wrong number of answers")
+9 -4
View File
@@ -13,13 +13,18 @@ type MDNSServer struct {
srv *dns.Server
zone Zone
allowLocal bool
ttl int
running bool
}
// Create a new mDNS server
// Nothing will be done (including port bindings) until you `Start()` the server
func NewMDNSServer(zone Zone, local bool) (*MDNSServer, error) {
return &MDNSServer{zone: zone, allowLocal: local}, nil
func NewMDNSServer(zone Zone, local bool, ttl int) (*MDNSServer, error) {
return &MDNSServer{
zone: zone,
allowLocal: local,
ttl: ttl,
}, nil
}
// Return true if testaddr is a UDP address with IP matching my local i/f
@@ -66,7 +71,7 @@ func (s *MDNSServer) Start(ifi *net.Interface) (err error) {
handleLocal := s.makeHandler(dns.TypeA,
func(zone ZoneLookup, r *dns.Msg, q *dns.Question) *dns.Msg {
if ips, err := zone.LookupName(q.Name); err == nil {
return makeAddressReply(r, q, ips)
return makeAddressReply(r, q, ips, s.ttl)
}
return nil
})
@@ -74,7 +79,7 @@ func (s *MDNSServer) Start(ifi *net.Interface) (err error) {
handleReverse := s.makeHandler(dns.TypePTR,
func(zone ZoneLookup, r *dns.Msg, q *dns.Question) *dns.Msg {
if names, err := zone.LookupInaddr(q.Name); err == nil {
return makePTRReply(r, q, names)
return makePTRReply(r, q, names, s.ttl)
}
return nil
})
+1 -1
View File
@@ -21,7 +21,7 @@ func TestServerSimpleQuery(t *testing.T) {
Info.Println("TestServerSimpleQuery starting")
mzone := newMockedZoneWithRecords([]ZoneRecord{testRecord1, testRecord2})
mdnsServer, err := NewMDNSServer(mzone, true)
mdnsServer, err := NewMDNSServer(mzone, true, DefaultLocalTTL)
wt.AssertNoErr(t, err)
err = mdnsServer.Start(nil)
wt.AssertNoErr(t, err)
+4 -4
View File
@@ -18,7 +18,7 @@ func TestClientServerSimpleQuery(t *testing.T) {
testInAddr1 := "1.2.2.10.in-addr.arpa."
mzone := newMockedZoneWithRecords([]ZoneRecord{testRecord1})
mdnsServer, err := NewMDNSServer(mzone, true)
mdnsServer, err := NewMDNSServer(mzone, true, DefaultLocalTTL)
wt.AssertNoErr(t, err)
err = mdnsServer.Start(nil)
wt.AssertNoErr(t, err)
@@ -94,21 +94,21 @@ func TestClientServerInsistentQuery(t *testing.T) {
testInAddr2 := "2.2.2.10.in-addr.arpa."
mzone1 := newMockedZoneWithRecords([]ZoneRecord{testRecord1})
mdnsServer1, err := NewMDNSServer(mzone1, true)
mdnsServer1, err := NewMDNSServer(mzone1, true, DefaultLocalTTL)
wt.AssertNoErr(t, err)
err = mdnsServer1.Start(nil)
wt.AssertNoErr(t, err)
defer mdnsServer1.Stop()
mzone2 := newMockedZoneWithRecords([]ZoneRecord{testRecord2})
mdnsServer2, err := NewMDNSServer(mzone2, true)
mdnsServer2, err := NewMDNSServer(mzone2, true, DefaultLocalTTL)
wt.AssertNoErr(t, err)
err = mdnsServer2.Start(nil)
wt.AssertNoErr(t, err)
defer mdnsServer2.Stop()
// create a third server with exactly the same info as the second server (so we can test duplicates removals)
mdnsServer3, err := NewMDNSServer(mzone2, true)
mdnsServer3, err := NewMDNSServer(mzone2, true, DefaultLocalTTL)
wt.AssertNoErr(t, err)
err = mdnsServer3.Start(nil)
wt.AssertNoErr(t, err)
+10 -2
View File
@@ -16,6 +16,7 @@ import (
const (
DefaultServerPort = 53 // The default server port
DefaultCLICfgFile = "/etc/resolv.conf" // default "resolv.conf" file to try to load
DefaultLocalTTL = 30 // default TTL for responses for local domain queries
DefaultUDPBuflen = 4096 // bigger than the default 512
DefaultCacheLen = 8192 // default cache capacity
DefaultTimeout = 5000 // default timeout for DNS resolutions (millisecs)
@@ -41,6 +42,8 @@ type DNSServerConfig struct {
UDPBufLen int
// (Optional) force a specific cache
Cache ZoneCache
// (Optional) TTL for local domain responses
LocalTTL int
// (Optional) TTL for negative results in the local domain
CacheNegLocalTTL int
// (Optional) for a specific clock provider
@@ -94,6 +97,7 @@ type DNSServer struct {
cache ZoneCache
cacheDisabled bool
maxAnswers int
localTTL int
negLocalTTL int
timeout time.Duration
readTimeout time.Duration
@@ -114,7 +118,8 @@ func NewDNSServer(config DNSServerConfig) (s *DNSServer, err error) {
readTimeout: DefaultTimeout * time.Millisecond,
cacheDisabled: false,
maxAnswers: DefaultMaxAnswers,
negLocalTTL: negLocalTTL,
localTTL: DefaultLocalTTL,
negLocalTTL: DefaultCacheNegLocalTTL,
clock: config.Clock,
}
@@ -153,6 +158,9 @@ func NewDNSServer(config DNSServerConfig) (s *DNSServer, err error) {
if config.MaxAnswers > 0 {
s.maxAnswers = config.MaxAnswers
}
if config.LocalTTL > 0 {
s.localTTL = config.LocalTTL
}
if config.CacheNegLocalTTL > 0 {
s.negLocalTTL = config.CacheNegLocalTTL
}
@@ -344,7 +352,7 @@ func (s *DNSServer) localHandler(proto dnsProtocol, kind string, qtype uint16,
maybeCache(nil, s.negLocalTTL, CacheNoLocalReplies)
fallback(w, r)
} else {
m := msgBuilder(r, &q, answers)
m := msgBuilder(r, &q, answers, s.localTTL)
m.Authoritative = true
maybeCache(m, nullTTL, 0)
m.Answer = pruneAnswers(shuffleAnswers(m.Answer), s.maxAnswers)
+1 -1
View File
@@ -17,7 +17,7 @@ func TestServerCacheRefresh(t *testing.T) {
containerID = "somecontainer"
testName1 = "first.weave.local."
testName2 = "second.weave.local."
refreshInterval = int(localTTL) / 3
refreshInterval = int(DefaultLocalTTL) / 3
)
InitDefaultLogging(testing.Verbose())
+2 -2
View File
@@ -158,7 +158,7 @@ func TestTCPDNSServer(t *testing.T) {
t.Logf("Fallback UDP server got asked: returning %d answers", numAnswers)
q := req.Question[0]
m := makeAddressReply(req, &q, addrs)
m := makeAddressReply(req, &q, addrs, DefaultLocalTTL)
mLen := m.Len()
m.SetEdns0(uint16(maxLen), false)
@@ -171,7 +171,7 @@ func TestTCPDNSServer(t *testing.T) {
fallbackTCPHandler := func(w dns.ResponseWriter, req *dns.Msg) {
t.Logf("Fallback TCP server got asked: returning %d answers", numAnswers)
q := req.Question[0]
m := makeAddressReply(req, &q, addrs)
m := makeAddressReply(req, &q, addrs, DefaultLocalTTL)
w.WriteMsg(m)
}
+13 -6
View File
@@ -17,10 +17,10 @@ const (
)
const (
DefaultLocalDomain = "weave.local." // The default name used for the local domain
DefaultRefreshInterval = int(localTTL) // Period for background updates with mDNS
DefaultRelevantTime = 60 // When to forget info about remote info if nobody asks...
DefaultNumUpdaters = 4 // Default number of background updaters
DefaultLocalDomain = "weave.local." // The default name used for the local domain
DefaultRefreshInterval = int(DefaultLocalTTL) // Period for background updates with mDNS
DefaultRelevantTime = 60 // When to forget info about remote info if nobody asks...
DefaultNumUpdaters = 4 // Default number of background updaters
defaultRefreshMailbox = 1000 // Number of on-the-fly background queries
defaultRemoteIdent = "weave:remote" // Ident used for info obtained from mDNS
@@ -126,7 +126,7 @@ func (re *recordEntry) notifyIPObservers() {
func (re *recordEntry) TTL() int {
// if we never set the TTL (eg, when using AddRecord()), return the standard value...
if re.ttl == 0 {
return int(localTTL)
return int(DefaultLocalTTL)
}
return re.ttl
}
@@ -429,6 +429,8 @@ type ZoneConfig struct {
RelevantTime int
// Max pending refresh requests
MaxRefreshRequests int
// TTL returnined in local asnwers (with mDNS)
LocalTTL int
// Force a specific mDNS client
MDNSClient ZoneMDNSClient
// Force a specific mDNS server
@@ -505,7 +507,12 @@ func NewZoneDb(config ZoneConfig) (zone *ZoneDb, err error) {
}
}
if zone.mdnsSrv == nil {
if zone.mdnsSrv, err = NewMDNSServer(zone, false); err != nil {
mdnsTTL := DefaultLocalTTL
if config.LocalTTL > 0 {
mdnsTTL = config.LocalTTL
}
if zone.mdnsSrv, err = NewMDNSServer(zone, false, mdnsTTL); err != nil {
return
}
}
+4
View File
@@ -24,6 +24,7 @@ func main() {
dnsPort int
httpPort int
wait int
ttl int
timeout int
udpbuf int
fallback string
@@ -46,6 +47,7 @@ func main() {
flag.IntVar(&dnsPort, "dnsport", weavedns.DefaultServerPort, "port to listen to DNS requests")
flag.IntVar(&httpPort, "httpport", 6785, "port to listen to HTTP requests")
flag.IntVar(&cacheLen, "cache", weavedns.DefaultCacheLen, "cache length")
flag.IntVar(&ttl, "ttl", weavedns.DefaultLocalTTL, "TTL (in secs) for responses for local names")
flag.BoolVar(&watch, "watch", true, "watch the docker socket for container events")
flag.BoolVar(&debug, "debug", false, "output debugging info to stderr")
// advanced options
@@ -82,6 +84,7 @@ func main() {
zoneConfig := weavedns.ZoneConfig{
Domain: domain,
Iface: iface,
LocalTTL: ttl,
RefreshInterval: refreshInterval,
RefreshWorkers: refreshWorkers,
RelevantTime: relevantTime,
@@ -107,6 +110,7 @@ func main() {
Zone: zone,
Port: dnsPort,
CacheLen: cacheLen,
LocalTTL: ttl,
MaxAnswers: maxAnswers,
Timeout: timeout,
UDPBufLen: udpbuf,