summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPiotrek Zadroga <piotrek@isc.org>2024-02-23 15:23:51 +0100
committerPiotrek Zadroga <piotrek@isc.org>2024-02-23 17:14:41 +0100
commita1c57f3f7343ceb61757e09280d6135405dfdf51 (patch)
tree940cb1fb12e23d55b72a84b786e47761a4139ce5
parent[#3141] addressed review comments (diff)
downloadkea-a1c57f3f7343ceb61757e09280d6135405dfdf51.tar.xz
kea-a1c57f3f7343ceb61757e09280d6135405dfdf51.zip
[#3141] addressed review comments
- refactored code of SvcParam config parser - added new 2 UTs - added some more comments in code
-rw-r--r--src/lib/dhcp/option4_dnr.cc423
-rw-r--r--src/lib/dhcp/option4_dnr.h44
-rw-r--r--src/lib/dhcp/option6_dnr.h1
-rw-r--r--src/lib/dhcp/option_definition.cc7
-rw-r--r--src/lib/dhcp/tests/option4_dnr_unittest.cc17
-rw-r--r--src/lib/dhcp/tests/option6_dnr_unittest.cc17
6 files changed, 309 insertions, 200 deletions
diff --git a/src/lib/dhcp/option4_dnr.cc b/src/lib/dhcp/option4_dnr.cc
index a1b5b9b215..f89b6c6265 100644
--- a/src/lib/dhcp/option4_dnr.cc
+++ b/src/lib/dhcp/option4_dnr.cc
@@ -609,228 +609,259 @@ DnrInstance::parseDnrInstanceConfigData(const std::string& config_txt) {
// parse resolver IP address/es
std::string txt_addresses = str::trim(tokens[2]);
- // determine v4/v6 universe
- std::string ip_version = (universe_ == Option::V6) ? "IPv6" : "IPv4";
- const size_t addr_len = (universe_ == Option::V6) ? V6ADDRESS_LEN : V4ADDRESS_LEN;
+ parseIpAddresses(txt_addresses);
+ }
- // IP addresses are separated with space
- std::vector<std::string> addresses = str::tokens(txt_addresses, std::string(" "));
- for (auto const& txt_addr : addresses) {
- try {
- addIpAddress(IOAddress(str::trim(txt_addr)));
- } catch (const Exception& e) {
- isc_throw(BadValue, getLogPrefix() << "Cannot parse " << ip_version << " address "
- << "from given value: " << txt_addr
- << ". Error: " << e.what());
+ if (tokens.size() == 4) {
+ // parse Service Parameters
+ std::string txt_svc_params = str::trim(tokens[3]);
+
+ parseSvcParams(txt_svc_params);
+ }
+}
+
+void
+DnrInstance::parseIpAddresses(const std::string& txt_addresses) {
+ // determine v4/v6 universe
+ std::string ip_version = (universe_ == Option::V6) ? "IPv6" : "IPv4";
+ const size_t addr_len = (universe_ == Option::V6) ? V6ADDRESS_LEN : V4ADDRESS_LEN;
+
+ // IP addresses are separated with space
+ std::vector<std::string> addresses = str::tokens(txt_addresses, std::string(" "));
+ for (auto const& txt_addr : addresses) {
+ try {
+ const IOAddress address = IOAddress(str::trim(txt_addr));
+ if ((address.isV4() && universe_ == Option::V6) ||
+ (address.isV6() && universe_ == Option::V4)) {
+ isc_throw(BadValue, "Given address is not " << ip_version << " address.");
}
- }
- // As per RFC9463 section 3.1.8:
- // (If ADN-only mode is not used)
- // The option includes at least one valid IP address.
- if (ip_addresses_.empty()) {
- isc_throw(BadValue, getLogPrefix() << "Option config requires at least one valid IP "
- << "address.");
+ addIpAddress(address);
+ } catch (const Exception& e) {
+ isc_throw(BadValue, getLogPrefix()
+ << "Cannot parse " << ip_version << " address "
+ << "from given value: " << txt_addr << ". Error: " << e.what());
}
+ }
- addr_length_ = ip_addresses_.size() * addr_len;
+ // As per RFC9463 section 3.1.8:
+ // (If ADN-only mode is not used)
+ // The option includes at least one valid IP address.
+ if (ip_addresses_.empty()) {
+ isc_throw(BadValue, getLogPrefix() << "Option config requires at least one valid IP "
+ << "address.");
}
- if (tokens.size() == 4) {
- // parse Service Parameters
- std::string txt_svc_params = str::trim(tokens[3]);
+ addr_length_ = ip_addresses_.size() * addr_len;
+}
- // SvcParamKey=SvcParamValue pairs are separated with space
- std::vector<std::string> svc_params_pairs = str::tokens(txt_svc_params, std::string(" "));
- std::vector<std::string> alpn_ids_tokens;
- OpaqueDataTuple svc_param_val_tuple(OpaqueDataTuple::LENGTH_2_BYTES);
- OutputBuffer out_buf(2);
- std::vector<uint8_t> utf8_encoded;
- for (auto const& svc_param_pair : svc_params_pairs) {
- std::vector<std::string> key_val_tokens = str::tokens(str::trim(svc_param_pair), "=");
- if (key_val_tokens.size() != 2) {
- isc_throw(InvalidOptionDnrSvcParams,
- getLogPrefix() << "Wrong Svc Params syntax - SvcParamKey=SvcParamValue "
- << "pair syntax must be used");
- }
+void
+DnrInstance::parseSvcParams(const std::string& txt_svc_params) {
+ // SvcParamKey=SvcParamValue pairs are separated with space
+ std::vector<std::string> svc_params_pairs = str::tokens(txt_svc_params, std::string(" "));
+ std::vector<std::string> alpn_ids_tokens;
- // SvcParam Key related checks come below.
- std::string svc_param_key = str::trim(key_val_tokens[0]);
+ OutputBuffer out_buf(2);
- // As per RFC9463 Section 3.1.8:
- // The service parameters do not include "ipv4hint" or "ipv6hint" parameters.
- if (FORBIDDEN_SVC_PARAMS.find(svc_param_key) != FORBIDDEN_SVC_PARAMS.end()) {
- isc_throw(InvalidOptionDnrSvcParams, getLogPrefix()
- << "Wrong Svc Params syntax - key "
- << svc_param_key << " must not be used");
- }
+ for (auto const& svc_param_pair : svc_params_pairs) {
+ std::vector<std::string> key_val_tokens = str::tokens(str::trim(svc_param_pair), "=");
+ if (key_val_tokens.size() != 2) {
+ isc_throw(InvalidOptionDnrSvcParams,
+ getLogPrefix() << "Wrong Svc Params syntax - SvcParamKey=SvcParamValue "
+ << "pair syntax must be used");
+ }
- // Check if SvcParamKey is known in
- // https://www.iana.org/assignments/dns-svcb/dns-svcb.xhtml
- auto svc_params_iterator = SVC_PARAMS.left.find(svc_param_key);
- if (svc_params_iterator == SVC_PARAMS.left.end()) {
- isc_throw(InvalidOptionDnrSvcParams,
- getLogPrefix() << "Wrong Svc Params syntax - key " << svc_param_key
- << " not found in SvcParamKeys registry");
- }
+ // SvcParam Key related checks come below.
+ std::string svc_param_key = str::trim(key_val_tokens[0]);
- // Check if SvcParamKey usage is supported by DNR DHCP option.
- // Note that SUPPORTED_SVC_PARAMS set may expand in the future.
- uint16_t num_svc_param_key = svc_params_iterator->second;
- if (SUPPORTED_SVC_PARAMS.find(num_svc_param_key) == SUPPORTED_SVC_PARAMS.end()) {
- isc_throw(InvalidOptionDnrSvcParams,
- getLogPrefix() << "Wrong Svc Params syntax - key " << svc_param_key
- << " not supported in DNR option SvcParams");
- }
+ // As per RFC9463 Section 3.1.8:
+ // The service parameters do not include "ipv4hint" or "ipv6hint" parameters.
+ if (FORBIDDEN_SVC_PARAMS.find(svc_param_key) != FORBIDDEN_SVC_PARAMS.end()) {
+ isc_throw(InvalidOptionDnrSvcParams, getLogPrefix()
+ << "Wrong Svc Params syntax - key "
+ << svc_param_key << " must not be used");
+ }
- // As per RFC9460 Section 2.2:
- // SvcParamKeys SHALL appear in increasing numeric order. (...)
- // There are no duplicate SvcParamKeys.
- //
- // We check for duplicates here. Correct ordering is done when option gets packed.
- if (svc_params_map_.find(num_svc_param_key) != svc_params_map_.end()) {
- isc_throw(InvalidOptionDnrSvcParams, getLogPrefix()
- << "Wrong Svc Params syntax - key "
- << svc_param_key << " is duplicated.");
- }
+ // Check if SvcParamKey is known in
+ // https://www.iana.org/assignments/dns-svcb/dns-svcb.xhtml
+ auto svc_params_iterator = SVC_PARAMS.left.find(svc_param_key);
+ if (svc_params_iterator == SVC_PARAMS.left.end()) {
+ isc_throw(InvalidOptionDnrSvcParams,
+ getLogPrefix() << "Wrong Svc Params syntax - key " << svc_param_key
+ << " not found in SvcParamKeys registry");
+ }
- // SvcParam Val check.
- std::string svc_param_val = str::trim(key_val_tokens[1]);
- if (svc_param_val.empty()) {
- isc_throw(InvalidOptionDnrSvcParams,
- getLogPrefix() << "Wrong Svc Params syntax - empty SvcParamValue for key "
- << svc_param_key);
- }
+ // Check if SvcParamKey usage is supported by DNR DHCP option.
+ // Note that SUPPORTED_SVC_PARAMS set may expand in the future.
+ uint16_t num_svc_param_key = svc_params_iterator->second;
+ if (SUPPORTED_SVC_PARAMS.find(num_svc_param_key) == SUPPORTED_SVC_PARAMS.end()) {
+ isc_throw(InvalidOptionDnrSvcParams,
+ getLogPrefix() << "Wrong Svc Params syntax - key " << svc_param_key
+ << " not supported in DNR option SvcParams");
+ }
- svc_param_val_tuple.clear();
- switch (num_svc_param_key) {
- case 1:
- // alpn
- // The wire-format value for "alpn" consists of at least one alpn-id prefixed by its
- // length as a single octet, and these length-value pairs are concatenated to form
- // the SvcParamValue.
- alpn_ids_tokens = str::tokens(svc_param_val, std::string(","));
- for (auto const& alpn_id : alpn_ids_tokens) {
- // Check if alpn-id is known in
- // https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
- if (ALPN_IDS.find(alpn_id) == ALPN_IDS.end()) {
- isc_throw(InvalidOptionDnrSvcParams,
- getLogPrefix() << "Wrong Svc Params syntax - alpn-id " << alpn_id
- << " not found in ALPN-IDs registry");
- }
-
- // Make notice if this is any of http alpn-ids.
- if (alpn_id[0] == 'h') {
- alpn_http_ = true;
- }
-
- OpaqueDataTuple alpn_id_tuple(OpaqueDataTuple::LENGTH_1_BYTE);
- alpn_id_tuple.append(alpn_id);
- alpn_id_tuple.pack(out_buf);
- svc_param_val_tuple.append(static_cast<const char*>(out_buf.getData()),
- out_buf.getLength());
- out_buf.clear();
- }
+ // As per RFC9460 Section 2.2:
+ // SvcParamKeys SHALL appear in increasing numeric order. (...)
+ // There are no duplicate SvcParamKeys.
+ //
+ // We check for duplicates here. Correct ordering is done when option gets packed.
+ if (svc_params_map_.find(num_svc_param_key) != svc_params_map_.end()) {
+ isc_throw(InvalidOptionDnrSvcParams, getLogPrefix()
+ << "Wrong Svc Params syntax - key "
+ << svc_param_key << " is duplicated.");
+ }
- svc_params_map_.insert(std::make_pair(num_svc_param_key, svc_param_val_tuple));
- break;
- case 3:
- // port
- // The wire format of the SvcParamValue is the corresponding 2-octet numeric value
- // in network byte order.
- uint16_t port;
- try {
- port = boost::lexical_cast<uint16_t>(svc_param_val);
- } catch (const std::exception& e) {
- isc_throw(InvalidOptionDnrSvcParams,
- getLogPrefix() << "Cannot parse uint_16 integer port nr "
- << "from given value: " << svc_param_val
- << ". Error: " << e.what());
- }
+ // SvcParam Val check.
+ std::string svc_param_val = str::trim(key_val_tokens[1]);
+ if (svc_param_val.empty()) {
+ isc_throw(InvalidOptionDnrSvcParams,
+ getLogPrefix() << "Wrong Svc Params syntax - empty SvcParamValue for key "
+ << svc_param_key);
+ }
- out_buf.writeUint16(port);
- svc_param_val_tuple.append(static_cast<const char*>(out_buf.getData()),
- out_buf.getLength());
- out_buf.clear();
- svc_params_map_.insert(std::make_pair(num_svc_param_key, svc_param_val_tuple));
- break;
- case 7:
- // dohpath - RFC9461 Section 5
- // single-valued SvcParamKey whose value (in both presentation format and wire
- // format) MUST be a URI Template in relative form ([RFC6570], Section 1.1) encoded
- // in UTF-8 [RFC3629]. If the "alpn" SvcParam indicates support for HTTP,
- // "dohpath" MUST be present. The URI Template MUST contain a "dns" variable,
- // and MUST be chosen such that the result after DoH URI Template expansion
- // (Section 6 of [RFC8484]) is always a valid and functional ":path" value
- // ([RFC9113], Section 8.3.1).
-
- // Check that "dns" variable is there
- if (svc_param_val.find("{?dns}") == std::string::npos) {
- isc_throw(InvalidOptionDnrSvcParams,
- getLogPrefix()
- << "Wrong Svc Params syntax - dohpath SvcParamValue URI"
- << " Template MUST contain a 'dns' variable.");
- }
+ switch (num_svc_param_key) {
+ case 1:
+ parseAlpnSvcParam(svc_param_val);
+ break;
+ case 3:
+ parsePortSvcParam(svc_param_val);
+ break;
+ case 7:
+ parseDohpathSvcParam(svc_param_val);
+ break;
+ default:
+ // This should not happen because we check if num_svc_param_key is
+ // in SUPPORTED_SVC_PARAMS before. But in case new SvcParam appears in Supported,
+ // and is not handled here...
+ isc_throw(InvalidOptionDnrSvcParams, getLogPrefix()
+ << "Wrong Svc Params syntax - key "
+ << num_svc_param_key << " not supported yet.");
+ }
+ }
- // We hope to have URI containing < 0x80 ASCII chars, however to be sure
- // and to be inline with RFC9461 Section 5, let's encode the dohpath with utf8.
- utf8_encoded = encode::encodeUtf8(svc_param_val);
- svc_param_val_tuple.append(utf8_encoded.begin(), utf8_encoded.size());
- svc_params_map_.insert(std::make_pair(num_svc_param_key, svc_param_val_tuple));
- break;
- default:
- // This should not happen because we check if num_svc_param_key is
- // in SUPPORTED_SVC_PARAMS before. But in case new SvcParam appears in Supported,
- // and is not handled here...
- isc_throw(InvalidOptionDnrSvcParams,
- getLogPrefix() << "Wrong Svc Params syntax - key " << num_svc_param_key
- << " not supported yet.");
- }
+ // If the "alpn" SvcParam indicates support for HTTP, "dohpath" MUST be present.
+ if (alpn_http_ && svc_params_map_.find(7) == svc_params_map_.end()) {
+ isc_throw(InvalidOptionDnrSvcParams,
+ getLogPrefix() << "Wrong Svc Params syntax - dohpath SvcParam missing. "
+ << "When alpn SvcParam indicates "
+ << "support for HTTP, dohpath must be present.");
+ }
+
+ // At this step all given SvcParams should be fine. We can pack everything to data
+ // buffer according to RFC9460 Section 2.2.
+ //
+ // When the list of SvcParams is non-empty, it contains a series of
+ // SvcParamKey=SvcParamValue pairs, represented as:
+ // - a 2-octet field containing the SvcParamKey as an integer in network byte order.
+ // - a 2-octet field containing the length of the SvcParamValue as an integer
+ // between 0 and 65535 in network byte order. (uint16)
+ // - an octet string of this length whose contents are the SvcParamValue in a format
+ // determined by the SvcParamKey.
+ // (...)
+ // SvcParamKeys SHALL appear in increasing numeric order.
+ // Note that (...) there are no duplicate SvcParamKeys.
+
+ for (auto const& svc_param_key : SUPPORTED_SVC_PARAMS) {
+ auto it = svc_params_map_.find(svc_param_key);
+ if (it != svc_params_map_.end()) {
+ // Write 2-octet field containing the SvcParamKey as an integer
+ // in network byte order.
+ out_buf.writeUint16(it->first);
+ // Write 2-octet field containing the length of the SvcParamValue
+ // and an octet string of this length whose contents are the SvcParamValue.
+ // We use OpaqueDataTuple#pack(&buf) here that will write correct len-data
+ // tuple to the buffer.
+ (it->second).pack(out_buf);
}
+ }
- // If the "alpn" SvcParam indicates support for HTTP, "dohpath" MUST be present.
- if (alpn_http_ && svc_params_map_.find(7) == svc_params_map_.end()) {
+ // Copy SvcParams buffer from OutputBuffer to OptionBuffer.
+ const uint8_t* ptr = static_cast<const uint8_t*>(out_buf.getData());
+ OptionBuffer temp_buf(ptr, ptr + out_buf.getLength());
+ svc_params_buf_ = temp_buf;
+ svc_params_length_ = out_buf.getLength();
+ out_buf.clear();
+}
+
+void
+DnrInstance::parseAlpnSvcParam(const std::string& svc_param_val) {
+ // The wire-format value for "alpn" consists of at least one alpn-id prefixed by its
+ // length as a single octet, and these length-value pairs are concatenated to form
+ // the SvcParamValue.
+ OutputBuffer out_buf(2);
+ OpaqueDataTuple svc_param_val_tuple(OpaqueDataTuple::LENGTH_2_BYTES);
+ std::vector<std::string> alpn_ids_tokens = str::tokens(svc_param_val, std::string(","));
+ for (auto const& alpn_id : alpn_ids_tokens) {
+ // Check if alpn-id is known in
+ // https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
+ if (ALPN_IDS.find(alpn_id) == ALPN_IDS.end()) {
isc_throw(InvalidOptionDnrSvcParams,
- getLogPrefix() << "Wrong Svc Params syntax - dohpath SvcParam missing. "
- << "When alpn SvcParam indicates "
- << "support for HTTP, dohpath must be present.");
+ getLogPrefix() << "Wrong Svc Params syntax - alpn-id " << alpn_id
+ << " not found in ALPN-IDs registry");
}
- // At this step all given SvcParams should be fine. We can pack everything to data
- // buffer according to RFC9460 Section 2.2.
- //
- // When the list of SvcParams is non-empty, it contains a series of
- // SvcParamKey=SvcParamValue pairs, represented as:
- // - a 2-octet field containing the SvcParamKey as an integer in network byte order.
- // - a 2-octet field containing the length of the SvcParamValue as an integer
- // between 0 and 65535 in network byte order. (uint16)
- // - an octet string of this length whose contents are the SvcParamValue in a format
- // determined by the SvcParamKey.
- // (...)
- // SvcParamKeys SHALL appear in increasing numeric order.
- // Note that (...) there are no duplicate SvcParamKeys.
-
- for (auto const& svc_param_key : SUPPORTED_SVC_PARAMS) {
- auto it = svc_params_map_.find(svc_param_key);
- if (it != svc_params_map_.end()) {
- // Write 2-octet field containing the SvcParamKey as an integer
- // in network byte order.
- out_buf.writeUint16(it->first);
- // Write 2-octet field containing the length of the SvcParamValue
- // and an octet string of this length whose contents are the SvcParamValue.
- // We use OpaqueDataTuple#pack(&buf) here that will write correct len-data
- // tuple to the buffer.
- (it->second).pack(out_buf);
- }
+ // Make notice if this is any of http alpn-ids.
+ if (alpn_id[0] == 'h') {
+ alpn_http_ = true;
}
- // Copy SvcParams buffer from OutputBuffer to OptionBuffer.
- const uint8_t* ptr = static_cast<const uint8_t*>(out_buf.getData());
- OptionBuffer temp_buf(ptr, ptr + out_buf.getLength());
- svc_params_buf_ = temp_buf;
- svc_params_length_ = out_buf.getLength();
- out_buf.clear();
+ OpaqueDataTuple alpn_id_tuple(OpaqueDataTuple::LENGTH_1_BYTE);
+ alpn_id_tuple.append(alpn_id);
+ alpn_id_tuple.pack(out_buf);
+ }
+
+ svc_param_val_tuple.append(static_cast<const char*>(out_buf.getData()), out_buf.getLength());
+ svc_params_map_.insert(std::make_pair(1, svc_param_val_tuple));
+ out_buf.clear();
+}
+
+void
+DnrInstance::parsePortSvcParam(const std::string& svc_param_val) {
+ // The wire format of the SvcParamValue is the corresponding 2-octet numeric value
+ // in network byte order.
+ OutputBuffer out_buf(2);
+ OpaqueDataTuple svc_param_val_tuple(OpaqueDataTuple::LENGTH_2_BYTES);
+ uint16_t port;
+ try {
+ port = boost::lexical_cast<uint16_t>(svc_param_val);
+ } catch (const std::exception& e) {
+ isc_throw(InvalidOptionDnrSvcParams, getLogPrefix()
+ << "Cannot parse uint_16 integer port nr "
+ << "from given value: " << svc_param_val
+ << ". Error: " << e.what());
+ }
+
+ out_buf.writeUint16(port);
+ svc_param_val_tuple.append(static_cast<const char*>(out_buf.getData()), out_buf.getLength());
+ out_buf.clear();
+ svc_params_map_.insert(std::make_pair(3, svc_param_val_tuple));
+}
+
+void
+DnrInstance::parseDohpathSvcParam(const std::string& svc_param_val) {
+ // RFC9461 Section 5
+ // single-valued SvcParamKey whose value (in both presentation format and wire
+ // format) MUST be a URI Template in relative form ([RFC6570], Section 1.1) encoded
+ // in UTF-8 [RFC3629]. If the "alpn" SvcParam indicates support for HTTP,
+ // "dohpath" MUST be present. The URI Template MUST contain a "dns" variable,
+ // and MUST be chosen such that the result after DoH URI Template expansion
+ // (Section 6 of [RFC8484]) is always a valid and functional ":path" value
+ // ([RFC9113], Section 8.3.1).
+ std::vector<uint8_t> utf8_encoded;
+ OpaqueDataTuple svc_param_val_tuple(OpaqueDataTuple::LENGTH_2_BYTES);
+
+ // Check that "dns" variable is there
+ if (svc_param_val.find("{?dns}") == std::string::npos) {
+ isc_throw(InvalidOptionDnrSvcParams,
+ getLogPrefix() << "Wrong Svc Params syntax - dohpath SvcParamValue URI"
+ << " Template MUST contain a 'dns' variable.");
}
+
+ // We hope to have URI containing < 0x80 ASCII chars, however to be sure
+ // and to be inline with RFC9461 Section 5, let's encode the dohpath with utf8.
+ utf8_encoded = encode::encodeUtf8(svc_param_val);
+ svc_param_val_tuple.append(utf8_encoded.begin(), utf8_encoded.size());
+ svc_params_map_.insert(std::make_pair(7, svc_param_val_tuple));
}
} // namespace dhcp
diff --git a/src/lib/dhcp/option4_dnr.h b/src/lib/dhcp/option4_dnr.h
index a00232bf84..e8d78024c2 100644
--- a/src/lib/dhcp/option4_dnr.h
+++ b/src/lib/dhcp/option4_dnr.h
@@ -291,6 +291,9 @@ public:
///
/// @param begin beginning of the buffer from which the field will be read
/// @param end end of the buffer from which the field will be read
+ ///
+ /// @throw OutOfRange Thrown when truncated data is detected.
+ /// @throw InvalidOptionDnrSvcParams Thrown when invalid SvcParams syntax is detected.
void unpackSvcParams(OptionBufferConstIter& begin, OptionBufferConstIter end);
/// @brief Adds IP address to @c ip_addresses_ container.
@@ -322,8 +325,6 @@ public:
/// @throw BadValue Thrown in case parser found wrong format of received string.
/// @throw InvalidOptionDnrDomainName Thrown in case parser had problems with extracting ADN
/// FQDN.
- /// @throw InvalidOptionDnrSvcParams Thrown in case parser had problems with extracting
- /// SvcParams.
void parseDnrInstanceConfigData(const std::string& config_txt);
protected:
@@ -431,6 +432,45 @@ private:
/// @throw BadValue thrown when there is a problem with reading alpn SvcParamVal from
/// @c svc_params_map_
std::string svcParamValAsText(const std::pair<uint16_t, OpaqueDataTuple>& svc_param) const;
+
+ /// @brief Parses DNR resolver IP address/es from a piece of convenient notation option config.
+ ///
+ /// @param txt_addresses a piece of convenient notation option config holding IP address/es
+ ///
+ /// @throw BadValue Thrown in case parser found wrong format of received string.
+ void parseIpAddresses(const std::string& txt_addresses);
+
+ /// @brief Parses Service Parameters from a piece of convenient notation option config.
+ ///
+ /// @param txt_svc_params a piece of convenient notation option config holding SvcParams
+ ///
+ /// @throw InvalidOptionDnrSvcParams Thrown in case parser had problems with extracting
+ /// SvcParams.
+ void parseSvcParams(const std::string& txt_svc_params);
+
+ /// @brief Parses ALPN Service Parameter from a piece of convenient notation option config.
+ ///
+ /// @param svc_param_val a piece of convenient notation option config holding ALPN SvcParam
+ ///
+ /// @throw InvalidOptionDnrSvcParams Thrown in case parser had problems with extracting
+ /// SvcParams.
+ void parseAlpnSvcParam(const std::string& svc_param_val);
+
+ /// @brief Parses Port Service Parameter from a piece of convenient notation option config.
+ ///
+ /// @param svc_param_val a piece of convenient notation option config holding Port SvcParam
+ ///
+ /// @throw InvalidOptionDnrSvcParams Thrown in case parser had problems with extracting
+ /// SvcParams.
+ void parsePortSvcParam(const std::string& svc_param_val);
+
+ /// @brief Parses Dohpath Service Parameter from a piece of convenient notation option config.
+ ///
+ /// @param svc_param_val a piece of convenient notation option config holding Dohpath SvcParam
+ ///
+ /// @throw InvalidOptionDnrSvcParams Thrown in case parser had problems with extracting
+ /// SvcParams.
+ void parseDohpathSvcParam(const std::string& svc_param_val);
};
/// @brief Represents DHCPv4 Encrypted DNS %Option (code 162).
diff --git a/src/lib/dhcp/option6_dnr.h b/src/lib/dhcp/option6_dnr.h
index f8a8b4ef44..a6206b9c16 100644
--- a/src/lib/dhcp/option6_dnr.h
+++ b/src/lib/dhcp/option6_dnr.h
@@ -104,6 +104,7 @@ public:
///
/// @throw OutOfRange Thrown in case of malformed data detected during parsing e.g.
/// Addr Len not divisible by 16, Addr Len is 0, addresses data truncated etc.
+ /// @throw BadValue Thrown when trying to unpack address which is not an IPv6 address
void unpackAddresses(OptionBufferConstIter& begin, OptionBufferConstIter end) override;
private:
diff --git a/src/lib/dhcp/option_definition.cc b/src/lib/dhcp/option_definition.cc
index adb69e85e7..54d569b660 100644
--- a/src/lib/dhcp/option_definition.cc
+++ b/src/lib/dhcp/option_definition.cc
@@ -319,8 +319,11 @@ OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
// true, so that the factory will have a chance to handle it in a special way.
// At this stage any escape backslash chars were lost during last call of
- // isc::util::str::tokens(), so we must restore them. Some INTERNAL options may use
- // escaped delimiters, e.g. DNR options.
+ // isc::util::str::tokens() inside of
+ // OptionDataParser::createOption(ConstElementPtr option_data), so we must
+ // restore them. Some INTERNAL options may use escaped delimiters, e.g. DNR options.
+ // Values are concatenated back to comma separated format and will be written to
+ // the OptionBuffer as one String type option.
std::ostringstream stream;
bool first = true;
for (auto val : values) {
diff --git a/src/lib/dhcp/tests/option4_dnr_unittest.cc b/src/lib/dhcp/tests/option4_dnr_unittest.cc
index 2fb616a4ff..a472cb1f3d 100644
--- a/src/lib/dhcp/tests/option4_dnr_unittest.cc
+++ b/src/lib/dhcp/tests/option4_dnr_unittest.cc
@@ -685,6 +685,23 @@ TEST(Option4DnrTest, fromConfigCtorWrongSvcParamsMissingVarInDohpath) {
ASSERT_FALSE(option);
}
+// This test verifies that option constructor throws
+// an exception when config provided via ctor is malformed
+// - IPv6 address given.
+TEST(Option4DnrTest, fromConfigCtorIPv6Address) {
+ // Prepare example config.
+ const std::string config = "100, dot1.example.org., 2001:db8::1";
+
+ OptionBuffer buf;
+ buf.assign(config.begin(), config.end());
+
+ // Create option instance. Check that constructor throws.
+ Option4DnrPtr option;
+ EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end(), true)),
+ BadValue);
+ ASSERT_FALSE(option);
+}
+
// This test verifies option packing into wire data.
// Provided data to pack contains 2 DNR instances:
// 1. ADN only mode
diff --git a/src/lib/dhcp/tests/option6_dnr_unittest.cc b/src/lib/dhcp/tests/option6_dnr_unittest.cc
index 40854572d6..91d0b154b3 100644
--- a/src/lib/dhcp/tests/option6_dnr_unittest.cc
+++ b/src/lib/dhcp/tests/option6_dnr_unittest.cc
@@ -590,6 +590,23 @@ TEST(Option6DnrTest, fromConfigCtorSvcParamsKeyRepeated) {
ASSERT_FALSE(option);
}
+// This test verifies that option constructor throws
+// an exception when config provided via ctor is malformed
+// - IPv4 address given.
+TEST(Option6DnrTest, fromConfigCtorIPv4Address) {
+ // Prepare example config.
+ const std::string config = "100, dot1.example.org., 10.0.2.3";
+
+ OptionBuffer buf;
+ buf.assign(config.begin(), config.end());
+
+ // Create option instance. Check that constructor throws.
+ Option6DnrPtr option;
+ EXPECT_THROW(option.reset(new Option6Dnr(buf.begin(), buf.end(), true)),
+ BadValue);
+ ASSERT_FALSE(option);
+}
+
// This test verifies that string representation of the option returned by
// toText method is correctly formatted.
TEST(Option6DnrTest, toText) {