]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3141] unpack alpn SvcParam
authorPiotrek Zadroga <piotrek@isc.org>
Wed, 14 Feb 2024 11:14:25 +0000 (12:14 +0100)
committerPiotrek Zadroga <piotrek@isc.org>
Fri, 23 Feb 2024 16:14:05 +0000 (17:14 +0100)
src/lib/dhcp/option4_dnr.h
src/lib/dhcp/option6_dnr.cc

index 1f0ef4088a158a690c0050a2ba12a96843c5ca88..cd653ced33dbca62a7a30f66862f0cf71ed1264b 100644 (file)
@@ -443,6 +443,17 @@ protected:
     /// following the rules in Section 2.1 of [I-D.ietf-dnsop-svcb-https].
     std::string svc_params_;
 
+    /// @brief Service Parameters stored in a map.
+    ///
+    /// A set of service parameters that are encoded following the same rules
+    /// for encoding SvcParams using the wire format specified in Section 2.2 of RFC9460.
+    /// SvcParams are stored here in a map where the key is the SvcParamKey as an uint_16.
+    /// (Defined values are in Section 14.3.2 of RFC9460 - listed in @c SVC_PARAMS).
+    /// The value is an OpaqueDataTuple containing:
+    /// - the length of the SvcParamValue as an uint_16 integer in network byte order
+    /// - data buffer the SvcParamValue in a format determined by the SvcParamKey.
+    std::map<uint16_t, OpaqueDataTuple> svc_params_map_;
+
     /// @brief Calculates and returns length of DNR Instance data in octets.
     /// @return length of DNR Instance data in octets.
     uint16_t dnrInstanceLen() const;
index 2a6ac713002b634f508b79c34e664e798ed8d671..6be3e05bf9d9ab801b6142f76b3b78734e286ba8 100644 (file)
@@ -240,60 +240,78 @@ Option6Dnr::parseConfigData(const std::string& config_txt){
         std::string txt_svc_params = str::trim(tokens[3]);
 
         // SvcParamKey=SvcParamValue pairs are separated with space
-        std::vector<std::string> svc_params = str::tokens(txt_svc_params, std::string(" "));
-        std::vector<std::string> alpn_ids;
-        std::vector<OpaqueDataTuple> alpn_ids_container;
-        for (auto const& txt_svc_param : svc_params) {
-            std::vector<std::string> key_val = str::tokens(str::trim(txt_svc_param), "=");
-            if (key_val.size() != 2) {
+        std::vector<std::string> svc_params_pairs = str::tokens(txt_svc_params, std::string(" "));
+        std::vector<std::string> alpn_ids_tokens;
+        OpaqueDataTuple alpn_svc_param_val(OpaqueDataTuple::LENGTH_2_BYTES);
+        OutputBuffer out_buf(2);
+        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");
             }
 
             // SvcParam Key related checks come below.
-            std::string key = str::trim(key_val[0]);
+            std::string svc_param_key = str::trim(key_val_tokens[0]);
 
-            if (FORBIDDEN_SVC_PARAMS.find(key) != FORBIDDEN_SVC_PARAMS.end()) {
-                isc_throw(InvalidOptionDnrSvcParams, getLogPrefix() << "Wrong Svc Params syntax - key "
-                                                                    << key << " must not be used");
+            // 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");
             }
 
-            auto svc_params_iterator = SVC_PARAMS.find(key);
+            // Check if SvcParamKey is known in https://www.iana.org/assignments/dns-svcb/dns-svcb.xhtml
+            auto svc_params_iterator = SVC_PARAMS.find(svc_param_key);
             if (svc_params_iterator == SVC_PARAMS.end()) {
                 isc_throw(InvalidOptionDnrSvcParams,
                           getLogPrefix() << "Wrong Svc Params syntax - key "
-                                         << key
+                                         << svc_param_key
                                          << " not found in SvcParamKeys registry");
             }
 
-            uint8_t num_svc_param_key = svc_params_iterator->second;
+            // Check if SvcParamKey usage is supported by DNR DHCP option.
+            // Note that SUPPORTED_SVC_PARAMS set may expand in 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 "
-                                         << key
+                                         << svc_param_key
                                          << " not supported in DNR option SvcParams");
             }
 
+            // 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.");
+            }
+
             // SvcParam Val check.
-            std::string val = str::trim(key_val[1]);
-            if (val.empty()) {
+            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 "
-                                         << key);
+                                         << svc_param_key);
             }
 
-
-
             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 = str::tokens(val, std::string(","));
-                for (auto const& alpn_id : alpn_ids) {
+                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 "
@@ -303,9 +321,13 @@ Option6Dnr::parseConfigData(const std::string& config_txt){
 
                     OpaqueDataTuple alpn_id_tuple(OpaqueDataTuple::LENGTH_1_BYTE);
                     alpn_id_tuple.append(alpn_id);
-                    alpn_ids_container.push_back(alpn_id_tuple);
+                    alpn_id_tuple.pack(out_buf);
+                    alpn_svc_param_val.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, alpn_svc_param_val));
+
                 break;
             case 3:
                 // port
@@ -316,13 +338,13 @@ Option6Dnr::parseConfigData(const std::string& config_txt){
             }
         }
 
-        std::ostringstream stream;
-        for (auto const& t : alpn_ids_container) {
-            stream << t.getLength() << "-" << t.getText() << " ";
-        }
-        isc_throw(BadValue, getLogPrefix() << "SvcParams: " + txt_svc_params + ", parsed "
-                                                                               "alpn-ids "
-                  + stream.str());
+        isc_throw(BadValue,
+                  getLogPrefix() << "SvcParams: " + txt_svc_params
+                                 << ", parsed alpn SvcParamVal len-data_to_text "
+                  << alpn_svc_param_val.getLength()
+                  << "-"
+                  << str::dumpAsHex(alpn_svc_param_val.getData().data(), alpn_svc_param_val.getLength())
+                  );
     }
 
 }