1 // Copyright (C) 2011-2019 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 <util/buffer.h>
12 #include <dns/exceptions.h>
13 #include <dns/messagerenderer.h>
14 #include <dns/rdata.h>
15 #include <dns/rdataclass.h>
16 #include <dns/rrclass.h>
17 #include <dns/rrtype.h>
18 
19 #include <gtest/gtest.h>
20 
21 #include <dns/tests/unittest_util.h>
22 #include <dns/tests/rdata_unittest.h>
23 #include <util/unittests/wiredata.h>
24 
25 using namespace std;
26 using namespace isc::util;
27 using namespace isc::dns;
28 using namespace isc::dns::rdata;
29 using isc::UnitTestUtil;
30 using isc::util::unittests::matchWireData;
31 
32 namespace {
33 class Rdata_MINFO_Test : public RdataTest {
34 protected:
Rdata_MINFO_Test()35     Rdata_MINFO_Test():
36         minfo_txt("rmailbox.example.com. emailbox.example.com."),
37         minfo_txt2("root.example.com. emailbox.example.com."),
38         too_long_label("01234567890123456789012345678901234567"
39                        "89012345678901234567890123."),
40         rdata_minfo(minfo_txt),
41         rdata_minfo2(minfo_txt2)
42     {}
43 
checkFromText_None(const string & rdata_str)44     void checkFromText_None(const string& rdata_str) {
45         checkFromText<generic::MINFO, isc::Exception, isc::Exception>(
46             rdata_str, rdata_minfo, false, false);
47     }
48 
checkFromText_LexerError(const string & rdata_str)49     void checkFromText_LexerError(const string& rdata_str) {
50         checkFromText
51             <generic::MINFO, InvalidRdataText, MasterLexer::LexerError>(
52             rdata_str, rdata_minfo, true, true);
53     }
54 
checkFromText_TooLongLabel(const string & rdata_str)55     void checkFromText_TooLongLabel(const string& rdata_str) {
56         checkFromText<generic::MINFO, TooLongLabel, TooLongLabel>(
57             rdata_str, rdata_minfo, true, true);
58     }
59 
checkFromText_BadString(const string & rdata_str)60     void checkFromText_BadString(const string& rdata_str) {
61         checkFromText<generic::MINFO, InvalidRdataText, isc::Exception>(
62             rdata_str, rdata_minfo, true, false);
63     }
64 
checkFromText_EmptyLabel(const string & rdata_str)65     void checkFromText_EmptyLabel(const string& rdata_str) {
66         checkFromText<generic::MINFO, EmptyLabel, EmptyLabel>(
67             rdata_str, rdata_minfo, true, true);
68     }
69 
checkFromText_MissingOrigin(const string & rdata_str)70     void checkFromText_MissingOrigin(const string& rdata_str) {
71         checkFromText
72             <generic::MINFO, MissingNameOrigin, MissingNameOrigin>(
73                 rdata_str, rdata_minfo, true, true);
74     }
75 
checkFromText_Origin(const string & rdata_str,const Name * origin)76     void checkFromText_Origin(const string& rdata_str, const Name* origin) {
77         checkFromText<generic::MINFO, MissingNameOrigin, isc::Exception>(
78             rdata_str, rdata_minfo, true, false, origin);
79     }
80 
81     const string minfo_txt;
82     const string minfo_txt2;
83     const string too_long_label;
84     const generic::MINFO rdata_minfo;
85     const generic::MINFO rdata_minfo2;
86 };
87 
88 
TEST_F(Rdata_MINFO_Test,createFromText)89 TEST_F(Rdata_MINFO_Test, createFromText) {
90     EXPECT_EQ(Name("rmailbox.example.com."), rdata_minfo.getRmailbox());
91     EXPECT_EQ(Name("emailbox.example.com."), rdata_minfo.getEmailbox());
92 
93     EXPECT_EQ(Name("root.example.com."), rdata_minfo2.getRmailbox());
94     EXPECT_EQ(Name("emailbox.example.com."), rdata_minfo2.getEmailbox());
95 
96     checkFromText_None(minfo_txt);
97 
98     // origin defined for lexer constructor, but not string constructor
99     const Name origin("example.com");
100     checkFromText_Origin("rmailbox emailbox", &origin);
101 
102     // lexer constructor accepts extra text, but string constructor doesn't
103     checkFromText_BadString("rmailbox.example.com. emailbox.example.com. "
104                             "extra.example.com.");
105 }
106 
TEST_F(Rdata_MINFO_Test,badText)107 TEST_F(Rdata_MINFO_Test, badText) {
108     // too long names
109     checkFromText_TooLongLabel("root.example.com."  + too_long_label +
110                                " emailbox.example.com.");
111     checkFromText_TooLongLabel("root.example.com. emailbox.example.com." +
112                                too_long_label);
113 
114     // invalid names
115     checkFromText_EmptyLabel("root..example.com. emailbox.example.com.");
116     checkFromText_EmptyLabel("root.example.com. emailbox..example.com.");
117 
118     // missing name
119     checkFromText_LexerError("root.example.com.");
120 
121     // missing origin
122     checkFromText_MissingOrigin("root.example.com emailbox.example.com.");
123     checkFromText_MissingOrigin("root.example.com. emailbox.example.com");
124 }
125 
TEST_F(Rdata_MINFO_Test,createFromWire)126 TEST_F(Rdata_MINFO_Test, createFromWire) {
127     // uncompressed names
128     EXPECT_EQ(0, rdata_minfo.compare(
129                   *rdataFactoryFromFile(RRType::MINFO(), RRClass::IN(),
130                                      "rdata_minfo_fromWire1.wire")));
131     // compressed names
132     EXPECT_EQ(0, rdata_minfo.compare(
133                   *rdataFactoryFromFile(RRType::MINFO(), RRClass::IN(),
134                                      "rdata_minfo_fromWire2.wire", 15)));
135     // RDLENGTH is too short
136     EXPECT_THROW(rdataFactoryFromFile(RRType::MINFO(), RRClass::IN(),
137                                      "rdata_minfo_fromWire3.wire"),
138                  InvalidRdataLength);
139     // RDLENGTH is too long
140     EXPECT_THROW(rdataFactoryFromFile(RRType::MINFO(), RRClass::IN(),
141                                       "rdata_minfo_fromWire4.wire"),
142                  InvalidRdataLength);
143     // bogus rmailbox name, the error should be detected in the name
144     // constructor
145     EXPECT_THROW(rdataFactoryFromFile(RRType::MINFO(), RRClass::IN(),
146                                       "rdata_minfo_fromWire5.wire"),
147                  DNSMessageFORMERR);
148     // bogus emailbox name, the error should be detected in the name
149     // constructor
150     EXPECT_THROW(rdataFactoryFromFile(RRType::MINFO(), RRClass::IN(),
151                                       "rdata_minfo_fromWire6.wire"),
152                  DNSMessageFORMERR);
153 }
154 
TEST_F(Rdata_MINFO_Test,assignment)155 TEST_F(Rdata_MINFO_Test, assignment) {
156     generic::MINFO copy((string(minfo_txt2)));
157     copy = rdata_minfo;
158     EXPECT_EQ(0, copy.compare(rdata_minfo));
159 
160     // Check if the copied data is valid even after the original is deleted
161     generic::MINFO* copy2 = new generic::MINFO(rdata_minfo);
162     generic::MINFO copy3((string(minfo_txt2)));
163     copy3 = *copy2;
164     delete copy2;
165     EXPECT_EQ(0, copy3.compare(rdata_minfo));
166 
167     // Self assignment
168     copy = *&copy;
169     EXPECT_EQ(0, copy.compare(rdata_minfo));
170 }
171 
TEST_F(Rdata_MINFO_Test,toWireBuffer)172 TEST_F(Rdata_MINFO_Test, toWireBuffer) {
173     rdata_minfo.toWire(obuffer);
174     vector<unsigned char> data;
175     UnitTestUtil::readWireData("rdata_minfo_toWireUncompressed1.wire", data);
176     matchWireData(&data[0], data.size(),
177                   obuffer.getData(), obuffer.getLength());
178 
179     obuffer.clear();
180     rdata_minfo2.toWire(obuffer);
181     vector<unsigned char> data2;
182     UnitTestUtil::readWireData("rdata_minfo_toWireUncompressed2.wire", data2);
183     matchWireData(&data2[0], data2.size(),
184                   obuffer.getData(), obuffer.getLength());
185 }
186 
TEST_F(Rdata_MINFO_Test,toWireRenderer)187 TEST_F(Rdata_MINFO_Test, toWireRenderer) {
188     rdata_minfo.toWire(renderer);
189     vector<unsigned char> data;
190     UnitTestUtil::readWireData("rdata_minfo_toWire1.wire", data);
191     matchWireData(&data[0], data.size(),
192                   renderer.getData(), renderer.getLength());
193 
194     renderer.clear();
195     rdata_minfo2.toWire(renderer);
196     vector<unsigned char> data2;
197     UnitTestUtil::readWireData("rdata_minfo_toWire2.wire", data2);
198     matchWireData(&data2[0], data2.size(),
199                   renderer.getData(), renderer.getLength());
200 }
201 
TEST_F(Rdata_MINFO_Test,toText)202 TEST_F(Rdata_MINFO_Test, toText) {
203     EXPECT_EQ(minfo_txt, rdata_minfo.toText());
204     EXPECT_EQ(minfo_txt2, rdata_minfo2.toText());
205 }
206 
TEST_F(Rdata_MINFO_Test,compare)207 TEST_F(Rdata_MINFO_Test, compare) {
208     // check reflexivity
209     EXPECT_EQ(0, rdata_minfo.compare(rdata_minfo));
210 
211     // names must be compared in case-insensitive manner
212     EXPECT_EQ(0, rdata_minfo.compare(generic::MINFO("RMAILBOX.example.com. "
213                                                   "emailbox.EXAMPLE.com.")));
214 
215     // another MINFO whose rmailbox name is larger than that of rdata_minfo.
216     const generic::MINFO large1_minfo("zzzzzzzz.example.com. "
217                                       "emailbox.example.com.");
218     EXPECT_GT(0, rdata_minfo.compare(large1_minfo));
219     EXPECT_LT(0, large1_minfo.compare(rdata_minfo));
220 
221     // another MINFO whose emailbox name is larger than that of rdata_minfo.
222     const generic::MINFO large2_minfo("rmailbox.example.com. "
223                                       "zzzzzzzzzzz.example.com.");
224     EXPECT_GT(0, rdata_minfo.compare(large2_minfo));
225     EXPECT_LT(0, large2_minfo.compare(rdata_minfo));
226 
227     // comparison attempt between incompatible RR types should be rejected
228     EXPECT_THROW(rdata_minfo.compare(*RdataTest::rdata_nomatch), bad_cast);
229 }
230 }
231