types: lowercase DNS extra record names

DNS names are case-insensitive, but clients match extra records against
the lowercased query name, so records with mixed-case names (for example
"Printer.fritz.box" in an extra_records_path file) never resolved and
queries fell through to the global nameserver.

Normalize record names to lowercase where the records enter the tailcfg
DNS config, covering both dns.extra_records and extra_records_path.

Fixes #2782

(cherry picked from commit 95ba1f0566)
This commit is contained in:
Saleh
2026-09-09 19:56:05 +00:00
committed by Kristoffer Dalby
parent 2b8dbea412
commit b4f991b381
2 changed files with 47 additions and 2 deletions
+18 -2
View File
@@ -967,7 +967,7 @@ func dnsToTailcfgDNS(dns DNSConfig) *tailcfg.DNSConfig {
cfg.Proxied = dns.MagicDNS
cfg.ExtraRecords = dns.ExtraRecords
cfg.ExtraRecords = lowercaseRecordNames(dns.ExtraRecords)
if dns.OverrideLocalDNS {
cfg.Resolvers = dns.globalResolvers()
} else {
@@ -1512,6 +1512,22 @@ func (c *Config) SetExtraRecords(records []tailcfg.DNSRecord) {
defer tailcfgDNSMu.Unlock()
if c.TailcfgDNSConfig != nil {
c.TailcfgDNSConfig.ExtraRecords = records
c.TailcfgDNSConfig.ExtraRecords = lowercaseRecordNames(records)
}
}
// lowercaseRecordNames normalizes DNS record names to lowercase, as DNS names
// are case-insensitive and clients match extra records by exact name.
func lowercaseRecordNames(records []tailcfg.DNSRecord) []tailcfg.DNSRecord {
if len(records) == 0 {
return records
}
normalized := make([]tailcfg.DNSRecord, len(records))
for i, record := range records {
record.Name = strings.ToLower(record.Name)
normalized[i] = record
}
return normalized
}
+29
View File
@@ -601,3 +601,32 @@ func TestTrustedProxies(t *testing.T) {
})
}
}
// DNS names are case-insensitive, but MagicDNS resolution in clients matches
// extra records by exact name, so mixed-case record names never resolve.
func TestExtraRecordsAreLowercased(t *testing.T) {
mixed := []tailcfg.DNSRecord{
{Name: "Printer.fritz.box", Type: "A", Value: "192.168.1.2"},
{Name: "NAS.FRITZ.BOX", Type: "A", Value: "192.168.1.3"},
}
want := []tailcfg.DNSRecord{
{Name: "printer.fritz.box", Type: "A", Value: "192.168.1.2"},
{Name: "nas.fritz.box", Type: "A", Value: "192.168.1.3"},
}
tcfg := dnsToTailcfgDNS(DNSConfig{
MagicDNS: true,
BaseDomain: "example.com",
ExtraRecords: mixed,
})
if diff := cmp.Diff(want, tcfg.ExtraRecords); diff != "" {
t.Errorf("dnsToTailcfgDNS extra records mismatch (-want +got):\n%s", diff)
}
cfg := &Config{TailcfgDNSConfig: &tailcfg.DNSConfig{}}
cfg.SetExtraRecords(mixed)
if diff := cmp.Diff(want, cfg.TailcfgDNSConfig.ExtraRecords); diff != "" {
t.Errorf("SetExtraRecords mismatch (-want +got):\n%s", diff)
}
}