1 // Copyright (C) 2010-2017 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7 #include <config.h>
8
9 #include <string>
10
11 #include <exceptions/exceptions.h>
12
13 #include <util/buffer.h>
14 #include <dns/exceptions.h>
15 #include <dns/messagerenderer.h>
16 #include <dns/rdata.h>
17 #include <dns/rdataclass.h>
18 #include <dns/rrclass.h>
19 #include <dns/rrtype.h>
20
21 #include <gtest/gtest.h>
22
23 #include <dns/tests/unittest_util.h>
24 #include <dns/tests/rdata_unittest.h>
25
26 using isc::UnitTestUtil;
27 using namespace std;
28 using namespace isc;
29 using namespace isc::dns;
30 using namespace isc::util;
31 using namespace isc::dns::rdata;
32
33 namespace {
34
35 // Note: some tests can be shared with NSEC3PARAM. They are unified as
36 // typed tests defined in nsec3param_like_unittest.
37 class Rdata_NSEC3_Test : public RdataTest {
38 protected:
Rdata_NSEC3_Test()39 Rdata_NSEC3_Test() :
40 nsec3_txt("1 1 1 D399EAAB H9RSFB7FPF2L8HG35CMPC765TDK23RP6 "
41 "A NS SOA"),
42 nsec3_nosalt_txt("1 1 1 - H9RSFB7FPF2L8HG35CMPC765TDK23RP6 A NS SOA"),
43 nsec3_notype_txt("1 1 1 D399EAAB H9RSFB7FPF2L8HG35CMPC765TDK23RP6"),
44 rdata_nsec3(nsec3_txt)
45 {}
46
checkFromText_None(const string & rdata_str)47 void checkFromText_None(const string& rdata_str) {
48 checkFromText<generic::NSEC3, isc::Exception, isc::Exception>(
49 rdata_str, rdata_nsec3, false, false);
50 }
51
checkFromText_InvalidText(const string & rdata_str)52 void checkFromText_InvalidText(const string& rdata_str) {
53 checkFromText<generic::NSEC3, InvalidRdataText, InvalidRdataText>(
54 rdata_str, rdata_nsec3, true, true);
55 }
56
checkFromText_BadValue(const string & rdata_str)57 void checkFromText_BadValue(const string& rdata_str) {
58 checkFromText<generic::NSEC3, BadValue, BadValue>(
59 rdata_str, rdata_nsec3, true, true);
60 }
61
checkFromText_LexerError(const string & rdata_str)62 void checkFromText_LexerError(const string& rdata_str) {
63 checkFromText
64 <generic::NSEC3, InvalidRdataText, MasterLexer::LexerError>(
65 rdata_str, rdata_nsec3, true, true);
66 }
67
checkFromText_BadString(const string & rdata_str)68 void checkFromText_BadString(const string& rdata_str) {
69 checkFromText
70 <generic::NSEC3, InvalidRdataText, isc::Exception>(
71 rdata_str, rdata_nsec3, true, false);
72 }
73
74 const string nsec3_txt;
75 const string nsec3_nosalt_txt;
76 const string nsec3_notype_txt;
77 const generic::NSEC3 rdata_nsec3;
78 };
79
TEST_F(Rdata_NSEC3_Test,fromText)80 TEST_F(Rdata_NSEC3_Test, fromText) {
81 // Hash that has the possible max length
82 EXPECT_EQ(255, generic::NSEC3("1 1 1 D399EAAB " +
83 string((255 * 8) / 5, '0') +
84 " NS").getNext().size());
85
86 // Hash is too long. Max = 255 bytes, base32-hex converts each 5 bytes
87 // of the original to 8 characters, so 260 * 8 / 5 is the smallest length
88 // of the encoded string that exceeds the max and doesn't require padding.
89 checkFromText_InvalidText("1 1 1 D399EAAB " + string((260 * 8) / 5, '0') +
90 " A NS SOA");
91
92 // Type bitmap is empty. it's possible and allowed for NSEC3.
93 EXPECT_NO_THROW(const generic::NSEC3 rdata_notype_nsec3(nsec3_notype_txt));
94
95 // Empty salt is also okay.
96 EXPECT_NO_THROW(const generic::NSEC3 rdata_nosalt_nsec3(nsec3_nosalt_txt));
97
98 // Bad type mnemonics
99 checkFromText_InvalidText("1 1 1 D399EAAB H9RSFB7FPF2L8HG35CMPC765TDK23RP6"
100 " BIFF POW SPOON");
101
102 // Bad base32hex
103 checkFromText_BadValue("1 1 1 D399EAAB "
104 "WXYZWXYZWXYZ=WXYZWXYZ==WXYZWXYZW A NS SOA");
105
106 // Hash algorithm out of range
107 checkFromText_InvalidText("256 1 1 D399EAAB "
108 "H9RSFB7FPF2L8HG35CMPC765TDK23RP6 A NS SOA");
109
110 // Flags out of range
111 checkFromText_InvalidText("1 256 1 D399EAAB "
112 "H9RSFB7FPF2L8HG35CMPC765TDK23RP6 A NS SOA");
113
114 // Iterations out of range
115 checkFromText_InvalidText("1 1 65536 D399EAAB "
116 "H9RSFB7FPF2L8HG35CMPC765TDK23RP6 A NS SOA");
117
118 // Space is not allowed in salt or the next hash. This actually
119 // causes the Base32 decoder that parses the next hash that comes
120 // afterwards, to throw.
121 checkFromText_BadValue("1 1 1 D399 EAAB H9RSFB7FPF2L8"
122 "HG35CMPC765TDK23RP6 A NS SOA");
123
124 // Next hash must not contain padding (trailing '=' characters)
125 checkFromText_InvalidText("1 1 1 D399EAAB "
126 "AAECAwQFBgcICQoLDA0ODw== A NS SOA");
127
128 // String instead of number
129 checkFromText_LexerError("foo 1 1 D399EAAB "
130 "H9RSFB7FPF2L8HG35CMPC765TDK23RP6 A NS SOA");
131 checkFromText_LexerError("1 foo 1 D399EAAB "
132 "H9RSFB7FPF2L8HG35CMPC765TDK23RP6 A NS SOA");
133 checkFromText_LexerError("1 1 foo D399EAAB "
134 "H9RSFB7FPF2L8HG35CMPC765TDK23RP6 A NS SOA");
135
136 // Trailing garbage. This should cause only the string constructor
137 // to fail, but the lexer constructor must be able to continue
138 // parsing from it.
139 checkFromText_BadString(
140 "1 1 1 D399EAAB H9RSFB7FPF2L8HG35CMPC765TDK23RP6 A NS SOA ;comment\n"
141 "1 1 1 D399EAAB H9RSFB7FPF2L8HG35CMPC765TDK23RP6 A NS SOA");
142
143 // Unmatched parenthesis should cause a lexer error
144 checkFromText_LexerError("1 1 1 D399EAAB "
145 "H9RSFB7FPF2L8HG35CMPC765TDK23RP6 A ) NS SOA");
146 }
147
TEST_F(Rdata_NSEC3_Test,createFromWire)148 TEST_F(Rdata_NSEC3_Test, createFromWire) {
149 // A valid NSEC3 RR with empty type bitmap.
150 EXPECT_NO_THROW(rdataFactoryFromFile(RRType::NSEC3(), RRClass::IN(),
151 "rdata_nsec3_fromWire15.wire"));
152
153 // Invalid bitmap cases are tested in Rdata_NSECBITMAP_Test.
154
155 // hash length is too large
156 EXPECT_THROW(rdataFactoryFromFile(RRType::NSEC3(), RRClass::IN(),
157 "rdata_nsec3_fromWire12.wire"),
158 DNSMessageFORMERR);
159
160 // empty hash. invalid.
161 EXPECT_THROW(rdataFactoryFromFile(RRType::NSEC3(), RRClass::IN(),
162 "rdata_nsec3_fromWire14.wire"),
163 DNSMessageFORMERR);
164
165 // RDLEN is too short to hold the hash length field
166 EXPECT_THROW(rdataFactoryFromFile(RRType::NSEC3(), RRClass::IN(),
167 "rdata_nsec3_fromWire17.wire"),
168 DNSMessageFORMERR);
169
170 // Short buffer cases. The data is valid NSEC3 RDATA, but the buffer
171 // is trimmed at the end. All cases should result in an exception from
172 // the buffer class.
173 vector<uint8_t> data;
174 UnitTestUtil::readWireData("rdata_nsec3_fromWire1", data);
175 const uint16_t rdlen = (data.at(0) << 8) + data.at(1);
176 for (int i = 0; i < rdlen; ++i) {
177 // intentionally construct a short buffer
178 InputBuffer b(&data[0] + 2, i);
179 EXPECT_THROW(createRdata(RRType::NSEC3(), RRClass::IN(), b, 39),
180 InvalidBufferPosition);
181 }
182 }
183
TEST_F(Rdata_NSEC3_Test,createFromLexer)184 TEST_F(Rdata_NSEC3_Test, createFromLexer) {
185 EXPECT_EQ(0, rdata_nsec3.compare(
186 *test::createRdataUsingLexer(RRType::NSEC3(), RRClass::IN(),
187 nsec3_txt)));
188
189 // empty salt is also okay.
190 const generic::NSEC3 rdata_nosalt_nsec3(nsec3_nosalt_txt);
191 EXPECT_EQ(0, rdata_nosalt_nsec3.compare(
192 *test::createRdataUsingLexer(RRType::NSEC3(), RRClass::IN(),
193 nsec3_nosalt_txt)));
194 }
195
TEST_F(Rdata_NSEC3_Test,assign)196 TEST_F(Rdata_NSEC3_Test, assign) {
197 generic::NSEC3 other_nsec3 = rdata_nsec3;
198 EXPECT_EQ(0, rdata_nsec3.compare(other_nsec3));
199 }
200
TEST_F(Rdata_NSEC3_Test,compare)201 TEST_F(Rdata_NSEC3_Test, compare) {
202 // trivial case: self equivalence
203 EXPECT_EQ(0, generic::NSEC3(nsec3_txt).compare(generic::NSEC3(nsec3_txt)));
204
205 // comparison attempt between incompatible RR types should be rejected
206 EXPECT_THROW(generic::NSEC3(nsec3_txt).compare(*rdata_nomatch),
207 bad_cast);
208
209 // test RDATAs, sorted in the ascending order. We only check comparison
210 // on NSEC3-specific fields. Bitmap comparison is tested in the bitmap
211 // tests. Common cases for NSEC3 and NSECPARAM3 are in their shared tests.
212 vector<generic::NSEC3> compare_set;
213 compare_set.push_back(generic::NSEC3("1 1 1 FF99EA0000 D1K6GQ38"));
214 compare_set.push_back(generic::NSEC3("1 1 1 FF99EA0000 D1K6GQ0000000000"));
215 compare_set.push_back(generic::NSEC3("1 1 1 FF99EA0000 D1K6GQ00UUUUUUUU"));
216
217 vector<generic::NSEC3>::const_iterator it;
218 const vector<generic::NSEC3>::const_iterator it_end = compare_set.end();
219 for (it = compare_set.begin(); it != it_end - 1; ++it) {
220 SCOPED_TRACE("compare " + it->toText() + " to " + (it + 1)->toText());
221 EXPECT_GT(0, (*it).compare(*(it + 1)));
222 EXPECT_LT(0, (*(it + 1)).compare(*it));
223 }
224 }
225
226 }
227