1package dns
2
3import (
4	"strconv"
5	"testing"
6)
7
8func TestPackNsec3(t *testing.T) {
9	nsec3 := HashName("dnsex.nl.", SHA1, 0, "DEAD")
10	if nsec3 != "ROCCJAE8BJJU7HN6T7NG3TNM8ACRS87J" {
11		t.Error(nsec3)
12	}
13
14	nsec3 = HashName("a.b.c.example.org.", SHA1, 2, "DEAD")
15	if nsec3 != "6LQ07OAHBTOOEU2R9ANI2AT70K5O0RCG" {
16		t.Error(nsec3)
17	}
18}
19
20func TestNsec3(t *testing.T) {
21	nsec3 := testRR("sk4e8fj94u78smusb40o1n0oltbblu2r.nl. IN NSEC3 1 1 5 F10E9F7EA83FC8F3 SK4F38CQ0ATIEI8MH3RGD0P5I4II6QAN NS SOA TXT RRSIG DNSKEY NSEC3PARAM")
22	if !nsec3.(*NSEC3).Match("nl.") { // name hash = sk4e8fj94u78smusb40o1n0oltbblu2r
23		t.Fatal("sk4e8fj94u78smusb40o1n0oltbblu2r.nl. should match sk4e8fj94u78smusb40o1n0oltbblu2r.nl.")
24	}
25	if !nsec3.(*NSEC3).Match("NL.") { // name hash = sk4e8fj94u78smusb40o1n0oltbblu2r
26		t.Fatal("sk4e8fj94u78smusb40o1n0oltbblu2r.NL. should match sk4e8fj94u78smusb40o1n0oltbblu2r.nl.")
27	}
28	if nsec3.(*NSEC3).Match("com.") { //
29		t.Fatal("com. is not in the zone nl.")
30	}
31	if nsec3.(*NSEC3).Match("test.nl.") { // name hash = gd0ptr5bnfpimpu2d3v6gd4n0bai7s0q
32		t.Fatal("gd0ptr5bnfpimpu2d3v6gd4n0bai7s0q.nl. should not match sk4e8fj94u78smusb40o1n0oltbblu2r.nl.")
33	}
34	nsec3 = testRR("nl. IN NSEC3 1 1 5 F10E9F7EA83FC8F3 SK4F38CQ0ATIEI8MH3RGD0P5I4II6QAN NS SOA TXT RRSIG DNSKEY NSEC3PARAM")
35	if nsec3.(*NSEC3).Match("nl.") {
36		t.Fatal("sk4e8fj94u78smusb40o1n0oltbblu2r.nl. should not match a record without a owner hash")
37	}
38
39	for _, tc := range []struct {
40		rr     *NSEC3
41		name   string
42		covers bool
43	}{
44		// positive tests
45		{ // name hash between owner hash and next hash
46			rr: &NSEC3{
47				Hdr:        RR_Header{Name: "2N1TB3VAIRUOBL6RKDVII42N9TFMIALP.com."},
48				Hash:       1,
49				Flags:      1,
50				Iterations: 5,
51				Salt:       "F10E9F7EA83FC8F3",
52				NextDomain: "PT3RON8N7PM3A0OE989IB84OOSADP7O8",
53			},
54			name:   "bsd.com.",
55			covers: true,
56		},
57		{ // end of zone, name hash is after owner hash
58			rr: &NSEC3{
59				Hdr:        RR_Header{Name: "3v62ulr0nre83v0rja2vjgtlif9v6rab.com."},
60				Hash:       1,
61				Flags:      1,
62				Iterations: 5,
63				Salt:       "F10E9F7EA83FC8F3",
64				NextDomain: "2N1TB3VAIRUOBL6RKDVII42N9TFMIALP",
65			},
66			name:   "csd.com.",
67			covers: true,
68		},
69		{ // end of zone, name hash is before beginning of zone
70			rr: &NSEC3{
71				Hdr:        RR_Header{Name: "PT3RON8N7PM3A0OE989IB84OOSADP7O8.com."},
72				Hash:       1,
73				Flags:      1,
74				Iterations: 5,
75				Salt:       "F10E9F7EA83FC8F3",
76				NextDomain: "3V62ULR0NRE83V0RJA2VJGTLIF9V6RAB",
77			},
78			name:   "asd.com.",
79			covers: true,
80		},
81		// negative tests
82		{ // too short owner name
83			rr: &NSEC3{
84				Hdr:        RR_Header{Name: "nl."},
85				Hash:       1,
86				Flags:      1,
87				Iterations: 5,
88				Salt:       "F10E9F7EA83FC8F3",
89				NextDomain: "39P99DCGG0MDLARTCRMCF6OFLLUL7PR6",
90			},
91			name:   "asd.com.",
92			covers: false,
93		},
94		{ // outside of zone
95			rr: &NSEC3{
96				Hdr:        RR_Header{Name: "39p91242oslggest5e6a7cci4iaeqvnk.nl."},
97				Hash:       1,
98				Flags:      1,
99				Iterations: 5,
100				Salt:       "F10E9F7EA83FC8F3",
101				NextDomain: "39P99DCGG0MDLARTCRMCF6OFLLUL7PR6",
102			},
103			name:   "asd.com.",
104			covers: false,
105		},
106		{ // empty interval
107			rr: &NSEC3{
108				Hdr:        RR_Header{Name: "2n1tb3vairuobl6rkdvii42n9tfmialp.com."},
109				Hash:       1,
110				Flags:      1,
111				Iterations: 5,
112				Salt:       "F10E9F7EA83FC8F3",
113				NextDomain: "2N1TB3VAIRUOBL6RKDVII42N9TFMIALP",
114			},
115			name:   "asd.com.",
116			covers: false,
117		},
118		{ // empty interval wildcard
119			rr: &NSEC3{
120				Hdr:        RR_Header{Name: "2n1tb3vairuobl6rkdvii42n9tfmialp.com."},
121				Hash:       1,
122				Flags:      1,
123				Iterations: 5,
124				Salt:       "F10E9F7EA83FC8F3",
125				NextDomain: "2N1TB3VAIRUOBL6RKDVII42N9TFMIALP",
126			},
127			name:   "*.asd.com.",
128			covers: true,
129		},
130		{ // name hash is before owner hash, not covered
131			rr: &NSEC3{
132				Hdr:        RR_Header{Name: "3V62ULR0NRE83V0RJA2VJGTLIF9V6RAB.com."},
133				Hash:       1,
134				Flags:      1,
135				Iterations: 5,
136				Salt:       "F10E9F7EA83FC8F3",
137				NextDomain: "PT3RON8N7PM3A0OE989IB84OOSADP7O8",
138			},
139			name:   "asd.com.",
140			covers: false,
141		},
142	} {
143		covers := tc.rr.Cover(tc.name)
144		if tc.covers != covers {
145			t.Fatalf("cover failed for %s: expected %t, got %t [record: %s]", tc.name, tc.covers, covers, tc.rr)
146		}
147	}
148}
149
150func TestNsec3EmptySalt(t *testing.T) {
151	rr, _ := NewRR("CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN NSEC3 1 1 0 - CK0Q1GIN43N1ARRC9OSM6QPQR81H5M9A  NS SOA RRSIG DNSKEY NSEC3PARAM")
152
153	if !rr.(*NSEC3).Match("com.") {
154		t.Fatalf("expected record to match com. label")
155	}
156}
157
158func BenchmarkHashName(b *testing.B) {
159	for _, iter := range []uint16{
160		150, 2500, 5000, 10000, ^uint16(0),
161	} {
162		b.Run(strconv.Itoa(int(iter)), func(b *testing.B) {
163			for n := 0; n < b.N; n++ {
164				if HashName("some.example.org.", SHA1, iter, "deadbeef") == "" {
165					b.Fatalf("HashName failed")
166				}
167			}
168		})
169	}
170}
171