|
@@ -12,6 +12,9 @@
|
|
|
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
// PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
|
+#include "rdata_encoder.h"
|
|
|
+#include "rdata_field.h"
|
|
|
+
|
|
|
#include <exceptions/exceptions.h>
|
|
|
|
|
|
#include <util/buffer.h>
|
|
@@ -23,10 +26,6 @@
|
|
|
#include <dns/rrclass.h>
|
|
|
#include <dns/rrtype.h>
|
|
|
|
|
|
-#include "rdata_encoder.h"
|
|
|
-
|
|
|
-#include <boost/static_assert.hpp>
|
|
|
-
|
|
|
#include <cassert>
|
|
|
#include <cstring>
|
|
|
#include <vector>
|
|
@@ -41,227 +40,6 @@ namespace datasrc {
|
|
|
namespace memory {
|
|
|
|
|
|
namespace {
|
|
|
-/// Specification of a single RDATA field in terms of internal encoding.
|
|
|
-struct RdataFieldSpec {
|
|
|
- enum FieldType {
|
|
|
- FIXEDLEN_DATA = 0, // fixed-length data field
|
|
|
- VARLEN_DATA, // variable-length data field
|
|
|
- DOMAIN_NAME // domain name
|
|
|
- };
|
|
|
-
|
|
|
- const FieldType type; // field type
|
|
|
-
|
|
|
- // The length of fixed-length data field. Only valid for FIXEDLEN_DATA.
|
|
|
- // For type DOMAIN_NAME, set it to 0.
|
|
|
- const uint16_t fixeddata_len;
|
|
|
-
|
|
|
- // Attributes of the name. Only valid for DOMAIN_NAME.
|
|
|
- // For type _DATA, set it to NAMEATTR_NONE.
|
|
|
- const RdataNameAttributes name_attributes;
|
|
|
-};
|
|
|
-
|
|
|
-/// Specification of RDATA in terms of internal encoding.
|
|
|
-///
|
|
|
-/// The fields must be a sequence of:
|
|
|
-/// <0 or 1 fixed/var-len data field>,
|
|
|
-/// <1 or more domain name fields>,
|
|
|
-/// <1 fixed/var-len data field>,
|
|
|
-/// <1 or more domain name fields>,
|
|
|
-/// <1 fixed/var-len data field>,
|
|
|
-/// ...and so on.
|
|
|
-/// There must not be more than one consecutive data fields (i.e., without
|
|
|
-/// interleaved by a domain name); it would just be inefficient in terms of
|
|
|
-/// memory footprint and iterating over the fields, and it would break
|
|
|
-/// some assumption within the encoder implementation. For consecutive
|
|
|
-/// data fields in the DNS protocol, if all fields have fixed lengths, they
|
|
|
-/// should be combined into a single fixed-length field (like the last 20
|
|
|
-/// bytes of SOA RDATA). If there's a variable length field, they should be
|
|
|
-/// combined into a single variable-length field (such as DNSKEY, which has
|
|
|
-/// 3 fixed-length fields followed by one variable-length field).
|
|
|
-struct RdataEncodeSpec {
|
|
|
- const uint16_t field_count; // total number of fields (# of fields member)
|
|
|
- const uint16_t name_count; // number of domain name fields
|
|
|
- const uint16_t varlen_count; // number of variable-length data fields
|
|
|
- const RdataFieldSpec* const fields; // list of field specs
|
|
|
-};
|
|
|
-
|
|
|
-// Many types of RDATA can be treated as a single-field, variable length
|
|
|
-// field (in terms of our encoding). The following define such most general
|
|
|
-// form of field spec.
|
|
|
-const RdataFieldSpec generic_data_fields[] = {
|
|
|
- {RdataFieldSpec::VARLEN_DATA, 0, NAMEATTR_NONE}
|
|
|
-};
|
|
|
-const uint16_t n_generic_data_fields =
|
|
|
- sizeof(generic_data_fields) / sizeof(RdataFieldSpec);
|
|
|
-const RdataEncodeSpec generic_data_spec = {
|
|
|
- n_generic_data_fields, 0, 1, generic_data_fields
|
|
|
-};
|
|
|
-
|
|
|
-// RDATA consist of a single IPv4 address field.
|
|
|
-const RdataFieldSpec single_ipv4_fields[] = {
|
|
|
- {RdataFieldSpec::FIXEDLEN_DATA, sizeof(uint32_t), NAMEATTR_NONE}
|
|
|
-};
|
|
|
-const uint16_t n_ipv4_fields =
|
|
|
- sizeof(single_ipv4_fields) / sizeof(RdataFieldSpec);
|
|
|
-
|
|
|
-// RDATA consist of a single IPv6 address field.
|
|
|
-const RdataFieldSpec single_ipv6_fields[] = {
|
|
|
- {RdataFieldSpec::FIXEDLEN_DATA, 16, NAMEATTR_NONE} // 128bits = 16 bytes
|
|
|
-};
|
|
|
-const uint16_t n_ipv6_fields =
|
|
|
- sizeof(single_ipv6_fields) / sizeof(RdataFieldSpec);
|
|
|
-
|
|
|
-// There are several RR types that consist of a single domain name.
|
|
|
-const RdataFieldSpec single_noattr_name_fields[] = {
|
|
|
- {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_NONE}
|
|
|
-};
|
|
|
-const RdataFieldSpec single_compressible_name_fields[] = {
|
|
|
- {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_COMPRESSIBLE}
|
|
|
-};
|
|
|
-const RdataFieldSpec single_compadditional_name_fields[] = {
|
|
|
- {RdataFieldSpec::DOMAIN_NAME, 0,
|
|
|
- static_cast<RdataNameAttributes>(
|
|
|
- static_cast<unsigned int>(NAMEATTR_COMPRESSIBLE) |
|
|
|
- static_cast<unsigned int>(NAMEATTR_ADDITIONAL))}
|
|
|
-};
|
|
|
-const uint16_t n_single_name_fields =
|
|
|
- sizeof(single_noattr_name_fields) / sizeof(RdataFieldSpec);
|
|
|
-
|
|
|
-// RDATA consisting of two names. There are some of this type.
|
|
|
-const RdataFieldSpec double_compressible_name_fields[] = {
|
|
|
- {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_COMPRESSIBLE},
|
|
|
- {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_COMPRESSIBLE}
|
|
|
-};
|
|
|
-const RdataFieldSpec double_noattr_name_fields[] = {
|
|
|
- {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_NONE},
|
|
|
- {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_NONE}
|
|
|
-};
|
|
|
-const uint16_t n_double_name_fields =
|
|
|
- sizeof(double_compressible_name_fields) / sizeof(RdataFieldSpec);
|
|
|
-
|
|
|
-// SOA specific: two compressible names + 5*32-bit data
|
|
|
-const RdataFieldSpec soa_fields[] = {
|
|
|
- {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_COMPRESSIBLE},
|
|
|
- {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_COMPRESSIBLE},
|
|
|
- {RdataFieldSpec::FIXEDLEN_DATA, sizeof(uint32_t) * 5, NAMEATTR_NONE}
|
|
|
-};
|
|
|
-const uint16_t n_soa_fields = sizeof(soa_fields) / sizeof(RdataFieldSpec);
|
|
|
-
|
|
|
-// MX specific: 16-bit data + compressible/additional name
|
|
|
-const RdataFieldSpec mx_fields[] = {
|
|
|
- {RdataFieldSpec::FIXEDLEN_DATA, sizeof(uint16_t), NAMEATTR_NONE},
|
|
|
- {RdataFieldSpec::DOMAIN_NAME, 0,
|
|
|
- static_cast<RdataNameAttributes>(
|
|
|
- static_cast<unsigned int>(NAMEATTR_COMPRESSIBLE) |
|
|
|
- static_cast<unsigned int>(NAMEATTR_ADDITIONAL))}
|
|
|
-};
|
|
|
-const uint16_t n_mx_fields = sizeof(mx_fields) / sizeof(RdataFieldSpec);
|
|
|
-
|
|
|
-// AFSDB specific: 16-bit data + no-attribute name
|
|
|
-const RdataFieldSpec afsdb_fields[] = {
|
|
|
- {RdataFieldSpec::FIXEDLEN_DATA, sizeof(uint16_t), NAMEATTR_NONE},
|
|
|
- {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_NONE}
|
|
|
-};
|
|
|
-const uint16_t n_afsdb_fields = sizeof(afsdb_fields) / sizeof(RdataFieldSpec);
|
|
|
-
|
|
|
-// SRV specific: 3*16-bit data + additional name
|
|
|
-const RdataFieldSpec srv_fields[] = {
|
|
|
- {RdataFieldSpec::FIXEDLEN_DATA, sizeof(uint16_t) * 3, NAMEATTR_NONE},
|
|
|
- {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_ADDITIONAL}
|
|
|
-};
|
|
|
-const uint16_t n_srv_fields = sizeof(srv_fields) / sizeof(RdataFieldSpec);
|
|
|
-
|
|
|
-// NAPTR specific: (multi-field) variable data + (additional) name
|
|
|
-// NAPTR requires complicated additional section handling; for now, we skip
|
|
|
-// the additional handling completely.
|
|
|
-const RdataFieldSpec naptr_fields[] = {
|
|
|
- {RdataFieldSpec::VARLEN_DATA, 0, NAMEATTR_NONE},
|
|
|
- {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_NONE}
|
|
|
-};
|
|
|
-const uint16_t n_naptr_fields = sizeof(naptr_fields) / sizeof(RdataFieldSpec);
|
|
|
-
|
|
|
-// NSEC specific: no-attribute name + varlen data
|
|
|
-const RdataFieldSpec nsec_fields[] = {
|
|
|
- {RdataFieldSpec::DOMAIN_NAME, 0, NAMEATTR_NONE},
|
|
|
- {RdataFieldSpec::VARLEN_DATA, 0, NAMEATTR_NONE}
|
|
|
-};
|
|
|
-const uint16_t n_nsec_fields = sizeof(nsec_fields) / sizeof(RdataFieldSpec);
|
|
|
-
|
|
|
-// Class IN encode specs. This gives a shortcut to the encode spec for
|
|
|
-// some well-known types of RDATA specific to class IN (most of which are
|
|
|
-// generic and can be used for other classes). The array index is the
|
|
|
-// RR type code.
|
|
|
-const RdataEncodeSpec encode_spec_list_in[] = {
|
|
|
- generic_data_spec, // #0: (NONE)
|
|
|
- {n_ipv4_fields, 0, 0, single_ipv4_fields}, // #1: A
|
|
|
- {n_single_name_fields, 1, 0, single_compadditional_name_fields}, // #2: NS
|
|
|
- generic_data_spec, // #3
|
|
|
- generic_data_spec, // #4
|
|
|
- {n_single_name_fields, 1, 0, single_compressible_name_fields}, // #5: CNAME
|
|
|
- {n_soa_fields, 2, 0, soa_fields}, // #6: SOA
|
|
|
- generic_data_spec, // #7
|
|
|
- generic_data_spec, // #8
|
|
|
- generic_data_spec, // #9
|
|
|
- generic_data_spec, // #10
|
|
|
- generic_data_spec, // #11
|
|
|
- {n_single_name_fields, 1, 0, single_compressible_name_fields}, // #12: PTR
|
|
|
- generic_data_spec, // #13: HINFO
|
|
|
- {n_double_name_fields, 2, 0, double_compressible_name_fields}, // #14:HINFO
|
|
|
- {n_mx_fields, 1, 0, mx_fields}, // #15: MX
|
|
|
- generic_data_spec, // #16: TXT
|
|
|
- {n_double_name_fields, 2, 0, double_noattr_name_fields}, // 17: RP
|
|
|
- {n_afsdb_fields, 1, 0, afsdb_fields}, // #18: AFSDB
|
|
|
- // #19-#26
|
|
|
- generic_data_spec, generic_data_spec, generic_data_spec, generic_data_spec,
|
|
|
- generic_data_spec, generic_data_spec, generic_data_spec, generic_data_spec,
|
|
|
- generic_data_spec, // #27
|
|
|
- {n_ipv6_fields, 0, 0, single_ipv6_fields}, // #28: AAAA
|
|
|
- // #29-#32
|
|
|
- generic_data_spec, generic_data_spec, generic_data_spec, generic_data_spec,
|
|
|
- {n_srv_fields, 1, 0, srv_fields}, // #33: SRV
|
|
|
- generic_data_spec, // #34
|
|
|
- {n_naptr_fields, 1, 1, naptr_fields}, // #35: NAPTR
|
|
|
- generic_data_spec, // #36
|
|
|
- generic_data_spec, // #37
|
|
|
- generic_data_spec, // #38
|
|
|
- {n_single_name_fields, 1, 0, single_noattr_name_fields}, // #39 DNAME
|
|
|
- generic_data_spec, // #40
|
|
|
- generic_data_spec, // #41 (OPT)
|
|
|
- generic_data_spec, // #42
|
|
|
- generic_data_spec, // #43: DS (this is opaque for encoding purposes)
|
|
|
- generic_data_spec, // #44: SSHFP (this is opaque for encoding purposes)
|
|
|
- generic_data_spec, // #45
|
|
|
- generic_data_spec, // #46: RRSIG (this is opaque for encoding purposes)
|
|
|
- {n_nsec_fields, 1, 1, nsec_fields} // #47: NSEC
|
|
|
-
|
|
|
- // All others can be treated as single-field variable length data, at
|
|
|
- // least for currently supported RR types.
|
|
|
-};
|
|
|
-
|
|
|
-// # of entries in encode_spec_list_in
|
|
|
-const size_t encode_spec_list_in_size =
|
|
|
- sizeof(encode_spec_list_in) / sizeof(encode_spec_list_in[0]);
|
|
|
-BOOST_STATIC_ASSERT(encode_spec_list_in_size == 48);
|
|
|
-
|
|
|
-inline
|
|
|
-const RdataEncodeSpec&
|
|
|
-getRdataEncodeSpec(RRClass rrclass, RRType rrtype) {
|
|
|
- // Special case: for classes other than IN, we treat RDATA of RR types
|
|
|
- // that are class-IN specific as generic opaque data.
|
|
|
- if (rrclass != RRClass::IN() &&
|
|
|
- (rrtype == RRType::A() || rrtype == RRType::AAAA() ||
|
|
|
- rrtype == RRType::SRV())) {
|
|
|
- return (generic_data_spec);
|
|
|
- }
|
|
|
-
|
|
|
- // Otherwise, if the type is in the pre-defined range, we use the defined
|
|
|
- // spec; otherwise we treat it as opaque data.
|
|
|
- const uint16_t typecode = rrtype.getCode();
|
|
|
- if (typecode < encode_spec_list_in_size) {
|
|
|
- return (encode_spec_list_in[rrtype.getCode()]);
|
|
|
- }
|
|
|
- return (generic_data_spec);
|
|
|
-}
|
|
|
|
|
|
// This class is a helper for RdataEncoder to divide the content of RDATA
|
|
|
// fields for encoding by "abusing" the message rendering logic.
|
|
@@ -525,77 +303,6 @@ RdataEncoder::encode(void* buf, size_t buf_len) const {
|
|
|
assert(buf_len >= dp - dp_beg);
|
|
|
}
|
|
|
|
|
|
-namespace testing {
|
|
|
-void
|
|
|
-foreachRdataField(RRClass rrclass, RRType rrtype,
|
|
|
- size_t rdata_count,
|
|
|
- const vector<uint8_t>& encoded_data,
|
|
|
- const vector<uint16_t>& varlen_list,
|
|
|
- NameCallback name_callback, DataCallback data_callback)
|
|
|
-{
|
|
|
- const RdataEncodeSpec& encode_spec = getRdataEncodeSpec(rrclass, rrtype);
|
|
|
-
|
|
|
- size_t off = 0;
|
|
|
- size_t varlen_count = 0;
|
|
|
- size_t name_count = 0;
|
|
|
- for (size_t count = 0; count < rdata_count; ++count) {
|
|
|
- for (size_t i = 0; i < encode_spec.field_count; ++i) {
|
|
|
- const RdataFieldSpec& field_spec = encode_spec.fields[i];
|
|
|
- switch (field_spec.type) {
|
|
|
- case RdataFieldSpec::FIXEDLEN_DATA:
|
|
|
- if (data_callback) {
|
|
|
- data_callback(&encoded_data.at(off),
|
|
|
- field_spec.fixeddata_len);
|
|
|
- }
|
|
|
- off += field_spec.fixeddata_len;
|
|
|
- break;
|
|
|
- case RdataFieldSpec::VARLEN_DATA:
|
|
|
- {
|
|
|
- const size_t varlen = varlen_list.at(varlen_count);
|
|
|
- if (data_callback && varlen > 0) {
|
|
|
- data_callback(&encoded_data.at(off), varlen);
|
|
|
- }
|
|
|
- off += varlen;
|
|
|
- ++varlen_count;
|
|
|
- break;
|
|
|
- }
|
|
|
- case RdataFieldSpec::DOMAIN_NAME:
|
|
|
- {
|
|
|
- ++name_count;
|
|
|
- const LabelSequence labels(&encoded_data.at(off));
|
|
|
- if (name_callback) {
|
|
|
- name_callback(labels, field_spec.name_attributes);
|
|
|
- }
|
|
|
- off += labels.getSerializedLength();
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- assert(name_count == encode_spec.name_count * rdata_count);
|
|
|
- assert(varlen_count == encode_spec.varlen_count * rdata_count);
|
|
|
-}
|
|
|
-
|
|
|
-void
|
|
|
-foreachRRSig(const vector<uint8_t>& encoded_data,
|
|
|
- const vector<uint16_t>& rrsiglen_list,
|
|
|
- DataCallback data_callback)
|
|
|
-{
|
|
|
- size_t rrsig_totallen = 0;
|
|
|
- for (vector<uint16_t>::const_iterator it = rrsiglen_list.begin();
|
|
|
- it != rrsiglen_list.end();
|
|
|
- ++it) {
|
|
|
- rrsig_totallen += *it;
|
|
|
- }
|
|
|
- assert(encoded_data.size() >= rrsig_totallen);
|
|
|
-
|
|
|
- const uint8_t* dp = &encoded_data[encoded_data.size() - rrsig_totallen];
|
|
|
- for (size_t i = 0; i < rrsiglen_list.size(); ++i) {
|
|
|
- data_callback(dp, rrsiglen_list[i]);
|
|
|
- dp += rrsiglen_list[i];
|
|
|
- }
|
|
|
-}
|
|
|
-} // namespace testing
|
|
|
|
|
|
} // namespace memory
|
|
|
} // namespace datasrc
|