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