package dnsrecord import "testing" func TestValidateRRSetAcceptsSupportedRecords(t *testing.T) { v := newTestValidator(t) cases := []struct { recordType string content string }{ {"A", "192.0.2.10"}, {"AAAA", "2001:db8::1"}, {"CAA", `0 issue "letsencrypt.org"`}, {"CNAME", "target.example.org."}, {"MX", "10 mail.example.org."}, {"NS", "ns1.example.org."}, {"SOA", "ns1.example.org. hostmaster.example.org. 2026010101 3600 600 604800 300"}, {"SRV", "10 20 443 service.example.org."}, {"TXT", `"v=spf1 -all"`}, {"TXT", `"v=DMARC1; p=reject; rua=mailto:postmaster@example.org; ruf=mailto:postmaster@example.org"`}, } for _, tc := range cases { t.Run(tc.recordType, func(t *testing.T) { if _, err := v.ValidateRRSet("www.example.org", tc.recordType, 300, []string{tc.content}); err != nil { t.Fatalf("ValidateRRSet returned error: %v", err) } }) } } func TestValidateRRSetRejectsInvalidRecords(t *testing.T) { v := newTestValidator(t) cases := []struct { name string recordType string content string }{ {"bad name", "A", "192.0.2.10"}, {"www.example.org.", "A", "2001:db8::1"}, {"www.example.org.", "AAAA", "192.0.2.10"}, {"www.example.org.", "MX", "mail.example.org."}, {"www.example.org.", "CNAME", "target.example.org"}, {"www.example.org.", "TXT", "not quoted"}, {"www.example.org.", "SOA", "ns1.example.org. hostmaster.example.org."}, {"www.example.org.", "UNSUPPORTED", "value"}, } for _, tc := range cases { t.Run(tc.recordType+" "+tc.content, func(t *testing.T) { if _, err := v.ValidateRRSet(tc.name, tc.recordType, 300, []string{tc.content}); err == nil { t.Fatal("expected validation error") } }) } } func TestValidateRRSetAcceptsUnderscoresInOwnerNames(t *testing.T) { v := newTestValidator(t) cases := []struct { name string recordType string content string wantName string }{ { name: "_dmarc.example.org", recordType: "TXT", content: `"v=DMARC1; p=reject; rua=mailto:postmaster@example.org; ruf=mailto:postmaster@example.org"`, wantName: "_dmarc.example.org.", }, { name: "_sip._tcp.example.org", recordType: "SRV", content: "10 20 5060 sip.example.org.", wantName: "_sip._tcp.example.org.", }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { rrset, err := v.ValidateRRSet(tc.name, tc.recordType, 300, []string{tc.content}) if err != nil { t.Fatalf("ValidateRRSet returned error: %v", err) } if rrset.Name != tc.wantName { t.Fatalf("unexpected normalized name: %q", rrset.Name) } if rrset.Records[0].Content != tc.content { t.Fatalf("unexpected content: %q", rrset.Records[0].Content) } }) } } func TestValidateRRSetRejectsUnderscoresInHostnameTargets(t *testing.T) { v := newTestValidator(t) cases := []struct { recordType string content string }{ {"CNAME", "_target.example.org."}, {"MX", "10 _mail.example.org."}, {"NS", "_ns.example.org."}, {"SOA", "_ns.example.org. hostmaster.example.org. 2026010101 3600 600 604800 300"}, {"SRV", "10 20 5060 _sip.example.org."}, } for _, tc := range cases { t.Run(tc.recordType, func(t *testing.T) { if _, err := v.ValidateRRSet("www.example.org.", tc.recordType, 300, []string{tc.content}); err == nil { t.Fatal("expected validation error") } }) } } func TestValidateRRSetRequiresTTL(t *testing.T) { v := newTestValidator(t) if _, err := v.ValidateRRSet("www.example.org.", "A", 0, []string{"192.0.2.10"}); err == nil { t.Fatal("expected ttl validation error") } } func newTestValidator(t *testing.T) *Validator { t.Helper() v, err := NewValidator() if err != nil { t.Fatalf("NewValidator returned error: %v", err) } return v }