rdata_encoder.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  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 <dns/name.h>
  15. #include <dns/labelsequence.h>
  16. #include <dns/rdata.h>
  17. #include <dns/rdataclass.h> // for a test function
  18. #include <dns/rrclass.h>
  19. #include <dns/rrtype.h>
  20. #include <util/buffer.h> // for test functions
  21. #include "rdata_encoder.h"
  22. #include <boost/static_assert.hpp>
  23. #include <cassert>
  24. #include <vector>
  25. #include <stdint.h>
  26. using namespace isc::dns;
  27. using std::vector;
  28. namespace isc {
  29. namespace datasrc {
  30. namespace memory {
  31. namespace {
  32. /// Specification of a single RDATA field in terms of internal encoding.
  33. struct RdataFieldSpec {
  34. enum FieldType {
  35. FIXEDLEN_DATA = 0, // fixed-length data field
  36. VARLEN_DATA, // variable-length data field
  37. DOMAIN_NAME // domain name
  38. };
  39. const FieldType type; // field type
  40. // type specific data. We use a union so it'll be clear only one of them
  41. // (determined by the type) is valid. Since we want to make it as
  42. // lightweight as possible, we use a relatively lower-level primitives
  43. // here.
  44. union {
  45. // The length of fixed-length data field. Only valid for FIXEDLEN_DATA
  46. const uint16_t fixeddata_len;
  47. // Attributes of the name. Only valid for DOMAIN_NAME.
  48. const RdataNameAttributes name_attributes;
  49. };
  50. };
  51. /// Specification of RDATA in terms of internal encoding.
  52. struct RdataEncodeSpec {
  53. const uint16_t field_count; // total number of fields (# of fields member)
  54. const uint16_t name_count; // number of domain name fields
  55. const uint16_t varlen_count; // number of variable-length data fields
  56. const RdataFieldSpec* const fields; // list of field specs
  57. };
  58. // These constants are convenient shortcut to initialize the name_attributes
  59. // member of RdataFieldSpec (since it's a union, we can only directly
  60. // initialize fixeddata_len member, so we need to convert it to its type).
  61. // These are essentially small integers, so the cast should be safe.
  62. const uint16_t NAMEATTR_NOATTRIBUTE_INITIALIZER = static_cast<uint16_t>(0);
  63. const uint16_t NAMEATTR_COMPRESSIBLE_INITIALIZER =
  64. static_cast<uint16_t>(NAMEATTR_COMPRESSIBLE);
  65. const uint16_t NAMEATTR_ADDITIONAL_INITIALIZER =
  66. static_cast<uint16_t>(NAMEATTR_ADDITIONAL);
  67. const uint16_t NAMEATTR_COMPADDITIONAL_INITIALIZER =
  68. static_cast<uint16_t>(NAMEATTR_COMPRESSIBLE | NAMEATTR_ADDITIONAL);
  69. // Many types of RDATA can be treated as a single-field, variable length
  70. // field (in terms of our encoding). The following define such most general
  71. // form of field spec.
  72. const RdataFieldSpec generic_data_fields[] = {
  73. {RdataFieldSpec::VARLEN_DATA, {0}}
  74. };
  75. const uint16_t n_generic_data_fields =
  76. sizeof(generic_data_fields) / sizeof(RdataFieldSpec);
  77. const RdataEncodeSpec generic_data_spec = {
  78. n_generic_data_fields, 0, 1, generic_data_fields
  79. };
  80. // RDATA consist of a single IPv4 address field.
  81. const RdataFieldSpec single_ipv4_fields[] = {
  82. {RdataFieldSpec::FIXEDLEN_DATA, {sizeof(uint32_t)}}
  83. };
  84. const uint16_t n_ipv4_fields =
  85. sizeof(single_ipv4_fields) / sizeof(RdataFieldSpec);
  86. // RDATA consist of a single IPv6 address field.
  87. const RdataFieldSpec single_ipv6_fields[] = {
  88. {RdataFieldSpec::FIXEDLEN_DATA, {16}} // 128bits = 16 bytes
  89. };
  90. const uint16_t n_ipv6_fields =
  91. sizeof(single_ipv6_fields) / sizeof(RdataFieldSpec);
  92. // There are several RR types that consist of a single domain name.
  93. const RdataFieldSpec single_noattr_name_fields[] = {
  94. {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_NOATTRIBUTE_INITIALIZER}}
  95. };
  96. const RdataFieldSpec single_compressible_name_fields[] = {
  97. {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_COMPRESSIBLE_INITIALIZER}}
  98. };
  99. const RdataFieldSpec single_compadditional_name_fields[] = {
  100. {RdataFieldSpec::DOMAIN_NAME,
  101. {NAMEATTR_COMPRESSIBLE_INITIALIZER|NAMEATTR_COMPADDITIONAL_INITIALIZER}}
  102. };
  103. const uint16_t n_single_name_fields =
  104. sizeof(single_noattr_name_fields) / sizeof(RdataFieldSpec);
  105. // RDATA consisting of two names. There are some of this type.
  106. const RdataFieldSpec double_compressible_name_fields[] = {
  107. {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_COMPRESSIBLE_INITIALIZER}},
  108. {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_COMPRESSIBLE_INITIALIZER}}
  109. };
  110. const RdataFieldSpec double_noattr_name_fields[] = {
  111. {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_NOATTRIBUTE_INITIALIZER}},
  112. {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_NOATTRIBUTE_INITIALIZER}}
  113. };
  114. const uint16_t n_double_name_fields =
  115. sizeof(double_compressible_name_fields) / sizeof(RdataFieldSpec);
  116. // SOA specific: two compressible names + 5*32-bit data
  117. const RdataFieldSpec soa_fields[] = {
  118. {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_COMPRESSIBLE_INITIALIZER}},
  119. {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_COMPRESSIBLE_INITIALIZER}},
  120. {RdataFieldSpec::FIXEDLEN_DATA, {sizeof(uint32_t) * 5}}
  121. };
  122. const uint16_t n_soa_fields = sizeof(soa_fields) / sizeof(RdataFieldSpec);
  123. // MX specific: 16-bit data + compressible/additional name
  124. const RdataFieldSpec mx_fields[] = {
  125. {RdataFieldSpec::FIXEDLEN_DATA, {sizeof(uint16_t)}},
  126. {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_COMPADDITIONAL_INITIALIZER}}
  127. };
  128. const uint16_t n_mx_fields = sizeof(mx_fields) / sizeof(RdataFieldSpec);
  129. // AFSDB specific: 16-bit data + no-attribute name
  130. const RdataFieldSpec afsdb_fields[] = {
  131. {RdataFieldSpec::FIXEDLEN_DATA, {sizeof(uint16_t)}},
  132. {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_NOATTRIBUTE_INITIALIZER}}
  133. };
  134. const uint16_t n_afsdb_fields = sizeof(afsdb_fields) / sizeof(RdataFieldSpec);
  135. // SRV specific: 3*16-bit data + additional name
  136. const RdataFieldSpec srv_fields[] = {
  137. {RdataFieldSpec::FIXEDLEN_DATA, {sizeof(uint16_t) * 3}},
  138. {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_ADDITIONAL_INITIALIZER}}
  139. };
  140. const uint16_t n_srv_fields = sizeof(srv_fields) / sizeof(RdataFieldSpec);
  141. // NAPTR specific: (multi-field) variable data + (additional) name
  142. // NAPTR requires complicated additional section handling; for now, we skip
  143. // the additional handling completely.
  144. const RdataFieldSpec naptr_fields[] = {
  145. {RdataFieldSpec::VARLEN_DATA, {0}},
  146. {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_NOATTRIBUTE_INITIALIZER}}
  147. };
  148. const uint16_t n_naptr_fields = sizeof(naptr_fields) / sizeof(RdataFieldSpec);
  149. // NSEC specific: no-attribute name + varlen data
  150. const RdataFieldSpec nsec_fields[] = {
  151. {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_NOATTRIBUTE_INITIALIZER}},
  152. {RdataFieldSpec::VARLEN_DATA, {0}}
  153. };
  154. const uint16_t n_nsec_fields = sizeof(nsec_fields) / sizeof(RdataFieldSpec);
  155. // Class IN encode specs. This gives a shortcut to the encode spec for
  156. // some well-known types of RDATA specific to class IN (most of which are
  157. // generic and can be used for other classes). The array index is the
  158. // RR type code.
  159. const RdataEncodeSpec encode_spec_list_in[] = {
  160. generic_data_spec, // #0: (NONE)
  161. {n_ipv4_fields, 0, 0, single_ipv4_fields}, // #1: A
  162. {n_single_name_fields, 1, 0, single_compadditional_name_fields}, // #2: NS
  163. generic_data_spec, // #3
  164. generic_data_spec, // #4
  165. {n_single_name_fields, 1, 0, single_compressible_name_fields}, // #5: CNAME
  166. {n_soa_fields, 2, 0, soa_fields}, // #6: SOA
  167. generic_data_spec, // #7
  168. generic_data_spec, // #8
  169. generic_data_spec, // #9
  170. generic_data_spec, // #10
  171. generic_data_spec, // #11
  172. {n_single_name_fields, 1, 0, single_compressible_name_fields}, // #12: PTR
  173. generic_data_spec, // #13: HINFO
  174. {n_double_name_fields, 2, 0, double_compressible_name_fields}, // #14:HINFO
  175. {n_mx_fields, 1, 0, mx_fields}, // #15: MX
  176. generic_data_spec, // #16: TXT
  177. {n_double_name_fields, 2, 0, double_noattr_name_fields}, // 17: RP
  178. {n_afsdb_fields, 1, 0, afsdb_fields}, // #18: AFSDB
  179. // #19-#26
  180. generic_data_spec, generic_data_spec, generic_data_spec, generic_data_spec,
  181. generic_data_spec, generic_data_spec, generic_data_spec, generic_data_spec,
  182. generic_data_spec, // #27
  183. {n_ipv6_fields, 0, 0, single_ipv6_fields}, // #28: AAAA
  184. // #29-#32
  185. generic_data_spec, generic_data_spec, generic_data_spec, generic_data_spec,
  186. {n_srv_fields, 1, 0, srv_fields}, // #33: SRV
  187. generic_data_spec, // #34
  188. {n_naptr_fields, 1, 1, naptr_fields}, // #35: NAPTR
  189. generic_data_spec, // #36
  190. generic_data_spec, // #37
  191. generic_data_spec, // #38
  192. {n_single_name_fields, 1, 0, single_noattr_name_fields}, // #39 DNAME
  193. generic_data_spec, // #40
  194. generic_data_spec, // #41 (OPT)
  195. generic_data_spec, // #42
  196. generic_data_spec, // #43: DS (this is opaque for encoding purposes)
  197. generic_data_spec, // #44: SSHFP (this is opaque for encoding purposes)
  198. generic_data_spec, // #45
  199. generic_data_spec, // #46: RRSIG (this is opaque for encoding purposes)
  200. {n_nsec_fields, 1, 1, nsec_fields} // #47: NSEC
  201. // All others can be treated as single-field variable length data, at
  202. // least for currently supported RR types.
  203. };
  204. // # of entries in encode_spec_list_in
  205. const size_t encode_spec_list_in_size =
  206. sizeof(encode_spec_list_in) / sizeof(encode_spec_list_in[0]);
  207. BOOST_STATIC_ASSERT(encode_spec_list_in_size == 48);
  208. inline
  209. const RdataEncodeSpec&
  210. getRdataEncodeSpec(RRClass rrclass, RRType rrtype) {
  211. // Special case: for classes other than IN, we treat RDATA of RR types
  212. // that are class-IN specific as generic opaque data.
  213. if (rrclass != RRClass::IN() &&
  214. (rrtype == RRType::A() || rrtype == RRType::AAAA() ||
  215. rrtype == RRType::SRV())) {
  216. return (generic_data_spec);
  217. }
  218. // Otherwise, if the type is in the pre-defined range, we use the defined
  219. // spec; otherwise we treat it as opaque data.
  220. const uint16_t typecode = rrtype.getCode();
  221. if (typecode < encode_spec_list_in_size) {
  222. return (encode_spec_list_in[rrtype.getCode()]);
  223. }
  224. return (generic_data_spec);
  225. }
  226. // A temporary helper of temporary encodeRdata(): it calculates the length
  227. // of the data portion of a NAPTR RDATA (i.e., the RDATA fields before the
  228. // "replacement" name).
  229. size_t
  230. getNAPTRDataLen(const rdata::Rdata& rdata) {
  231. const rdata::generic::NAPTR& naptr_rdata =
  232. dynamic_cast<const rdata::generic::NAPTR&>(rdata);
  233. util::OutputBuffer buffer(0);
  234. rdata.toWire(buffer);
  235. return (buffer.getLength() - naptr_rdata.getReplacement().getLength());
  236. }
  237. } // end of unnamed namespace
  238. namespace testing {
  239. void
  240. encodeRdata(const rdata::Rdata& rdata, RRClass rrclass, RRType rrtype,
  241. vector<uint8_t>& data_result, vector<uint16_t>& len_result)
  242. {
  243. util::OutputBuffer buffer(0);
  244. rdata.toWire(buffer);
  245. util::InputBuffer ibuffer(buffer.getData(), buffer.getLength());
  246. vector<uint8_t> tmp; // used as temporary placeholder below
  247. const RdataEncodeSpec& encode_spec = getRdataEncodeSpec(rrclass, rrtype);
  248. for (size_t i = 0; i < encode_spec.field_count; ++i) {
  249. const RdataFieldSpec& field_spec = encode_spec.fields[i];
  250. switch (field_spec.type) {
  251. case RdataFieldSpec::FIXEDLEN_DATA:
  252. tmp.resize(field_spec.fixeddata_len);
  253. ibuffer.readData(&tmp[0], tmp.size());
  254. data_result.insert(data_result.end(), tmp.begin(), tmp.end());
  255. break;
  256. case RdataFieldSpec::VARLEN_DATA:
  257. {
  258. // In the vast majority cases of our supported RR types,
  259. // variable-length data fields are placed at the end of RDATA,
  260. // so the length of the field should be the remaining length
  261. // of the output buffer. The only exception is NAPTR, for which
  262. // we use an ad hoc workaround (remember this function is for
  263. // initial testing only, and will be cleaned up eventually).
  264. const size_t pos = ibuffer.getPosition();
  265. const size_t data_len = rrtype == RRType::NAPTR() ?
  266. getNAPTRDataLen(rdata) : (ibuffer.getLength() - pos);
  267. tmp.resize(data_len);
  268. ibuffer.readData(&tmp[0], tmp.size());
  269. data_result.insert(data_result.end(), tmp.begin(), tmp.end());
  270. len_result.push_back(data_len);
  271. break;
  272. }
  273. case RdataFieldSpec::DOMAIN_NAME:
  274. {
  275. const Name name(ibuffer);
  276. const LabelSequence labels(name);
  277. size_t nlen;
  278. const uint8_t* ndata = labels.getData(&nlen);
  279. size_t olen;
  280. uint8_t offset_holder[Name::MAX_LABELS];
  281. labels.getOffsetData(&olen, offset_holder);
  282. data_result.push_back(nlen);
  283. data_result.push_back(olen);
  284. data_result.insert(data_result.end(), ndata, ndata + nlen);
  285. data_result.insert(data_result.end(), offset_holder,
  286. offset_holder + olen);
  287. break;
  288. }
  289. }
  290. }
  291. }
  292. void
  293. foreachRdataField(RRClass rrclass, RRType rrtype,
  294. const vector<uint8_t>& encoded_data,
  295. const vector<uint16_t>& varlen_list,
  296. NameCallback name_callback, DataCallback data_callback)
  297. {
  298. const RdataEncodeSpec& encode_spec = getRdataEncodeSpec(rrclass, rrtype);
  299. size_t off = 0;
  300. size_t varlen_count = 0;
  301. size_t name_count = 0;
  302. for (size_t i = 0; i < encode_spec.field_count; ++i) {
  303. const RdataFieldSpec& field_spec = encode_spec.fields[i];
  304. switch (field_spec.type) {
  305. case RdataFieldSpec::FIXEDLEN_DATA:
  306. if (data_callback) {
  307. data_callback(&encoded_data.at(off), field_spec.fixeddata_len);
  308. }
  309. off += field_spec.fixeddata_len;
  310. break;
  311. case RdataFieldSpec::VARLEN_DATA:
  312. {
  313. const size_t varlen = varlen_list.at(varlen_count);
  314. if (data_callback && varlen > 0) {
  315. data_callback(&encoded_data.at(off), varlen);
  316. }
  317. off += varlen;
  318. ++varlen_count;
  319. break;
  320. }
  321. case RdataFieldSpec::DOMAIN_NAME:
  322. {
  323. ++name_count;
  324. const uint8_t nlen = encoded_data.at(off);
  325. const uint8_t olen = encoded_data.at(off + 1);
  326. if (name_callback) {
  327. const uint8_t* ndata = &encoded_data.at(off + 2);
  328. const uint8_t* odata = &encoded_data.at(off + 2 + nlen);
  329. name_callback(LabelSequence(ndata, odata, olen),
  330. field_spec.name_attributes);
  331. }
  332. off += (2 + nlen + olen);
  333. break;
  334. }
  335. }
  336. }
  337. assert(name_count == encode_spec.name_count);
  338. assert(varlen_count == encode_spec.varlen_count);
  339. }
  340. } // namespace testing
  341. } // namespace memory
  342. } // namespace datasrc
  343. } // datasrc isc