Add DNS resource NSEC helper

This commit is contained in:
Virgil 2026-04-04 06:30:08 +00:00
parent 317c731c2a
commit b3f1c5dcd7
3 changed files with 90 additions and 0 deletions

View file

@ -730,6 +730,11 @@ func TestPackageResourceAliases(t *testing.T) {
t.Fatal("resource aliases should expose record type helpers from pkg/dns")
}
nsec := resource.ToNSEC("Example")
if nsec.Name != "Example." || nsec.NextDomain != "example\x00." || nsec.TTL != DEFAULT_TTL {
t.Fatalf("Resource.ToNSEC returned %+v", nsec)
}
encoded, err := resource.Encode()
if err != nil {
t.Fatalf("Resource.Encode returned error: %v", err)

View file

@ -247,6 +247,30 @@ func (r *Resource) GetHasDS() bool {
return r.HasDS()
}
// ToNSEC constructs the reference NSEC helper output for the resource.
//
// The bitmap selection matches the JS reference helper:
// - NS-capable resources use TYPE_MAP_NS
// - TXT-only resources use TYPE_MAP_TXT
// - everything else falls back to TYPE_MAP_EMPTY
func (r *Resource) ToNSEC(name string) NSECRecord {
typeMap := TYPE_MAP_EMPTY
if r != nil {
if r.HasNS() {
typeMap = TYPE_MAP_NS
} else if r.HasType(HSTypeTXT) {
typeMap = TYPE_MAP_TXT
}
}
return Create(name, NextName(name), typeMap)
}
// GetToNSEC is an alias for ToNSEC.
func (r *Resource) GetToNSEC(name string) NSECRecord {
return r.ToNSEC(name)
}
// Encode serializes the resource payload in the reference binary format.
func (r *Resource) Encode() ([]byte, error) {
if r == nil {

View file

@ -242,6 +242,67 @@ func TestResourceTypeHelpers(t *testing.T) {
}
}
func TestResourceToNSEC(t *testing.T) {
cases := []struct {
name string
record []ResourceRecord
want []byte
}{
{
name: "empty",
want: TYPE_MAP_EMPTY,
},
{
name: "txt",
record: []ResourceRecord{
TXTRecord{Entries: []string{"txt"}},
},
want: TYPE_MAP_TXT,
},
{
name: "ns",
record: []ResourceRecord{
TXTRecord{Entries: []string{"txt"}},
NSRecord{NS: "ns1.example."},
},
want: TYPE_MAP_NS,
},
}
for _, tc := range cases {
resource := NewResource()
resource.Records = append(resource.Records, tc.record...)
rr := resource.ToNSEC("Example")
if rr.Name != "Example." {
t.Fatalf("%s: ToNSEC name = %q, want %q", tc.name, rr.Name, "Example.")
}
if rr.NextDomain != "example\x00." {
t.Fatalf("%s: ToNSEC next domain = %q, want %q", tc.name, rr.NextDomain, "example\x00.")
}
if rr.TTL != DEFAULT_TTL {
t.Fatalf("%s: ToNSEC TTL = %d, want %d", tc.name, rr.TTL, DEFAULT_TTL)
}
if !bytes.Equal(rr.TypeBitmap, tc.want) {
t.Fatalf("%s: ToNSEC bitmap = %x, want %x", tc.name, rr.TypeBitmap, tc.want)
}
alias := resource.GetToNSEC("Example")
if alias.Name != rr.Name || alias.NextDomain != rr.NextDomain || alias.TTL != rr.TTL {
t.Fatalf("%s: GetToNSEC should alias ToNSEC, got %+v want %+v", tc.name, alias, rr)
}
}
var nilResource *Resource
rr := nilResource.ToNSEC("Example")
if !bytes.Equal(rr.TypeBitmap, TYPE_MAP_EMPTY) {
t.Fatalf("nil resource ToNSEC bitmap = %x, want %x", rr.TypeBitmap, TYPE_MAP_EMPTY)
}
}
func TestResourceDecodeStopsAtUnknownType(t *testing.T) {
resource := NewResource()
resource.Records = []ResourceRecord{TXTRecord{Entries: []string{"known"}}}