"name": "v4-portparams"
},
- // Option codes 161-209 are unassigned.
+ // Option codes 160-161 are unassigned.
+
+ /*
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | OPTION_V4_DNR | Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ~ DNR Instance Data #1 ~
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---
+ . ... . |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ optional
+ ~ DNR Instance Data #n ~ |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---
+
+ DNR Instance Data Format:
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | DNR Instance Data Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Service Priority |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ADN Length | |
+ +-+-+-+-+-+-+-+-+ |
+ ~ authentication-domain-name ~
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Addr Length | |
+ +-+-+-+-+-+-+-+-+ |
+ ~ IPv4 Address(es) ~
+ | +-+-+-+-+-+-+-+-+
+ | | |
+ +-+-+-+-+-+-+-+-+ |
+ ~Service Parameters (SvcParams) ~
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ Code: OPTION_V4_DNR (162).
+
+ Length: Indicates the length of the enclosed data in octets.
+
+ DNR Instance Data: Includes the configuration data of an encrypted
+ DNS resolver. When several encrypted DNS resolvers are to be included, the "DNR
+ Instance Data" field is repeated.
+
+ DNR Instance Data Length: Length of all following data in octets.
+ This field is set to ('ADN Length' + 3) when only an ADN is
+ provided for a DNR instance.
+
+ Service Priority: The priority of this instance compared to other
+ DNR instances. This 16-bit unsigned integer is interpreted
+ following the rules specified in Section 2.4.1 of
+ [I-D.ietf-dnsop-svcb-https].
+
+ ADN Length: Length of the authentication-domain-name in octets.
+
+ authentication-domain-name (variable length): The authentication
+ domain name of the encrypted DNS resolver. This field is
+ formatted as specified in Section 10 of [RFC8415].
+
+ Addr Length: Length of included IPv4 addresses in octets. When
+ present, it MUST be a multiple of 4.
+
+ IPv4 Address(es) (variable length): Indicates one or more IPv4
+ addresses to reach the encrypted DNS resolver. Both private and
+ public IPv4 addresses can be included in this field.
+
+ Service Parameters (SvcParams) (variable length): Specifies a set of
+ service parameters that are encoded following the rules in
+ Section 2.1 of [I-D.ietf-dnsop-svcb-https].
+ The length of this field is ('DNR Instance Data Length' - 4 - 'ADN
+ Length' - 'Addr Length').
+
+ Note that "Addr Length", "IPv4 Address(es)", and "Service Parameters
+ (SvcParams)" fields are not present if the ADN-only mode is used.
+ */
+ // Type: uint16, uint16, uint8, FQDN, binary
+ {
+ // only one DNR instance ADN only mode - IP address(es) and SvcParams are missing on purpose.
+ "code": 162,
+ "name": "v4-dnr",
+ "data": "26, 1234, 23, example.some.host.org., " // please notice comma and space at the end put on purpose
+ // this means empty last type of the record - binary type
+ },
+ {
+ // 2 DNR instances with IP address(es) and SvcParams included as binary type.
+ "code": 162,
+ "name": "v4-dnr", // addresses len=8 | IPv4 1 | IPv4 2 | SvcParams "key1=val1 key2=val2" |Len2 |Prio2| | ADN with Len=21=15hex myhost1.example.com | | IPv4 1 | IPv4 2 | SvcParams "key3=val3 key4=val4" |
+ "data": "54, 3234, 23, example.some.host.org., 08 c0 a8 00 01 c0 a8 00 02 6b 65 79 31 3d 76 61 6c 31 20 6b 65 79 32 3d 76 61 6c 32 00 34 10 e1 15 07 6D 79 68 6F 73 74 31 07 65 78 61 6D 70 6C 65 03 63 6F 6D 00 08 c0 a9 00 01 c0 a9 00 02 6b 65 79 33 3d 76 61 6c 33 20 6b 65 79 34 3d 76 61 6c 34"
+ },
+
+ // Option codes 163-209 are unassigned.
/*
0 1 2 3
"name": "ipv6-address-andsf"
},
- // Option codes 144-65535 are unassigned.
+ /*
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Option-code | Option-length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Service Priority | ADN Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ~ authentication-domain-name ~
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Addr Length | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+ ~ ipv6-address(es) ~
+ | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+ ~ Service Parameters (SvcParams) ~
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ Option-code: OPTION_V6_DNR (144)
+
+ Option-length: Length of the enclosed data in octets. The option
+ length is ('ADN Length' + 4) when only an ADN is included in the
+ option.
+
+ Service Priority: The priority of this OPTION_V6_DNR instance
+ compared to other instances. This 16-bit unsigned integer is
+ interpreted following the rules specified in Section 2.4.1 of
+ [I-D.ietf-dnsop-svcb-https].
+
+ ADN Length: Length of the authentication-domain-name field in
+ octets.
+
+ authentication-domain-name (variable length): A fully qualified
+ domain name of the encrypted DNS resolver. This field is
+ formatted as specified in Section 10 of [RFC8415].
+
+ Addr Length: Length of enclosed IPv6 addresses in octets. When
+ present, it MUST be a multiple of 16.
+
+ ipv6-address(es) (variable length): Indicates one or more IPv6
+ addresses to reach the encrypted DNS resolver. An address can be
+ link-local, ULA, or GUA.
+
+ Service Parameters (SvcParams) (variable length): Specifies a set of
+ service parameters that are encoded following the rules in
+ Section 2.1 of [I-D.ietf-dnsop-svcb-https].
+ */
+ // Type: uint16, uint16, FQDN, binary
+ {
+ // DNR ADN only mode - IP address(es) and SvcParams are missing on purpose.
+ "code": 144,
+ "name": "v6-dnr",
+ "data": "1234, 23, example.some.host.org., " // please notice comma and space at the end put on purpose
+ // this means empty last type of the record - binary type
+
+ },
+ {
+ // DNR with IP address(es) and SvcParams included as binary type.
+ "code": 144,
+ "name": "v6-dnr", // addresses len=32 | 1st IPv6 | 2nd IPv6 | SvcParams "key1=val1 key2=val2" |
+ "data": "3234, 23, example.some.host.org., 00 20 20 01 0d b8 00 01 00 00 00 00 00 00 de ad be ef ff 02 00 00 00 00 00 00 00 00 00 00 fa ce b0 0c 6b 65 79 31 3d 76 61 6c 31 20 6b 65 79 32 3d 76 61 6c 32"
+ },
+
+ // Option codes 145-65535 are unassigned.
/* Custom option data */
// See "option-def" below for the definitions.
+----------------------------------------+------+---------------------------+-------------+-------------+
| v4-portparams | 159 | record (uint8, psid) | false | false |
+----------------------------------------+------+---------------------------+-------------+-------------+
- | v4-dnr | 162 | binary | false | false |
+ | v4-dnr | 162 | record (uint16, uint16, | false | false |
+ | | | uint8, fqdn, binary) | | |
+----------------------------------------+------+---------------------------+-------------+-------------+
| option-6rd | 212 | record (uint8, uint8, | true | false |
| | | ipv6-address, | | |
| ipv6-address-andsf | 143 | ipv6-address | true |
+--------------------------+-----------------+-----------------+-----------------+
| v6-dnr | 144 | record (uint16, | false |
- | | | uint16, binary) | |
+ | | | uint16, fqdn, | |
+ | | | binary) | |
+--------------------------+-----------------+-----------------+-----------------+
Options marked with (1) have option definitions, but the logic behind
// 160 used to be assigned in RFC7710, but was removed in RFC8910
// The Captive Portal option now uses code 114.
// DHO_MUD_URL_V4 = 161, /* RFC8520 */
- DHO_V4_DNR = 162, /* RFC-ietf-add-dnr-13 */
+ DHO_V4_DNR = 162, /* RFC-ietf-add-dnr */
// 163-209 are removed/unassigned
// DHO_PATH_PREFIX = 210, /* RFC5071 */
// DHO_REBOOT_TIME = 211, /* RFC5071 */
D60_V6_SZTP_REDIRECT = 136, /* RFC8572 */
// Option codes 137-142 are unassigned.
D6O_IPV6_ADDRESS_ANDSF = 143, /* RFC6153 */
- D6O_V6_DNR = 144 /* RFC-ietf-add-dnr-13 */
+ D6O_V6_DNR = 144 /* RFC-ietf-add-dnr */
};
/*
dnr_instance.unpackAddresses(begin, dnr_instance_end);
// SvcParams (variable length) field is last.
- dnr_instance.unpackSvcParams(begin, end);
+ dnr_instance.unpackSvcParams(begin, dnr_instance_end);
addDnrInstance(dnr_instance);
}
/// @param adn ADN FQDN
/// @param ip_addresses Container of IP addresses
/// @param svc_params Service Parameters
+ ///
+ /// @throw InvalidOptionDnrDomainName Thrown in case of any issue with parsing ADN
+ /// @throw InvalidOptionDnrSvcParams Thrown when @c checkSvcParams(from_wire_data) throws
+ /// @throw OutOfRange Thrown in case of no IP addresses found or when IP addresses length
+ /// is too big
DnrInstance(Option::Universe universe,
uint16_t service_priority,
const std::string& adn,
/// @param universe either V4 or V6 Option universe
/// @param service_priority Service priority
/// @param adn ADN FQDN
+ ///
+ /// @throw InvalidOptionDnrDomainName Thrown in case of any issue with parsing ADN
DnrInstance(Option::Universe universe, uint16_t service_priority, const std::string& adn);
/// @brief Default destructor.
/// @param begin Iterator pointing to the beginning of the buffer holding an
/// option.
/// @param end Iterator pointing to the end of the buffer holding an option.
+ ///
+ /// @throw OutOfRange Thrown in case of truncated data. May be also thrown when
+ /// @c DnrInstance::unpackDnrInstanceDataLength(begin,end) throws.
+ /// @throw BadValue Thrown when @c DnrInstance::unpackAdn(begin,end) throws.
+ /// @throw InvalidOptionDnrDomainName Thrown when @c DnrInstance::unpackAdn(begin,end) throws.
Option4Dnr(OptionBufferConstIter begin, OptionBufferConstIter end);
/// @brief Constructor of the empty %Option.
/// @param begin Iterator pointing to the beginning of the buffer holding an
/// option.
/// @param end Iterator pointing to the end of the buffer holding an option.
+ ///
+ /// @throw OutOfRange Thrown in case of truncated data.
+ /// @throw BadValue Thrown when @c DnrInstance::unpackAdn(begin,end) throws.
+ /// @throw InvalidOptionDnrDomainName Thrown when @c DnrInstance::unpackAdn(begin,end) throws.
Option6Dnr(OptionBufferConstIter begin, OptionBufferConstIter end);
/// @brief Constructor of the %Option with all fields from params.
/// @param adn ADN FQDN
/// @param ip_addresses Container of IP addresses
/// @param svc_params Service Parameters
+ ///
+ /// @throw InvalidOptionDnrDomainName Thrown in case of any issue with parsing ADN
+ /// @throw InvalidOptionDnrSvcParams Thrown when @c checkSvcParams(from_wire_data) throws
+ /// @throw OutOfRange Thrown in case of no IP addresses found or when IP addresses length
+ /// is too big
Option6Dnr(const uint16_t service_priority,
const std::string& adn,
const Option6Dnr::AddressContainer& ip_addresses,
///
/// @param service_priority Service priority
/// @param adn ADN FQDN
+ ///
+ /// @throw InvalidOptionDnrDomainName Thrown in case of any issue with parsing ADN
Option6Dnr(const uint16_t service_priority, const std::string& adn)
: Option(V6, D6O_V6_DNR), DnrInstance(V6, service_priority, adn) {}
RECORD_DECL(OPT_6RD_RECORDS, OPT_UINT8_TYPE, OPT_UINT8_TYPE,
OPT_IPV6_ADDRESS_TYPE, OPT_IPV4_ADDRESS_TYPE);
+// RFC-draft-ietf-add-dnr DHCPv4 DNR option.
+//
+// DNR Instance Data Length (2 octets), Service Priority (2 octets),
+// ADN Length (1 octet), ADN FQDN.
+// Opaque data is represented here by the binary data field.
+// It may contain Addr Length (1 octet), IPv4 address(es), SvcParams,
+// and next DNR instances as binary data.
+RECORD_DECL(V4_DNR_RECORDS, OPT_UINT16_TYPE, OPT_UINT16_TYPE, OPT_UINT8_TYPE,
+ OPT_FQDN_TYPE, OPT_BINARY_TYPE);
+
/// @brief Definitions of standard DHCPv4 options.
const OptionDefParams STANDARD_V4_OPTION_DEFINITIONS[] = {
{ "subnet-mask", DHO_SUBNET_MASK, DHCP4_OPTION_SPACE,
OPT_UINT8_TYPE, false, NO_RECORD_DEF, "" },
{ "v4-portparams", DHO_V4_PORTPARAMS, DHCP4_OPTION_SPACE, OPT_RECORD_TYPE,
false, RECORD_DEF(V4_PORTPARAMS_RECORDS), "" },
- { "v4-dnr", DHO_V4_DNR, DHCP4_OPTION_SPACE, OPT_BINARY_TYPE,
- false, NO_RECORD_DEF, "" },
+ { "v4-dnr", DHO_V4_DNR, DHCP4_OPTION_SPACE, OPT_RECORD_TYPE,
+ false, RECORD_DEF(V4_DNR_RECORDS), "" },
{ "option-6rd", DHO_6RD, DHCP4_OPTION_SPACE, OPT_RECORD_TYPE, true,
RECORD_DEF(OPT_6RD_RECORDS), "" },
{ "v4-access-domain", DHO_V4_ACCESS_DOMAIN, DHCP4_OPTION_SPACE,
// RFC-draft-ietf-add-dnr DHCPv6 DNR option.
//
-// Service Priority (2 octets), ADN Length (2 octets),
+// Service Priority (2 octets), ADN Length (2 octets), ADN FQDN.
// Opaque data is represented here by the binary data field.
-// It must contain at least authentication-domain-name FQDN(s).
// It may contain Addr Length (2 octets), IPv6 address(es), SvcParams.
-RECORD_DECL(V6_DNR_RECORDS, OPT_UINT16_TYPE, OPT_UINT16_TYPE, OPT_BINARY_TYPE);
+RECORD_DECL(V6_DNR_RECORDS, OPT_UINT16_TYPE, OPT_UINT16_TYPE, OPT_FQDN_TYPE, OPT_BINARY_TYPE);
/// Standard DHCPv6 option definitions.
///
#include <dhcp/option6_addrlst.h>
#include <dhcp/option6_ia.h>
#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option4_dnr.h>
+#include <dhcp/option6_dnr.h>
#include <dhcp/option_custom.h>
#include <dhcp/option_definition.h>
#include <dhcp/option_int.h>
EXPECT_EQ("world", tuple2.getText());
}
+// The purpose of this test is to verify that definition can be created
+// for option that comprises record of data. In this particular test
+// the V4-DNR option is used (code 162) in ADN only mode, only one DNR instance.
+// Option's fields are specified as a vector of strings.
+TEST_F(OptionDefinitionTest, recordOption4DnrAdnOnly) {
+ OptionDefinition opt_def("option-dnr", DHO_V4_DNR, DHCP4_OPTION_SPACE, "record", false);
+ opt_def.addRecordField(OPT_UINT16_TYPE);
+ opt_def.addRecordField(OPT_UINT16_TYPE);
+ opt_def.addRecordField(OPT_UINT8_TYPE);
+ opt_def.addRecordField(OPT_FQDN_TYPE);
+ opt_def.addRecordField(OPT_BINARY_TYPE);
+
+ OptionPtr option;
+
+ // Specify option's fields for ADN only mode.
+ std::vector<std::string> values;
+ values.push_back("26"); // DNR instance data Len
+ values.push_back("1234"); // service priority
+ values.push_back("23"); // ADN Len
+ values.push_back("Example.Some.Host.Org."); // ADN FQDN
+ values.push_back(""); // leave empty Binary type
+
+ // Create an instance of this option using the definition.
+ ASSERT_NO_THROW(option = opt_def.optionFactory(Option::V4, DHO_V4_DNR, values););
+
+ // Make sure that the returned option class is correct.
+ const Option* optptr = option.get();
+ ASSERT_TRUE(optptr);
+ ASSERT_TRUE(typeid(*optptr) == typeid(Option4Dnr));
+
+ // Validate that option's fields were correctly parsed from strings.
+ Option4DnrPtr option_cast = boost::dynamic_pointer_cast<Option4Dnr>(option);
+
+ auto dnr_instances = option_cast->getDnrInstances();
+
+ // Only one DNR instance is expected.
+ ASSERT_EQ(1, dnr_instances.size());
+
+ DnrInstance& dnr = dnr_instances[0];
+ ASSERT_EQ(26, dnr.getDnrInstanceDataLength());
+ ASSERT_EQ(1234, dnr.getServicePriority());
+ ASSERT_EQ(true, dnr.isAdnOnlyMode());
+ ASSERT_EQ("example.some.host.org.", dnr.getAdnAsText());
+ ASSERT_EQ(23, dnr.getAdnLength());
+ ASSERT_EQ(0, dnr.getAddrLength());
+ ASSERT_EQ(0, dnr.getSvcParamsLength());
+}
+
+// The purpose of this test is to verify that definition can be created
+// for option that comprises record of data. In this particular test
+// the V4-DNR option is used (code 162) with ADN, IP addresses and Service
+// Parameters included. Option's fields are specified as a vector of strings.
+// Multiple DNR instances are configured in this test.
+TEST_F(OptionDefinitionTest, recordOption4Dnr) {
+ OptionDefinition opt_def("option-dnr", DHO_V4_DNR, DHCP4_OPTION_SPACE, "record", false);
+ opt_def.addRecordField(OPT_UINT16_TYPE);
+ opt_def.addRecordField(OPT_UINT16_TYPE);
+ opt_def.addRecordField(OPT_UINT8_TYPE);
+ opt_def.addRecordField(OPT_FQDN_TYPE);
+ opt_def.addRecordField(OPT_BINARY_TYPE);
+
+ OptionPtr option;
+
+ // Specify option's fields - multiple DNR instances.
+ std::vector<std::string> values;
+ values.push_back("54"); // DNR instance #1 data Len
+ values.push_back("1234"); // service priority
+ values.push_back("23"); // ADN Len
+ values.push_back("Example.Some.Host.Org."); // ADN FQDN
+ values.push_back("08 " // Addr Len
+ "c0 a8 00 01" // IP 192.168.0.1
+ "c0 a8 00 02" // IP 192.168.0.2
+ "6b 65 79 31 3d 76 61 6c 31 20 " // SvcParams "key1=val1 "
+ "6b 65 79 32 3d 76 61 6c 32 " // SvcParams "key2=val2"
+ "00 34 " // DNR instance #2 data Len 52
+ "10 e1 " // service priority 4321
+ "15 " // ADN Len 21
+ "07 6D 79 68 6F 73 74 31 " // ADN FQDN myhost1.
+ "07 65 78 61 6D 70 6C 65 " // example.
+ "03 63 6F 6D 00 " // com.
+ "08 " // Addr Len 8
+ "c0 a9 00 01" // IP 192.169.0.1
+ "c0 a9 00 02" // IP 192.169.0.2
+ "6b 65 79 33 3d 76 61 6c 33 20 " // SvcParams "key3=val3 "
+ "6b 65 79 34 3d 76 61 6c 34 " // SvcParams "key4=val4"
+ );
+
+ // Create an instance of this option using the definition.
+ ASSERT_NO_THROW(option = opt_def.optionFactory(Option::V4, DHO_V4_DNR, values););
+
+ // Make sure that the returned option class is correct.
+ const Option* optptr = option.get();
+ ASSERT_TRUE(optptr);
+ ASSERT_TRUE(typeid(*optptr) == typeid(Option4Dnr));
+
+ // Validate that option's fields were correctly parsed from strings.
+ Option4DnrPtr option_cast = boost::dynamic_pointer_cast<Option4Dnr>(option);
+
+ auto dnr_instances = option_cast->getDnrInstances();
+
+ // Two DNR instances are expected.
+ ASSERT_EQ(2, dnr_instances.size());
+
+ // Let's check 1st DNR instance.
+ DnrInstance& dnr_1 = dnr_instances[0];
+ ASSERT_EQ(54, dnr_1.getDnrInstanceDataLength());
+ ASSERT_EQ(1234, dnr_1.getServicePriority());
+ ASSERT_EQ(false, dnr_1.isAdnOnlyMode());
+ ASSERT_EQ(23, dnr_1.getAdnLength());
+ ASSERT_EQ("example.some.host.org.", dnr_1.getAdnAsText());
+ ASSERT_EQ(8, dnr_1.getAddrLength());
+ ASSERT_EQ(19, dnr_1.getSvcParamsLength());
+ auto addresses_1 = dnr_1.getAddresses();
+ ASSERT_EQ(2, addresses_1.size());
+ ASSERT_EQ("192.168.0.1", addresses_1[0].toText());
+ ASSERT_EQ("192.168.0.2", addresses_1[1].toText());
+ ASSERT_EQ("key1=val1 key2=val2", dnr_1.getSvcParams());
+
+ // Let's check 2nd DNR instance.
+ DnrInstance& dnr_2 = dnr_instances[1];
+ ASSERT_EQ(52, dnr_2.getDnrInstanceDataLength());
+ ASSERT_EQ(4321, dnr_2.getServicePriority());
+ ASSERT_EQ(false, dnr_2.isAdnOnlyMode());
+ ASSERT_EQ(21, dnr_2.getAdnLength());
+ ASSERT_EQ("myhost1.example.com.", dnr_2.getAdnAsText());
+ ASSERT_EQ(8, dnr_2.getAddrLength());
+ ASSERT_EQ(19, dnr_2.getSvcParamsLength());
+ auto addresses_2 = dnr_2.getAddresses();
+ ASSERT_EQ(2, addresses_2.size());
+ ASSERT_EQ("192.169.0.1", addresses_2[0].toText());
+ ASSERT_EQ("192.169.0.2", addresses_2[1].toText());
+ ASSERT_EQ("key3=val3 key4=val4", dnr_2.getSvcParams());
+}
+
+// The purpose of this test is to verify that definition can be created
+// for option that comprises record of data. In this particular test
+// the V6-DNR option is used (code 144) in ADN only mode.
+// Option's fields are specified as a vector of strings.
+TEST_F(OptionDefinitionTest, recordOption6DnrAdnOnly) {
+ OptionDefinition opt_def("option-dnr", D6O_V6_DNR, DHCP6_OPTION_SPACE, "record", false);
+ opt_def.addRecordField(OPT_UINT16_TYPE);
+ opt_def.addRecordField(OPT_UINT16_TYPE);
+ opt_def.addRecordField(OPT_FQDN_TYPE);
+ opt_def.addRecordField(OPT_BINARY_TYPE);
+
+ OptionPtr option;
+
+ // Specify option's fields for ADN only mode.
+ std::vector<std::string> values;
+ values.push_back("1234"); // service priority
+ values.push_back("23"); // ADN Len
+ values.push_back("Example.Some.Host.Org."); // ADN FQDN
+ values.push_back(""); // leave empty Binary type
+
+ // Create an instance of this option using the definition.
+ ASSERT_NO_THROW(option = opt_def.optionFactory(Option::V6, D6O_V6_DNR, values););
+
+ // Make sure that the returned option class is correct.
+ const Option* optptr = option.get();
+ ASSERT_TRUE(optptr);
+ ASSERT_TRUE(typeid(*optptr) == typeid(Option6Dnr));
+
+ // Validate that option's fields were correctly parsed from strings.
+ Option6DnrPtr option_cast = boost::dynamic_pointer_cast<Option6Dnr>(option);
+
+ ASSERT_EQ(1234, option_cast->getServicePriority());
+ ASSERT_EQ(true, option_cast->isAdnOnlyMode());
+ ASSERT_EQ("example.some.host.org.", option_cast->getAdnAsText());
+ ASSERT_EQ(23, option_cast->getAdnLength());
+ ASSERT_EQ(0, option_cast->getAddrLength());
+ ASSERT_EQ(0, option_cast->getSvcParamsLength());
+}
+
+// The purpose of this test is to verify that definition can be created
+// for option that comprises record of data. In this particular test
+// the V6-DNR option is used (code 144) with ADN, IP addresses and Service
+// Parameters included. Option's fields are specified as a vector of strings.
+TEST_F(OptionDefinitionTest, recordOption6Dnr) {
+ OptionDefinition opt_def("option-dnr", D6O_V6_DNR, DHCP6_OPTION_SPACE, "record", false);
+ opt_def.addRecordField(OPT_UINT16_TYPE);
+ opt_def.addRecordField(OPT_UINT16_TYPE);
+ opt_def.addRecordField(OPT_FQDN_TYPE);
+ opt_def.addRecordField(OPT_BINARY_TYPE);
+
+ OptionPtr option;
+
+ // Specify option's fields: service priority, ADN, IP addresses and SvcParams.
+ std::vector<std::string> values;
+ values.push_back("1234"); // service priority
+ values.push_back("23"); // ADN Len
+ values.push_back("Example.Some.Host.Org."); // ADN FQDN
+ values.push_back("00 20 " // Addr Len
+ "20 01 0d b8 00 01 00 00 00 00 00 00 de ad be ef " // IP 2001:db8:1::dead:beef
+ "ff 02 00 00 00 00 00 00 00 00 00 00 fa ce b0 0c " // IP ff02::face:b00c
+ "6b 65 79 31 3d 76 61 6c 31 20 " // SvcParams "key1=val1 "
+ "6b 65 79 32 3d 76 61 6c 32" // SvcParams "key2=val2"
+ );
+
+ // Create an instance of this option using the definition.
+ ASSERT_NO_THROW(option = opt_def.optionFactory(Option::V6, D6O_V6_DNR, values););
+
+ // Make sure that the returned option class is correct.
+ const Option* optptr = option.get();
+ ASSERT_TRUE(optptr);
+ ASSERT_TRUE(typeid(*optptr) == typeid(Option6Dnr));
+
+ // Validate that option's fields were correctly parsed from strings.
+ Option6DnrPtr option_cast = boost::dynamic_pointer_cast<Option6Dnr>(option);
+
+ ASSERT_EQ(1234, option_cast->getServicePriority());
+ ASSERT_EQ(false, option_cast->isAdnOnlyMode());
+ ASSERT_EQ("example.some.host.org.", option_cast->getAdnAsText());
+ ASSERT_EQ(23, option_cast->getAdnLength());
+ ASSERT_EQ(32, option_cast->getAddrLength());
+ auto addresses = option_cast->getAddresses();
+ ASSERT_EQ(2, addresses.size());
+ ASSERT_EQ("2001:db8:1::dead:beef", addresses[0].toText());
+ ASSERT_EQ("ff02::face:b00c", addresses[1].toText());
+ ASSERT_EQ("key1=val1 key2=val2", option_cast->getSvcParams());
+}
+
// This test verifies that a definition of an option with an array
// of DHCPv6 tuples can be created and that the instance of this option
// can be created by specifying multiple DHCPv6 tuples in the textual format.