]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1860] lenient parsing logic for option 16
authorAndrei Pavel <andrei@isc.org>
Fri, 14 May 2021 13:38:01 +0000 (16:38 +0300)
committerAndrei Pavel <andrei@isc.org>
Wed, 19 May 2021 12:59:02 +0000 (15:59 +0300)
src/bin/dhcp4/json_config_parser.cc
src/bin/dhcp6/json_config_parser.cc
src/lib/dhcp/opaque_data_tuple.h
src/lib/dhcp/option.cc
src/lib/dhcp/option.h
src/lib/dhcpsrv/cfgmgr.cc
src/lib/dhcpsrv/srv_config.cc
src/lib/dhcpsrv/srv_config.h

index a8ea78fd591714ffe554ffc559cb2f4137526a68..977c16201ad04d32d6db80b23e7701b434048316 100644 (file)
@@ -578,6 +578,16 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
             CfgMgr::instance().getStagingCfg()->setConfigControlInfo(config_ctl_info);
         }
 
+        ConstElementPtr compatibility = mutable_cfg->get("compatibility");
+        if (compatibility) {
+            for (auto kv : compatibility->mapValue()) {
+                if (kv.first == "lenient-option-parsing") {
+                    CfgMgr::instance().getStagingCfg()->setLenientOptionParsing(
+                        kv.second->boolValue());
+                }
+            }
+        }
+
         // Make parsers grouping.
         ConfigPair config_pair;
         const std::map<std::string, ConstElementPtr>& values_map =
index c6a31a8a63a09b872dc639894a9aa70a6ab8fc73..9daf670f2ca8faffd83dc61a588c4e8488f655d9 100644 (file)
@@ -711,6 +711,16 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
             parser.parse(srv_config, rsoo_list);
         }
 
+        ConstElementPtr compatibility = mutable_cfg->get("compatibility");
+        if (compatibility) {
+            for (auto kv : compatibility->mapValue()) {
+                if (kv.first == "lenient-option-parsing") {
+                    CfgMgr::instance().getStagingCfg()->setLenientOptionParsing(
+                        kv.second->boolValue());
+                }
+            }
+        }
+
         // Make parsers grouping.
         ConfigPair config_pair;
         const std::map<std::string, ConstElementPtr>& values_map =
index b20ab6b1b5e348a6206ec9ac35b60d772c9b3a48..6554155c28341df30dff185556db91cb4c77781a 100644 (file)
@@ -7,8 +7,10 @@
 #ifndef OPAQUE_DATA_TUPLE_H
 #define OPAQUE_DATA_TUPLE_H
 
+#include <dhcp/option.h>
 #include <util/buffer.h>
 #include <util/io_utilities.h>
+
 #include <iostream>
 #include <iterator>
 #include <string>
@@ -78,8 +80,9 @@ public:
     /// @param end Iterator pointing to the end of the buffer holding wire data.
     /// @tparam InputIterator Type of the iterators passed to this function.
     /// @throw It may throw an exception if the @c unpack throws.
-    template<typename InputIterator>
-    OpaqueDataTuple(LengthFieldType length_field_type, InputIterator begin,
+    template <typename InputIterator>
+    OpaqueDataTuple(LengthFieldType length_field_type,
+                    InputIterator begin,
                     InputIterator end)
         : length_field_type_(length_field_type) {
         unpack(begin, end);
@@ -211,7 +214,6 @@ public:
     /// @tparam InputIterator Type of the iterators passed to this function.
     template<typename InputIterator>
     void unpack(InputIterator begin, InputIterator end) {
-        Buffer buf(begin, end);
         // The buffer must at least hold the size of the data.
         if (std::distance(begin, end) < getDataFieldSize()) {
             isc_throw(OpaqueDataTupleError,
@@ -226,12 +228,17 @@ public:
         // Now that we have the expected data size, let's check that the
         // reminder of the buffer is long enough.
         begin += getDataFieldSize();
+        // Attempt to parse as a length-value pair.
         if (std::distance(begin, end) < len) {
-            isc_throw(OpaqueDataTupleError,
-                      "unable to parse the opaque data tuple, the buffer"
-                      " length is " << std::distance(begin, end)
-                      << ", but the length of the tuple in the length field"
-                      " is " << len);
+            if (Option::lenient_parsing_) {
+                // Fallback to parsing the rest of the option as a single value.
+                len = std::distance(begin, end);
+            } else {
+                isc_throw(OpaqueDataTupleError,
+                          "unable to parse the opaque data tuple, "
+                          "the buffer length is " << std::distance(begin, end)
+                          << ", but the tuple length is " << len);
+            }
         }
         // The buffer length is long enough to read the desired amount of data.
         assign(begin, len);
@@ -277,6 +284,7 @@ private:
 
     /// @brief Buffer which holds the opaque tuple data.
     Buffer data_;
+
     /// @brief Holds a type of tuple size field (1 byte long or 2 bytes long).
     LengthFieldType length_field_type_;
 };
index e8f26f3da9ba8ca9d95ca2abe49e57bc34af883c..6ffb323cb881e6c6585eb10e0ae9bdc184490234 100644 (file)
@@ -402,5 +402,7 @@ Option::~Option() {
 
 }
 
+bool Option::lenient_parsing_;
+
 } // end of isc::dhcp namespace
 } // end of isc namespace
index b270be5335a56fee332b17c93d91d26ce6b8604a..25b48916041544f512b054d819c010596aecf65c 100644 (file)
@@ -451,6 +451,9 @@ public:
     /// @return true if options are equal, false otherwise.
     virtual bool equals(const Option& other) const;
 
+    /// @brief Governs whether options should be parsed less strictly.
+    static bool lenient_parsing_;
+
 protected:
 
     /// @brief Copies this option and returns a pointer to the copy.
index 955e4a6405cd1095918b8ec0da47c8ffdd847ea9..be1952e1134bc2ed27e621e0c46011baaad7057d 100644 (file)
@@ -88,8 +88,6 @@ CfgMgr::clear() {
 
 void
 CfgMgr::commit() {
-
-
     ensureCurrentAllocated();
 
     // First we need to remove statistics. The new configuration can have fewer
@@ -114,6 +112,8 @@ CfgMgr::commit() {
 
     // Now we need to set the statistics back.
     configuration_->updateStatistics();
+
+    configuration_->injectIntoDependencies();
 }
 
 void
index 0f4bc1785f9edce208c95cb0220c6753d2c804a6..80d6afdb10efa4d4509340d558f3b63eede5d16c 100644 (file)
@@ -45,7 +45,8 @@ SrvConfig::SrvConfig()
       decline_timer_(0), echo_v4_client_id_(true), dhcp4o6_port_(0),
       d2_client_config_(new D2ClientConfig()),
       configured_globals_(Element::createMap()),
-      cfg_consist_(new CfgConsistency()) {
+      cfg_consist_(new CfgConsistency()),
+      lenient_option_parsing_(false) {
 }
 
 SrvConfig::SrvConfig(const uint32_t sequence)
@@ -890,6 +891,11 @@ SrvConfig::setIPReservationsUnique(const bool unique) {
     getCfgDbAccess()->setIPReservationsUnique(unique);
 }
 
+void
+SrvConfig::injectIntoDependencies() const {
+    Option::lenient_parsing_ = lenient_option_parsing_;
+}
+
 bool
 DdnsParams::getEnableUpdates() const {
     if (!subnet_) {
index a6ee6455f5e31ac0cf230b23540a774eaaa31354..0d2af4caba46285f11692a8a6ae71c1d4c4523cb 100644 (file)
@@ -847,6 +847,28 @@ public:
     /// @return a pointer to unparsed configuration
     virtual isc::data::ElementPtr toElement() const;
 
+    /// @brief Set lenient option parsing compatibility flag.
+    ///
+    /// @param value the boolean value to be set when configuring lenient option
+    /// parsing
+    void setLenientOptionParsing(bool const value) {
+        lenient_option_parsing_ = value;
+    }
+
+    /// @brief Get lenient option parsing compatibility flag.
+    ///
+    /// @return the configured value for lenient option parsing
+    bool getLenientOptionParsing() const {
+        return lenient_option_parsing_;
+    }
+
+    /// @brief Convenience method to inject configuration parameters into
+    /// internal libraries that don't have access to the server's current
+    /// configuration
+    ///
+    /// Happen on configuration commit.
+    void injectIntoDependencies() const;
+
 private:
 
     /// @brief Merges the DHCPv4 configuration specified as a parameter into
@@ -998,6 +1020,11 @@ private:
 
     /// @brief Pointer to the configuration consistency settings
     CfgConsistencyPtr cfg_consist_;
+
+    /// @brief Compatibility flags
+    /// @{
+    bool lenient_option_parsing_;
+    /// @}
 };
 
 /// @name Pointers to the @c SrvConfig object.