rdata_encoder_unittest.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <exceptions/exceptions.h>
  15. #include <util/buffer.h>
  16. #include <dns/name.h>
  17. #include <dns/labelsequence.h>
  18. #include <dns/messagerenderer.h>
  19. #include <dns/rdata.h>
  20. #include <dns/rdataclass.h>
  21. #include <dns/rrclass.h>
  22. #include <dns/rrtype.h>
  23. #include <datasrc/memory/rdata_encoder.h>
  24. #include <util/unittests/wiredata.h>
  25. #include <gtest/gtest.h>
  26. #include <boost/bind.hpp>
  27. #include <boost/foreach.hpp>
  28. #include <cstring>
  29. #include <set>
  30. #include <string>
  31. #include <vector>
  32. using namespace isc::dns;
  33. using namespace isc::dns::rdata;
  34. using namespace isc::datasrc::memory;
  35. using namespace isc::datasrc::memory::testing;
  36. using isc::util::unittests::matchWireData;
  37. using std::string;
  38. using std::vector;
  39. namespace {
  40. // This defines a tuple of test data used in test_rdata_list below.
  41. struct TestRdata {
  42. const char* const rrclass; // RR class, textual form
  43. const char* const rrtype; // RR type, textual form
  44. const char* const rdata; // textual RDATA
  45. const size_t n_varlen_fields; // expected # of variable-len fields
  46. };
  47. // This test data consist of (almost) all supported types of RDATA (+ some
  48. // unusual and corner cases).
  49. const TestRdata test_rdata_list[] = {
  50. {"IN", "A", "192.0.2.1", 0},
  51. {"IN", "NS", "ns.example.com", 0},
  52. {"IN", "CNAME", "cname.example.com", 0},
  53. {"IN", "SOA", "ns.example.com root.example.com 0 0 0 0 0", 0},
  54. {"IN", "PTR", "reverse.example.com", 0},
  55. {"IN", "HINFO", "\"cpu-info\" \"OS-info\"", 1},
  56. {"IN", "MINFO", "root.example.com mbox.example.com", 0},
  57. {"IN", "MX", "10 mx.example.com", 0},
  58. {"IN", "TXT", "\"test1\" \"test 2\"", 1},
  59. {"IN", "RP", "root.example.com. rp-text.example.com", 0},
  60. {"IN", "AFSDB", "1 afsdb.example.com", 0},
  61. {"IN", "AAAA", "2001:db8::1", 0},
  62. {"IN", "SRV", "1 0 10 target.example.com", 0},
  63. {"IN", "NAPTR", "100 50 \"s\" \"http\" \"\" _http._tcp.example.com", 1},
  64. {"IN", "DNAME", "dname.example.com", 0},
  65. {"IN", "DS", "12892 5 2 5F0EB5C777586DE18DA6B5", 1},
  66. {"IN", "SSHFP", "1 1 dd465c09cfa51fb45020cc83316fff", 1},
  67. // We handle RRSIG separately, so it's excluded from the list
  68. {"IN", "NSEC", "next.example.com. A AAAA NSEC RRSIG", 1},
  69. {"IN", "DNSKEY", "256 3 5 FAKEFAKE", 1},
  70. {"IN", "DHCID", "FAKEFAKE", 1},
  71. {"IN", "NSEC3", "1 1 12 AABBCCDD FAKEFAKE A RRSIG", 1},
  72. {"IN", "NSEC3PARAM", "1 0 12 AABBCCDD", 1},
  73. {"IN", "SPF", "v=spf1 +mx a:colo.example.com/28 -all", 1},
  74. {"IN", "DLV", "12892 5 2 5F0EB5C777586DE18DA6B5", 1},
  75. {"IN", "TYPE65000", "\\# 3 010203", 1}, // some "custom" type
  76. {"IN", "TYPE65535", "\\# 0", 1}, // max RR type, 0-length RDATA
  77. {"CH", "A", "\\# 2 0102", 1}, // A RR for non-IN class; varlen data
  78. {"CH", "NS", "ns.example.com", 0}, // class CH, generic data
  79. {"CH", "TXT", "BIND10", 1}, // ditto
  80. {"HS", "A", "\\# 5 0102030405", 1}, // A RR for non-IN class; varlen data
  81. {NULL, NULL, NULL, 0}
  82. };
  83. // The following two functions will be used to generate wire format data
  84. // from encoded representation of each RDATA.
  85. void
  86. renderNameField(MessageRenderer* renderer, bool additional_required,
  87. const LabelSequence& labels, RdataNameAttributes attributes)
  88. {
  89. EXPECT_EQ(additional_required,
  90. (attributes & NAMEATTR_ADDITIONAL) != 0);
  91. renderer->writeName(labels, (attributes & NAMEATTR_COMPRESSIBLE) != 0);
  92. }
  93. void
  94. renderDataField(MessageRenderer* renderer, const uint8_t* data,
  95. size_t data_len)
  96. {
  97. renderer->writeData(data, data_len);
  98. }
  99. class RdataEncoderTest : public ::testing::Test {
  100. protected:
  101. RdataEncoderTest() : a_rdata_(createRdata(RRType::A(), RRClass::IN(),
  102. "192.0.2.53")),
  103. aaaa_rdata_(createRdata(RRType::AAAA(), RRClass::IN(),
  104. "2001:db8::53")),
  105. rrsig_rdata_(createRdata(
  106. RRType::RRSIG(), RRClass::IN(),
  107. "A 5 2 3600 20120814220826 "
  108. "20120715220826 12345 com. FAKE"))
  109. {}
  110. // This helper test method constructs encodes the given list of RDATAs
  111. // (in rdata_list), and then iterates over the data, rendering the fields
  112. // in the wire format. It then compares the wire data with the one
  113. // generated by the normal libdns++ interface to see the encoding/decoding
  114. // works as intended.
  115. void checkEncode(RRClass rrclass, RRType rrtype,
  116. const vector<ConstRdataPtr>& rdata_list,
  117. size_t expected_varlen_fields,
  118. const vector<ConstRdataPtr>& rrsig_list);
  119. void addRdataCommon(const vector<ConstRdataPtr>& rrsigs);
  120. void addRdataMultiCommon(const vector<ConstRdataPtr>& rrsigs);
  121. // Some commonly used RDATA
  122. const ConstRdataPtr a_rdata_;
  123. const ConstRdataPtr aaaa_rdata_;
  124. const ConstRdataPtr rrsig_rdata_;
  125. RdataEncoder encoder_;
  126. vector<uint8_t> encoded_data_;
  127. MessageRenderer expected_renderer_;
  128. MessageRenderer actual_renderer_;
  129. vector<ConstRdataPtr> rdata_list_;
  130. };
  131. void
  132. RdataEncoderTest::checkEncode(RRClass rrclass, RRType rrtype,
  133. const vector<ConstRdataPtr>& rdata_list,
  134. size_t expected_varlen_fields,
  135. const vector<ConstRdataPtr>& rrsig_list =
  136. vector<ConstRdataPtr>())
  137. {
  138. // These two names will be rendered before and after the test RDATA,
  139. // to check in case the RDATA contain a domain name whether it's
  140. // compressed or not correctly. The names in the RDATA should basically
  141. // a subdomain of example.com, so it can be compressed due to dummy_name.
  142. // Likewise, dummy_name2 should be able to be fully compressed due to
  143. // the name in the RDATA.
  144. const Name dummy_name("com");
  145. const Name dummy_name2("example.com");
  146. // The set of RR types that require additional section processing.
  147. // We'll pass it to renderNameField to check the stored attribute matches
  148. // our expectation.
  149. std::set<RRType> need_additionals;
  150. need_additionals.insert(RRType::NS());
  151. need_additionals.insert(RRType::MX());
  152. need_additionals.insert(RRType::SRV());
  153. expected_renderer_.clear();
  154. actual_renderer_.clear();
  155. encoded_data_.clear();
  156. const bool additional_required =
  157. (need_additionals.find(rrtype) != need_additionals.end());
  158. // Build expected wire-format data
  159. expected_renderer_.writeName(dummy_name);
  160. BOOST_FOREACH(const ConstRdataPtr& rdata, rdata_list) {
  161. rdata->toWire(expected_renderer_);
  162. }
  163. expected_renderer_.writeName(dummy_name2);
  164. BOOST_FOREACH(const ConstRdataPtr& rdata, rrsig_list) {
  165. rdata->toWire(expected_renderer_);
  166. }
  167. // Then build wire format data using the encoded data.
  168. // 1st dummy name
  169. actual_renderer_.writeName(dummy_name);
  170. // Create encoded data
  171. encoder_.start(rrclass, rrtype);
  172. BOOST_FOREACH(const ConstRdataPtr& rdata, rdata_list) {
  173. encoder_.addRdata(*rdata);
  174. }
  175. BOOST_FOREACH(const ConstRdataPtr& rdata, rrsig_list) {
  176. encoder_.addSIGRdata(*rdata);
  177. }
  178. encoded_data_.resize(encoder_.getStorageLength());
  179. encoder_.encode(&encoded_data_[0], encoded_data_.size());
  180. // If this type of RDATA is expected to contain variable-length fields,
  181. // we brute force the encoded data, exploiting our knowledge of actual
  182. // encoding, then adjust the encoded data excluding the list of length
  183. // fields. This is ugly, but we should be able to eliminate this hack
  184. // at #2096.
  185. vector<uint16_t> varlen_list;
  186. if (expected_varlen_fields > 0) {
  187. const size_t varlen_list_size =
  188. rdata_list.size() * expected_varlen_fields * sizeof(uint16_t);
  189. ASSERT_LE(varlen_list_size, encoded_data_.size());
  190. varlen_list.resize(rdata_list.size() * expected_varlen_fields);
  191. std::memcpy(&varlen_list[0], &encoded_data_[0], varlen_list_size);
  192. encoded_data_.assign(encoded_data_.begin() + varlen_list_size,
  193. encoded_data_.end());
  194. }
  195. // If RRSIGs are given, we need to extract the list of the RRSIG lengths
  196. // and adjust encoded_data_ further (this will be unnecessary at #2096,
  197. // too).
  198. vector<uint16_t> rrsiglen_list;
  199. if (rrsig_list.size() > 0) {
  200. const size_t rrsig_len_size = rrsig_list.size() * sizeof(uint16_t);
  201. ASSERT_LE(rrsig_len_size, encoded_data_.size());
  202. rrsiglen_list.resize(rrsig_list.size() * rrsig_len_size);
  203. std::memcpy(&rrsiglen_list[0], &encoded_data_[0], rrsig_len_size);
  204. encoded_data_.assign(encoded_data_.begin() + rrsig_len_size,
  205. encoded_data_.end());
  206. }
  207. // Create wire-format data from the encoded data
  208. foreachRdataField(rrclass, rrtype, rdata_list.size(), encoded_data_,
  209. varlen_list,
  210. boost::bind(renderNameField, &actual_renderer_,
  211. additional_required, _1, _2),
  212. boost::bind(renderDataField, &actual_renderer_, _1, _2));
  213. // 2nd dummy name
  214. actual_renderer_.writeName(dummy_name2);
  215. // Finally, dump any RRSIGs in wire format.
  216. foreachRRSig(encoded_data_, rrsiglen_list,
  217. boost::bind(renderDataField, &actual_renderer_, _1, _2));
  218. // Two sets of wire-format data should be identical.
  219. matchWireData(expected_renderer_.getData(), expected_renderer_.getLength(),
  220. actual_renderer_.getData(), actual_renderer_.getLength());
  221. }
  222. void
  223. RdataEncoderTest::addRdataCommon(const vector<ConstRdataPtr>& rrsigs) {
  224. // Basic check on the encoded data for (most of) all supported RR types,
  225. // in a comprehensive manner.
  226. for (size_t i = 0; test_rdata_list[i].rrclass != NULL; ++i) {
  227. SCOPED_TRACE(string(test_rdata_list[i].rrclass) + "/" +
  228. test_rdata_list[i].rrtype);
  229. const RRClass rrclass(test_rdata_list[i].rrclass);
  230. const RRType rrtype(test_rdata_list[i].rrtype);
  231. const ConstRdataPtr rdata = createRdata(rrtype, rrclass,
  232. test_rdata_list[i].rdata);
  233. rdata_list_.clear();
  234. rdata_list_.push_back(rdata);
  235. checkEncode(rrclass, rrtype, rdata_list_,
  236. test_rdata_list[i].n_varlen_fields, rrsigs);
  237. }
  238. }
  239. TEST_F(RdataEncoderTest, addRdata) {
  240. vector<ConstRdataPtr> rrsigs;
  241. addRdataCommon(rrsigs); // basic tests without RRSIGs (empty vector)
  242. // Test with RRSIGs (covered type doesn't always match, but the encoder
  243. // doesn't check that)
  244. rrsigs.push_back(rrsig_rdata_);
  245. addRdataCommon(rrsigs);
  246. }
  247. void
  248. RdataEncoderTest::addRdataMultiCommon(const vector<ConstRdataPtr>& rrsigs) {
  249. // Similar to addRdata(), but test with multiple RDATAs.
  250. // Four different cases are tested: a single fixed-len RDATA (A),
  251. // fixed-len data + domain name (MX), variable-len data only (TXT),
  252. // variable-len data + domain name (NAPTR).
  253. ConstRdataPtr a_rdata2 = createRdata(RRType::A(), RRClass::IN(),
  254. "192.0.2.54");
  255. rdata_list_.clear();
  256. rdata_list_.push_back(a_rdata_);
  257. rdata_list_.push_back(a_rdata2);
  258. checkEncode(RRClass::IN(), RRType::A(), rdata_list_, 0, rrsigs);
  259. ConstRdataPtr mx_rdata1 = createRdata(RRType::MX(), RRClass::IN(),
  260. "5 mx1.example.com");
  261. ConstRdataPtr mx_rdata2 = createRdata(RRType::MX(), RRClass::IN(),
  262. "10 mx2.example.com");
  263. rdata_list_.clear();
  264. rdata_list_.push_back(mx_rdata1);
  265. rdata_list_.push_back(mx_rdata2);
  266. checkEncode(RRClass::IN(), RRType::MX(), rdata_list_, 0, rrsigs);
  267. ConstRdataPtr txt_rdata1 = createRdata(RRType::TXT(), RRClass::IN(),
  268. "foo bar baz");
  269. ConstRdataPtr txt_rdata2 = createRdata(RRType::TXT(), RRClass::IN(),
  270. "another text data");
  271. rdata_list_.clear();
  272. rdata_list_.push_back(txt_rdata1);
  273. rdata_list_.push_back(txt_rdata2);
  274. checkEncode(RRClass::IN(), RRType::TXT(), rdata_list_, 1, rrsigs);
  275. ConstRdataPtr naptr_rdata1 =
  276. createRdata(RRType::NAPTR(), RRClass::IN(),
  277. "100 50 \"s\" \"http\" \"\" _http._tcp.example.com");
  278. ConstRdataPtr naptr_rdata2 =
  279. createRdata(RRType::NAPTR(), RRClass::IN(),
  280. "200 100 \"s\" \"http\" \"\" _http._tcp.example.com");
  281. rdata_list_.clear();
  282. rdata_list_.push_back(naptr_rdata1);
  283. rdata_list_.push_back(naptr_rdata2);
  284. checkEncode(RRClass::IN(), RRType::NAPTR(), rdata_list_, 1, rrsigs);
  285. }
  286. TEST_F(RdataEncoderTest, encodeLargeRdata) {
  287. // There should be no reason for a large RDATA to fail in encoding,
  288. // but we check such a case explicitly.
  289. encoded_data_.resize(65535); // max unsigned 16-bit int
  290. isc::util::InputBuffer buffer(&encoded_data_[0], encoded_data_.size());
  291. const in::DHCID large_dhcid(buffer, encoded_data_.size());
  292. encoder_.start(RRClass::IN(), RRType::DHCID());
  293. encoder_.addRdata(large_dhcid);
  294. encoded_data_.resize(encoder_.getStorageLength());
  295. encoder_.encode(&encoded_data_[0], encoded_data_.size());
  296. // The encoded data should be identical to the original one.
  297. ASSERT_LT(sizeof(uint16_t), encoder_.getStorageLength());
  298. isc::util::InputBuffer ib(&encoded_data_[2], encoded_data_.size() - 2);
  299. const in::DHCID encoded_dhcid(ib, ib.getLength());
  300. EXPECT_EQ(0, encoded_dhcid.compare(large_dhcid));
  301. }
  302. TEST_F(RdataEncoderTest, addRdataMulti) {
  303. vector<ConstRdataPtr> rrsigs;
  304. addRdataMultiCommon(rrsigs); // test without RRSIGs (empty vector)
  305. // Tests with two RRSIGs
  306. rrsigs.push_back(rrsig_rdata_);
  307. rrsigs.push_back(createRdata(RRType::RRSIG(), RRClass::IN(),
  308. "A 5 2 3600 20120814220826 "
  309. "20120715220826 54321 com. FAKE"));
  310. addRdataMultiCommon(rrsigs);
  311. }
  312. TEST_F(RdataEncoderTest, badAddRdata) {
  313. // Some operations must follow start().
  314. EXPECT_THROW(encoder_.addRdata(*a_rdata_), isc::InvalidOperation);
  315. EXPECT_THROW(encoder_.getStorageLength(), isc::InvalidOperation);
  316. encoded_data_.resize(256); // allocate space of some arbitrary size
  317. EXPECT_THROW(encoder_.encode(&encoded_data_[0], encoded_data_.size()),
  318. isc::InvalidOperation);
  319. // Bad buffer for encode
  320. encoder_.start(RRClass::IN(), RRType::A());
  321. encoder_.addRdata(*a_rdata_);
  322. const size_t buf_len = encoder_.getStorageLength();
  323. // NULL buffer for encode
  324. EXPECT_THROW(encoder_.encode(NULL, buf_len), isc::BadValue);
  325. // buffer length is too short
  326. encoded_data_.resize(buf_len - 1);
  327. EXPECT_THROW(encoder_.encode(&encoded_data_[0], buf_len - 1),
  328. isc::BadValue);
  329. encoded_data_.resize(buf_len + 1);
  330. encoder_.encode(&encoded_data_[1], buf_len);
  331. // Type of RDATA and the specified RR type don't match. addRdata() should
  332. // detect this inconsistency.
  333. encoder_.start(RRClass::IN(), RRType::AAAA());
  334. EXPECT_THROW(encoder_.addRdata(*a_rdata_), isc::BadValue);
  335. // Likewise.
  336. encoder_.start(RRClass::IN(), RRType::A());
  337. EXPECT_THROW(encoder_.addRdata(*aaaa_rdata_), isc::BadValue);
  338. // Likewise. The encoder expects the first name completes the data, and
  339. // throws on the second due as an unexpected name field.
  340. const ConstRdataPtr rp_rdata =
  341. createRdata(RRType::RP(), RRClass::IN(), "a.example. b.example");
  342. encoder_.start(RRClass::IN(), RRType::NS());
  343. EXPECT_THROW(encoder_.addRdata(*rp_rdata), isc::BadValue);
  344. // Likewise. The encoder considers the name data a variable length data
  345. // field, and throws on the first name.
  346. encoder_.start(RRClass::IN(), RRType::DHCID());
  347. EXPECT_THROW(encoder_.addRdata(*rp_rdata), isc::BadValue);
  348. // Likewise. The text RDATA (2 bytes) will be treated as MX preference,
  349. // and the encoder will still expect to see a domain name.
  350. const ConstRdataPtr txt_rdata = createRdata(RRType::TXT(), RRClass::IN(),
  351. "a");
  352. encoder_.start(RRClass::IN(), RRType::MX());
  353. EXPECT_THROW(encoder_.addRdata(*txt_rdata), isc::BadValue);
  354. // Likewise. Inconsistent name compression policy.
  355. const ConstRdataPtr ns_rdata =
  356. createRdata(RRType::NS(), RRClass::IN(), "ns.example");
  357. encoder_.start(RRClass::IN(), RRType::DNAME());
  358. EXPECT_THROW(encoder_.addRdata(*ns_rdata), isc::BadValue);
  359. // Same as the previous one, opposite inconsistency.
  360. const ConstRdataPtr dname_rdata =
  361. createRdata(RRType::DNAME(), RRClass::IN(), "dname.example");
  362. encoder_.start(RRClass::IN(), RRType::NS());
  363. EXPECT_THROW(encoder_.addRdata(*dname_rdata), isc::BadValue);
  364. // RDATA len exceeds the 16-bit range. Technically not invalid, but
  365. // we don't support that (and it's practically useless anyway).
  366. encoded_data_.resize(65536); // use encoded_data_ for placeholder
  367. isc::util::InputBuffer buffer(&encoded_data_[0], encoded_data_.size());
  368. encoder_.start(RRClass::IN(), RRType::DHCID());
  369. EXPECT_THROW(encoder_.addRdata(in::DHCID(buffer, encoded_data_.size())),
  370. RdataEncodingError);
  371. // RRSIG cannot be used as the main RDATA type (can only be added as
  372. // a signature for some other type of RDATAs).
  373. EXPECT_THROW(encoder_.start(RRClass::IN(), RRType::RRSIG()),
  374. isc::BadValue);
  375. }
  376. TEST_F(RdataEncoderTest, addSIGRdataOnly) {
  377. // Encoded data that only contain RRSIGs. Mostly useless, but can happen
  378. // (in a partially broken zone) and it's accepted.
  379. encoder_.start(RRClass::IN(), RRType::A());
  380. encoder_.addSIGRdata(*rrsig_rdata_);
  381. encoded_data_.resize(encoder_.getStorageLength());
  382. encoder_.encode(&encoded_data_[0], encoded_data_.size());
  383. ASSERT_LT(sizeof(uint16_t), encoder_.getStorageLength());
  384. // The encoded data should be identical to the given one.
  385. isc::util::InputBuffer ib(&encoded_data_[2], encoded_data_.size() - 2);
  386. const generic::RRSIG encoded_sig(ib, ib.getLength());
  387. EXPECT_EQ(0, encoded_sig.compare(*rrsig_rdata_));
  388. }
  389. TEST_F(RdataEncoderTest, badAddSIGRdata) {
  390. // try adding SIG before start
  391. EXPECT_THROW(encoder_.addSIGRdata(*rrsig_rdata_), isc::InvalidOperation);
  392. // Very big RRSIG. This implementation rejects it.
  393. isc::util::OutputBuffer ob(0);
  394. rrsig_rdata_->toWire(ob);
  395. // append dummy trailing signature to make it too big
  396. vector<uint8_t> dummy_sig(65536 - ob.getLength());
  397. ob.writeData(&dummy_sig[0], dummy_sig.size());
  398. ASSERT_EQ(65536, ob.getLength());
  399. isc::util::InputBuffer ib(ob.getData(), ob.getLength());
  400. const generic::RRSIG big_sigrdata(ib, ob.getLength());
  401. encoder_.start(RRClass::IN(), RRType::A());
  402. EXPECT_THROW(encoder_.addSIGRdata(big_sigrdata), RdataEncodingError);
  403. }
  404. }