Files
ctrld/nameservers_scutil_test.go
T
Dev Scribe c7b3881e13 Port DNS64, VPN routing and DNS recovery ownership to master
Retain master's context-aware VPN and resolver APIs, per-program logger,
shutdown fencing, native CLAT service identity and firewall behavior.
Keep saved-DNS paths owned by the root ctrld package; isolate the added
ownership/sweep tests with a shared path seam and temporary backups.

Preserve the source DNS64 DNSSEC/cache gates, longest-suffix VPN routing,
DNS-journal convergence, scoped IPv6 handling, target ownership checks,
custom-listener regressions and documented native QA limits.
2026-09-28 14:44:47 +07:00

81 lines
2.9 KiB
Go

package ctrld
import (
"net/netip"
"slices"
"strings"
"testing"
)
func TestScutilNameserversIPv6AndZones(t *testing.T) {
output := []byte(`DNS configuration
resolver #1
nameserver[0] : 192.0.2.53
nameserver[1] : 2001:db8::53
nameserver[2] : fe80::1%en0
nameserver[3] : 2001:db8::53
nameserver[4] : fe80::1%en1
nameserver[5] : 127.0.0.1
nameserver[6] : ::1
nameserver[7] : fe80::2%en0
nameserver[8] : not-an-address
search domain[0] : internal.example
`)
local := []netip.Addr{netip.MustParseAddr("127.0.0.1"), netip.MustParseAddr("::1"), netip.MustParseAddr("fe80::2%en0")}
got, err := parseScutilNameservers(output, local)
want := []string{"192.0.2.53", "2001:db8::53", "fe80::1%en0", "fe80::1%en1"}
if err != nil || !slices.Equal(got, want) {
t.Fatalf("nameservers=%v err=%v", got, err)
}
effective := initializeOsResolver(got)
r := newResolverWithNameserver(effective)
if !slices.Contains(*r.lanServers.Load(), "[fe80::1%en0]:53") || !slices.Contains(*r.lanServers.Load(), "[fe80::1%en1]:53") {
t.Fatalf("zones lost in effective resolver: %v", effective)
}
if !slices.Contains(*r.publicServers.Load(), "[2001:db8::53]:53") {
t.Fatalf("global IPv6 lost: %v", effective)
}
}
func TestScutilNameserversLocalExclusion(t *testing.T) {
for _, tt := range []struct {
name, local, server string
excluded bool
}{
{"unzoned link-local does not exclude scoped router", "fe80::1", "fe80::1%en0", false},
{"loopback link-local does not exclude router", "fe80::1%lo0", "fe80::1%en0", false},
{"other link does not exclude router", "fe80::1%en1", "fe80::1%en0", false},
{"same link excludes local address", "fe80::1%en0", "fe80::1%en0", true},
{"unzoned link-local matches unzoned local", "fe80::1", "fe80::1", true},
{"scoped local does not exclude unzoned candidate", "fe80::1%en0", "fe80::1", false},
{"global ignores zones", "2001:db8::1%en0", "2001:db8::1%en1", true},
{"loopback ignores zones", "::1%lo0", "::1", true},
{"IPv4 mapped local", "::ffff:192.0.2.1", "192.0.2.1", true},
{"IPv4 mapped candidate", "192.0.2.1", "::ffff:192.0.2.1", true},
{"IPv4 link-local mapped candidate", "169.254.1.1", "::ffff:169.254.1.1", true},
{"other global is retained", "2001:db8::1", "2001:db8::53", false},
} {
t.Run(tt.name, func(t *testing.T) {
got, err := parseScutilNameservers([]byte("nameserver[0] : "+tt.server+"\n"), []netip.Addr{netip.MustParseAddr(tt.local)})
if err != nil {
t.Fatal(err)
}
var want []string
if !tt.excluded {
want = []string{tt.server}
}
if !slices.Equal(got, want) {
t.Fatalf("nameservers=%v, want %v", got, want)
}
})
}
}
func TestScutilNameserversRejectsPartialScan(t *testing.T) {
output := []byte("nameserver[0] : 192.0.2.53\n" + strings.Repeat("x", 128*1024))
got, err := parseScutilNameservers(output, nil)
if err == nil || got != nil {
t.Fatalf("partial scan accepted: %v, %v", got, err)
}
}