net/dns: ensure the Windows configurator does not touch the hosts file unless the configuration actually changed

We build up maps of both the existing MagicDNS configuration in hosts
and the desired MagicDNS configuration, compare the two, and only
write out a new one if there are changes. The comparison doesn't need
to be perfect, as the occasional false-positive is fine, but this
should greatly reduce rewrites of the hosts file.

I also changed the hosts updating code to remove the CRLF/LF conversion
stuff, and use Fprintf instead of Frintln to let us write those inline.

Updates #14428

Signed-off-by: Aaron Klotz <aaron@tailscale.com>
This commit is contained in:
Aaron Klotz
2025-01-13 13:47:56 -07:00
parent 27477983e3
commit d818a58a77
2 changed files with 107 additions and 19 deletions

View File

@@ -15,6 +15,7 @@ import (
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/registry"
"tailscale.com/types/logger"
"tailscale.com/util/dnsname"
"tailscale.com/util/winutil"
"tailscale.com/util/winutil/gp"
@@ -24,9 +25,56 @@ const testGPRuleID = "{7B1B6151-84E6-41A3-8967-62F7F7B45687}"
func TestHostFileNewLines(t *testing.T) {
in := []byte("#foo\r\n#bar\n#baz\n")
want := []byte("#foo\r\n#bar\r\n#baz\r\n")
want := []byte("#foo\r\n#bar\r\n#baz\r\n# TailscaleHostsSectionStart\r\n# This section contains MagicDNS entries for Tailscale.\r\n# Do not edit this section manually.\r\n\r\n192.168.1.1 aaron\r\n\r\n# TailscaleHostsSectionEnd\r\n")
got, err := setTailscaleHosts(in, nil)
he := []*HostEntry{
&HostEntry{
Addr: netip.MustParseAddr("192.168.1.1"),
Hosts: []string{"aaron"},
},
}
got, err := setTailscaleHosts(logger.Discard, in, he)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(got, want) {
t.Errorf("got %q, want %q\n", got, want)
}
}
func TestHostFileUnchanged(t *testing.T) {
in := []byte("#foo\r\n#bar\r\n#baz\r\n# TailscaleHostsSectionStart\r\n# This section contains MagicDNS entries for Tailscale.\r\n# Do not edit this section manually.\r\n\r\n192.168.1.1 aaron\r\n\r\n# TailscaleHostsSectionEnd\r\n")
he := []*HostEntry{
&HostEntry{
Addr: netip.MustParseAddr("192.168.1.1"),
Hosts: []string{"aaron"},
},
}
got, err := setTailscaleHosts(logger.Discard, in, he)
if err != nil {
t.Fatal(err)
}
if got != nil {
t.Errorf("got %q, want nil\n", got)
}
}
func TestHostFileChanged(t *testing.T) {
in := []byte("#foo\r\n#bar\r\n#baz\r\n# TailscaleHostsSectionStart\r\n# This section contains MagicDNS entries for Tailscale.\r\n# Do not edit this section manually.\r\n\r\n192.168.1.1 aaron1\r\n\r\n# TailscaleHostsSectionEnd\r\n")
want := []byte("#foo\r\n#bar\r\n#baz\r\n# TailscaleHostsSectionStart\r\n# This section contains MagicDNS entries for Tailscale.\r\n# Do not edit this section manually.\r\n\r\n192.168.1.1 aaron1\r\n192.168.1.2 aaron2\r\n\r\n# TailscaleHostsSectionEnd\r\n")
he := []*HostEntry{
&HostEntry{
Addr: netip.MustParseAddr("192.168.1.1"),
Hosts: []string{"aaron1"},
},
&HostEntry{
Addr: netip.MustParseAddr("192.168.1.2"),
Hosts: []string{"aaron2"},
},
}
got, err := setTailscaleHosts(logger.Discard, in, he)
if err != nil {
t.Fatal(err)
}