From 8fb81f90b1ef8c420aa4891eef968887d5b0cfcb Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sat, 20 Jul 2019 12:23:48 +0200 Subject: [PATCH] dns: make more recent DHCP leases overwrite older ones fixes #20 --- internal/dns/dns.go | 11 ++++++++++ internal/dns/dns_test.go | 47 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/internal/dns/dns.go b/internal/dns/dns.go index 78bbd09..76e948c 100644 --- a/internal/dns/dns.go +++ b/internal/dns/dns.go @@ -247,6 +247,17 @@ func (s *Server) SetLeases(leases []dhcp4d.Lease) { defer s.mu.Unlock() s.initHostsLocked() now := time.Now() + { + // defensive copy + slice := make([]dhcp4d.Lease, len(leases)) + copy(slice, leases) + leases = slice + } + // First entry wins, so we order by expiration descendingly to put the + // newest entry for any given name into s.hostsByName. + sort.Slice(leases, func(i, j int) bool { + return !leases[i].Expiry.Before(leases[j].Expiry) + }) for _, l := range leases { if l.Expired(now) { continue diff --git a/internal/dns/dns_test.go b/internal/dns/dns_test.go index e1ecd95..8924491 100644 --- a/internal/dns/dns_test.go +++ b/internal/dns/dns_test.go @@ -228,9 +228,7 @@ func TestHostname(t *testing.T) { t.Run(hostname, func(t *testing.T) { m := new(dns.Msg) m.SetQuestion(hostname+".lan.", dns.TypeA) - log.Printf("before ServeDNS") s.Mux.ServeDNS(r, m) - log.Printf("after ServeDNS") if got, want := len(r.response.Answer), 1; got != want { t.Fatalf("unexpected number of answers for %v: got %d, want %d", m.Question, got, want) } @@ -260,6 +258,51 @@ func TestHostname(t *testing.T) { t.Fatalf("unexpected response record: got %q, want %q", got, want) } }) + + t.Run("MoreRecent", func(t *testing.T) { + now := time.Now() + older := dhcp4d.Lease{ + Hostname: "xps", + Addr: net.IP{192, 168, 42, 23}, + Expiry: now.Add(1 * time.Second), + } + newer := dhcp4d.Lease{ + Hostname: "xps", + Addr: net.IP{192, 168, 42, 42}, + Expiry: now.Add(2 * time.Second), + } + + for _, tt := range []struct { + name string + order []dhcp4d.Lease + }{ + { + name: "older, newer", + order: []dhcp4d.Lease{older, newer}, + }, + { + name: "newer, older", + order: []dhcp4d.Lease{newer, older}, + }, + } { + t.Run(tt.name, func(t *testing.T) { + s.SetLeases(tt.order) + m := new(dns.Msg) + m.SetQuestion("xps.lan.", dns.TypeA) + s.Mux.ServeDNS(r, m) + if got, want := len(r.response.Answer), 1; got != want { + t.Fatalf("unexpected number of answers for %v: got %d, want %d", m.Question, got, want) + } + a := r.response.Answer[0] + if _, ok := a.(*dns.A); !ok { + t.Fatalf("unexpected response type: got %T, want dns.A", a) + } + if got, want := a.(*dns.A).A, net.ParseIP("192.168.42.42"); !got.Equal(want) { + t.Fatalf("unexpected response IP: got %v, want %v", got, want) + } + }) + } + }) } func TestHostnameDHCP(t *testing.T) {