noinst_LTLIBRARIES = libdatasrc_memory.la
libdatasrc_memory_la_SOURCES = \
- rdata_encoder.h \
- rdata_encoder.cc \
+ rdata_encoder.h rdata_encoder.cc \
+ rdata_field.h rdata_field.cc \
rdata_reader.h rdata_reader.cc \
domaintree.h
// 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>
#include <dns/rrclass.h>
#include <dns/rrtype.h>
-#include "rdata_encoder.h"
-
-#include <boost/static_assert.hpp>
-
#include <cassert>
#include <cstring>
#include <vector>
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.
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
--- /dev/null
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include "rdata_field.h"
+
+#include <boost/static_assert.hpp>
+
+using namespace isc::dns;
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+namespace {
+
+// 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);
+
+}
+
+const RdataEncodeSpec&
+getRdataEncodeSpec(const RRClass& rrclass, const 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);
+}
+
+}
+}
+}
--- /dev/null
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef DATASRC_MEMORY_RDATA_FIELD
+#define DATASRC_MEMORY_RDATA_FIELD
+
+#include "rdata_encoder.h"
+
+/// \file rdata_field.h
+///
+/// This header should be considered private to the implementation and should
+/// not be used from outside.
+///
+/// It is used to share the definition of encoding for RRtypes.
+
+namespace isc {
+namespace dns {
+class RRType;
+class RRClass;
+}
+namespace datasrc {
+namespace memory {
+
+/// 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
+};
+
+/// \brief Get the spec for given class and type
+const RdataEncodeSpec&
+getRdataEncodeSpec(const dns::RRClass& rrclass, const dns::RRType& rrtype);
+
+}
+}
+}
+
+#endif
#include <dns/rrtype.h>
#include <datasrc/memory/rdata_encoder.h>
+#include <datasrc/memory/rdata_field.h>
#include <util/unittests/wiredata.h>
// but it allows the tests to check the internals of the data.
class ManualDecoderStyle {
public:
+ static 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);
+ }
+
+ static 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];
+ }
+ }
+
static void decode(const isc::dns::RRClass& rrclass,
const isc::dns::RRType& rrtype,
size_t rdata_count,