Skip to content

Commit

Permalink
Add RFC4034 domain comparison + NSEC Cover
Browse files Browse the repository at this point in the history
  • Loading branch information
monoidic committed Nov 21, 2021
1 parent 3b8982c commit 78dd548
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 0 deletions.
59 changes: 59 additions & 0 deletions nsecx.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,62 @@ func (rr *NSEC3) Match(name string) bool {
}
return false
}

// compares domains according to the canonical ordering specified in RFC4034
// returns an integer value similar to strcmp
// (0 for equal values, -1 if s1 < s2, 1 if s1 > s2)
func DomainCompare(s1, s2 string) int {
s1 = strings.ToLower(s1)
s2 = strings.ToLower(s2)

if s1 == s2 {
return 0
}

s1_labels := SplitDomainName(s1)
s2_labels := SplitDomainName(s2)

if s1_labels == nil { // s1 is root
return -1
}
if s2_labels == nil { // s2 is root
return 1
}

reverse_arr(s1_labels)
reverse_arr(s2_labels)

s1_label_len := len(s1_labels)
s2_label_len := len(s2_labels)

var min_label_len int
var default_ret int // based on label count, if the common prefix matches

if s1_label_len < s2_label_len {
min_label_len = s1_label_len
default_ret = -1
} else {
min_label_len = s2_label_len
default_ret = 1
}

for i := 0; i < min_label_len; i++ {
cmp := strings.Compare(s1_labels[i], s2_labels[i])
if cmp != 0 {
return cmp
}
}

return default_ret
}

// Match returns true if the given name is covered by the NSEC record
func (rr *NSEC) Cover(name string) bool {
return DomainCompare(rr.Hdr.Name, name) <= 0 && DomainCompare(name, rr.NextDomain) == -1
}

func reverse_arr(arr []string) {
for i, j := 0, len(arr) - 1; i < j; i, j = i+1, j-1 {
arr[i], arr[j] = arr[j], arr[i]
}
}
52 changes: 52 additions & 0 deletions nsecx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,55 @@ func BenchmarkHashName(b *testing.B) {
})
}
}

func TestDomainCompare(t *testing.T) {
domains := []string{ // from RFC 4034
"example.",
"a.example.",
"yljkjljk.a.example.",
"Z.a.example.",
"zABC.a.EXAMPLE.",
"z.example.",
"\x01.z.example.",
"*.z.example.",
"\xc8.z.example.",
}

len_domains := len(domains)

for i, domain := range domains {
if i != 0 {
prev_domain := domains[i-1]
if !(DomainCompare(prev_domain, domain) == -1 && DomainCompare(domain, prev_domain) == 1) {
t.Fatalf("prev comparison failure between %s and %s", prev_domain, domain)
}
}

if DomainCompare(domain, domain) != 0 {
t.Fatalf("self comparison failure for %s", domain)
}

if i != len_domains-1 {
next_domain := domains[i+1]
if !(DomainCompare(domain, next_domain) == -1 && DomainCompare(next_domain, domain) == 1) {
t.Fatalf("next comparison failure between %s and %s, %d and %d", domain, next_domain, DomainCompare(domain, next_domain), DomainCompare(next_domain, domain))
}
}
}
}

func TestNsecCover(t *testing.T) {
nsec := testRR("aaa.ee. 3600 IN NSEC aac.ee. NS RRSIG NSEC").(*NSEC)

if !nsec.Cover("aaaa.ee.") {
t.Fatal("nsec cover positive example failure")
}

if !nsec.Cover("aaa.ee.") {
t.Fatal("nsec cover self example failure")
}

if nsec.Cover("aad.ee.") {
t.Fatal("nsec cover negative example failure")
}
}

0 comments on commit 78dd548

Please sign in to comment.