Commit 0019f64f authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[2097] Merge branch 'trac2096' into trac2097

parents ab4d2090 87830ae5
......@@ -11,6 +11,7 @@ CLEANFILES = *.gcno *.gcda datasrc_messages.h datasrc_messages.cc
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
......@@ -12,6 +12,8 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "rdata_encoder.h"
#include <exceptions/exceptions.h>
#include <util/buffer.h>
......@@ -23,16 +25,10 @@
#include <dns/rrclass.h>
#include <dns/rrtype.h>
#include "rdata_encoder.h"
#include <boost/static_assert.hpp>
#include <cassert>
#include <cstring>
#include <vector>
#include <stdint.h>
using namespace isc::dns;
using std::vector;
......@@ -41,227 +37,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 +300,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
......
......@@ -15,6 +15,8 @@
#ifndef DATASRC_MEMORY_RDATA_ENCODER_H
#define DATASRC_MEMORY_RDATA_ENCODER_H 1
#include "rdata_field.h"
#include <exceptions/exceptions.h>
#include <dns/labelsequence.h>
......@@ -106,18 +108,6 @@ public:
Exception(file, line, what) {}
};
/// \brief Attributes of domain name fields of encoded RDATA.
///
/// The enum values define special traits of the name that can affect how
/// it should be handled in rendering or query processing.
enum RdataNameAttributes {
NAMEATTR_NONE = 0, ///< No special attributes
NAMEATTR_COMPRESSIBLE = 1, ///< Name should be compressed when rendered
NAMEATTR_ADDITIONAL = (NAMEATTR_COMPRESSIBLE << 1) ///< Name requires
///< Additional section
///< handling
};
/// \brief RDATA encoder.
///
/// This class provides interfaces to encode a set of RDATA of a specific
......@@ -276,38 +266,6 @@ private:
RdataEncoderImpl* impl_;
};
// We use the following quick-hack version of "foreach"
// operators until we implement the complete versions. The plan is to
// update the test cases that use these functions with the complete
// functions/classes, and then remove the entire namespace.
namespace testing {
// Callbacks used in foreachRdataField.
typedef boost::function<void(const dns::LabelSequence&,
RdataNameAttributes)> NameCallback;
typedef boost::function<void(const uint8_t*, size_t)> DataCallback;
// Iterate over each field (in terms of the internal encoding) of each
// RDATA stored in encoded_data, and call the given callback for each
// data (for domain name fields, name_callback will be called; for
// normal data fields data_callback will be called). rdata_count is
// the number of RDATAs. If the encoded data contain variable-length
// data fields, varlen_list should store a sequence of their lengths,
// in the order of the appearance.
void foreachRdataField(dns::RRClass rrclass, dns::RRType rrtype,
size_t rdata_count,
const std::vector<uint8_t>& encoded_data,
const std::vector<uint16_t>& varlen_list,
NameCallback name_callback, DataCallback data_callback);
// Iterate over each RRSIG stored in encoded_data, and call the given
// callback for each. rrsiglen_list should store a sequence of their lengths,
// in the order of the appearance. Its size is the number of RRSIGs.
// The list can be empty, in which case this function does nothing.
void foreachRRSig(const std::vector<uint8_t>& encoded_data,
const std::vector<uint16_t>& rrsiglen_list,
DataCallback data_callback);
}
} // namespace memory
} // namespace datasrc
} // namespace isc
......
// 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 <dns/rrclass.h>
#include <dns/rrtype.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() &&