]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3074] code cleaning + docs
authorPiotrek Zadroga <piotrek@isc.org>
Mon, 16 Oct 2023 21:18:45 +0000 (23:18 +0200)
committerPiotrek Zadroga <piotrek@isc.org>
Tue, 9 Jan 2024 10:38:08 +0000 (11:38 +0100)
src/lib/dhcp/option_classless_static_route.cc
src/lib/dhcp/option_classless_static_route.h

index c2a4c985786e080283bf2cf930f8ba91dd838041..4a6f640cdcf78bcaf02b2af52d6b3db3ca492046 100644 (file)
@@ -51,14 +51,14 @@ OptionClasslessStaticRoute::unpack(OptionBufferConstIter begin, OptionBufferCons
                                   << ", must be at least 5.");
     }
 
-    // As an alternative to binary format,
+    // As an alternative to the binary format,
     // we provide convenience option definition as a string in format:
     // subnet1 - router1 IP addr, subnet2 - router2 IP addr, ...
     // e.g.:
     // 10.0.0.0/8 - 10.2.3.1, 10.229.0.128/25 - 10.1.0.3, ...
     // where destination descriptors will be encoded as per RFC3442.
     // We need to determine if OptionBuffer contains dash `-` separator (0x2d).
-    // If not, we assume this is binary format and no encoding needs to be done.
+    // If not, we assume this is binary format.
     auto begin_copy = begin;
     while (begin_copy != end) {
         if (*begin_copy == '-') {
@@ -70,137 +70,11 @@ OptionClasslessStaticRoute::unpack(OptionBufferConstIter begin, OptionBufferCons
 
     if (begin_copy == end) {
         // no separator found, assuming this is a hex on-wire data
-        while (begin != end) {
-            // check for truncated data for each static route
-            if (distance(begin, end) < 5) {
-                isc_throw(OutOfRange, "DHCPv4 OptionClasslessStaticRoute "
-                                          << type_ << " has invalid length=" << distance(begin, end)
-                                          << ", must be at least 5.");
-            }
-
-            // 1st octet is a width of subnet mask
-            uint8_t mask_width = *begin;
-            if (mask_width > 32) {
-                isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
-                                        << type_ << " has invalid value, provided width of subnet mask "
-                                        << static_cast<int>(mask_width) << " is not valid.");
-            }
-
-            uint8_t significant_octets = calcSignificantOctets(mask_width);
-            ++begin;
-
-            // once we know haw many significant octets there are, check for truncated data again
-            if (distance(begin, end) < (significant_octets + V4ADDRESS_LEN)) {
-                isc_throw(OutOfRange, "DHCPv4 OptionClasslessStaticRoute "
-                                          << type_ << " is truncated.");
-            }
-
-            // following octets are significant octets of the subnet nr
-            uint32_t subnet_octets;
-            IOAddress subnet_nr = asiolink::IOAddress::IPV4_ZERO_ADDRESS();
-
-            switch (significant_octets) {
-            case 0:
-                // no-op - this is 0.0.0.0/0 subnet
-                break;
-            case 1:
-                subnet_octets = *begin;
-                subnet_nr = IOAddress(subnet_octets << 24);
-                break ;
-            case 2:
-                subnet_octets = readUint16(&(*begin), distance(begin, end));
-                subnet_nr = IOAddress(subnet_octets << 16);
-                break ;
-            case 3:
-                // we are reading one octet too much in this case,
-                // but since we did check for truncated data before,
-                // we are safe do so and mask 4th octet with zeros
-                subnet_octets = readUint32(&(*begin), distance(begin, end));
-                subnet_nr = IOAddress(subnet_octets & 0xFFFFFF00);
-                break ;
-            case 4:
-                subnet_octets = readUint32(&(*begin), distance(begin, end));
-                subnet_nr = IOAddress(subnet_octets);
-                break;
-            }
-
-            begin += significant_octets;
-
-            // last comes router IPv4 address
-            IOAddress router_addr = IOAddress(readUint32(&(*begin), distance(begin, end)));
-            begin += V4ADDRESS_LEN;
-
-            StaticRouteTuple route = std::make_tuple(subnet_nr, mask_width, router_addr);
-            static_routes_.push_back(route);
-        }
+        parseWireData(begin, end);
     } else {
         // separator was found, assuming this is option data string from config
-        std::string buffer_to_str = std::string(begin, end);
-        // this option allows more than one static route, so let's separate them using comma
-        std::vector<std::string> tokens = str::tokens(buffer_to_str, std::string(","));
-        for (const auto& route_str : tokens) {
-            std::vector<std::string> parts = str::tokens(str::trim(route_str), std::string("-"));
-            if (parts.size() != 2) {
-                isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
-                                        << type_ << " has invalid value, route definition must"
-                                                    " have format as in example: 10.229.0.128/25"
-                                                    " - 10.229.0.1");
-            }
-
-            std::string txt_prefix = str::trim(parts[0]);
-
-            // Is this prefix/len notation?
-            size_t pos = txt_prefix.find('/');
-            if (pos == std::string::npos) {
-                isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
-                                        << type_ << " has invalid value, provided IPv4 prefix "
-                                        << parts[0] << " is not valid.");
-            }
-
-            std::string txt_subnet_nr = txt_prefix.substr(0, pos);
-            IOAddress subnet_nr = IOAddress("::");
-            try {
-                subnet_nr = IOAddress(txt_subnet_nr);
-                if (!subnet_nr.isV4()) {
-                    isc_throw(IOError, "");
-                }
-            } catch (const IOError& e) {
-                isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
-                                        << type_ << " has invalid value, provided subnet_nr "
-                                        << txt_subnet_nr << " is not a valid IPv4 address.");
-            }
-
-            std::string txt_prefix_len = txt_prefix.substr(pos + 1);
-            int8_t len = 0;
-            try {
-                // We should be able to lexically cast IPv4 prefix len to short int,
-                // and then downcast it to signed char. After that len<=32 check is
-                // also required.
-                len = boost::numeric_cast<int8_t>(boost::lexical_cast<int16_t>(txt_prefix_len));
-                if (len > 32) {
-                    isc_throw(BadValue, "");
-                }
-            } catch (...)  {
-                isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
-                                        << type_ << " has invalid value, provided prefix len "
-                                               << txt_prefix_len << " is not valid.");
-            }
-
-            IOAddress router_addr = IOAddress("::");
-            try {
-                router_addr = IOAddress(str::trim(parts[1]));
-                if (!router_addr.isV4()) {
-                    isc_throw(IOError, "");
-                }
-            } catch (const IOError& e) {
-                isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
-                                        << type_ << " has invalid value, provided router address "
-                                        << parts[1] << " is not a valid IPv4 address.");
-            }
-
-            StaticRouteTuple route = std::make_tuple(subnet_nr, len, router_addr);
-            static_routes_.push_back(route);
-        }
+        std::string config_txt = std::string(begin, end);
+        parseConfigData(config_txt);
     }
 
     calcDataLen();
@@ -289,5 +163,141 @@ OptionClasslessStaticRoute::calcDataLen() {
     data_len_ = len;
 }
 
+void
+OptionClasslessStaticRoute::parseWireData(OptionBufferConstIter begin, OptionBufferConstIter end) {
+    while (begin != end) {
+        // check for truncated data for each static route
+        if (distance(begin, end) < 5) {
+            isc_throw(OutOfRange, "DHCPv4 OptionClasslessStaticRoute "
+                                      << type_ << " has invalid length=" << distance(begin, end)
+                                      << ", must be at least 5.");
+        }
+
+        // 1st octet is a width of subnet mask
+        uint8_t mask_width = *begin;
+        if (mask_width > 32) {
+            isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
+                                    << type_ << " has invalid value, provided width of subnet mask "
+                                    << static_cast<int>(mask_width) << " is not valid.");
+        }
+
+        uint8_t significant_octets = calcSignificantOctets(mask_width);
+        ++begin;
+
+        // once we know haw many significant octets there are, check for truncated data again
+        if (distance(begin, end) < (significant_octets + V4ADDRESS_LEN)) {
+            isc_throw(OutOfRange, "DHCPv4 OptionClasslessStaticRoute "
+                                      << type_ << " is truncated.");
+        }
+
+        // following octets are significant octets of the subnet nr
+        uint32_t subnet_octets;
+        IOAddress subnet_nr = asiolink::IOAddress::IPV4_ZERO_ADDRESS();
+
+        switch (significant_octets) {
+        case 0:
+            // no-op - this is 0.0.0.0/0 subnet
+            break;
+        case 1:
+            subnet_octets = *begin;
+            subnet_nr = IOAddress(subnet_octets << 24);
+            break ;
+        case 2:
+            subnet_octets = readUint16(&(*begin), distance(begin, end));
+            subnet_nr = IOAddress(subnet_octets << 16);
+            break ;
+        case 3:
+            // we are reading one octet too much in this case,
+            // but since we did check for truncated data before,
+            // we are safe do so and mask 4th octet with zeros
+            subnet_octets = readUint32(&(*begin), distance(begin, end));
+            subnet_nr = IOAddress(subnet_octets & 0xFFFFFF00);
+            break ;
+        case 4:
+            subnet_octets = readUint32(&(*begin), distance(begin, end));
+            subnet_nr = IOAddress(subnet_octets);
+            break;
+        }
+
+        begin += significant_octets;
+
+        // last comes router IPv4 address
+        IOAddress router_addr = IOAddress(readUint32(&(*begin), distance(begin, end)));
+        begin += V4ADDRESS_LEN;
+
+        StaticRouteTuple route = std::make_tuple(subnet_nr, mask_width, router_addr);
+        static_routes_.push_back(route);
+    }
+}
+
+void
+OptionClasslessStaticRoute::parseConfigData(const std::string& config_txt) {
+    // this option allows more than one static route, so let's separate them using comma
+    std::vector<std::string> tokens = str::tokens(config_txt, std::string(","));
+    for (const auto& route_str : tokens) {
+        std::vector<std::string> parts = str::tokens(str::trim(route_str), std::string("-"));
+        if (parts.size() != 2) {
+            isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
+                                    << type_ << " has invalid value, route definition must"
+                                                " have format as in example: 10.229.0.128/25"
+                                                " - 10.229.0.1");
+        }
+
+        std::string txt_prefix = str::trim(parts[0]);
+
+        // Is this prefix/len notation?
+        size_t pos = txt_prefix.find('/');
+        if (pos == std::string::npos) {
+            isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
+                                    << type_ << " has invalid value, provided IPv4 prefix "
+                                    << parts[0] << " is not valid.");
+        }
+
+        std::string txt_subnet_nr = txt_prefix.substr(0, pos);
+        IOAddress subnet_nr = IOAddress("::");
+        try {
+            subnet_nr = IOAddress(txt_subnet_nr);
+            if (!subnet_nr.isV4()) {
+                isc_throw(IOError, "");
+            }
+        } catch (const IOError& e) {
+            isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
+                                    << type_ << " has invalid value, provided subnet_nr "
+                                    << txt_subnet_nr << " is not a valid IPv4 address.");
+        }
+
+        std::string txt_prefix_len = txt_prefix.substr(pos + 1);
+        int8_t len = 0;
+        try {
+            // We should be able to lexically cast IPv4 prefix len to short int,
+            // and then downcast it to signed char. After that len<=32 check is
+            // also required.
+            len = boost::numeric_cast<int8_t>(boost::lexical_cast<int16_t>(txt_prefix_len));
+            if (len > 32) {
+                isc_throw(BadValue, "");
+            }
+        } catch (...)  {
+            isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
+                                    << type_ << " has invalid value, provided prefix len "
+                                    << txt_prefix_len << " is not valid.");
+        }
+
+        IOAddress router_addr = IOAddress("::");
+        try {
+            router_addr = IOAddress(str::trim(parts[1]));
+            if (!router_addr.isV4()) {
+                isc_throw(IOError, "");
+            }
+        } catch (const IOError& e) {
+            isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
+                                    << type_ << " has invalid value, provided router address "
+                                    << parts[1] << " is not a valid IPv4 address.");
+        }
+
+        StaticRouteTuple route = std::make_tuple(subnet_nr, len, router_addr);
+        static_routes_.push_back(route);
+    }
+}
+
 }  // namespace dhcp
 }  // namespace isc
index e39347fd41b7c1be9c24adff952b637af55e906a..5ebcfcadfdaf8053ca0b63912969d2413b61247d 100644 (file)
@@ -42,21 +42,19 @@ public:
     ///
     /// Writes option in wire-format to buffer, returns pointer to first unused
     /// byte after stored option (that is useful for writing options one after
-    /// another).
+    /// another). It may throw an exception if the @c packHeader method throws.
     ///
     /// @param buf pointer to a buffer
     /// @param check flag which indicates if checking the option length is
     /// required (used only in V4)
-    ///
-    /// @throw OutOfRange Thrown when @c check param set to @c true and
-    /// @c Option::packHeader(buf,check) throws due to option len>255 octets.
     void pack(util::OutputBuffer& buf, bool check = true) const override;
 
-    /// @brief Parses received wire data buffer.
+    /// @brief Parses option from the received buffer.
     ///
     /// @param begin iterator to first byte of option data
     /// @param end iterator to end of option data (first byte after option end)
-    /// @throw
+    ///
+    /// @throw OutOfRange Thrown in case option contents are truncated.
     void unpack(OptionBufferConstIter begin, OptionBufferConstIter end) override;
 
     /// @brief Returns string representation of the option.
@@ -110,9 +108,38 @@ private:
     /// Calculation is done according to static routes encoding rules in RFC3442.
     /// This should be called whenever @c static_routes_ is changed.
     void calcDataLen();
+
+    /// @brief Parses received wire data buffer.
+    ///
+    /// It is used by @c unpack method in case received buffer with
+    /// option data is in binary on-wire format.
+    ///
+    /// @param begin iterator to first byte of option data
+    /// @param end iterator to end of option data (first byte after option end)
+    ///
+    /// @throw OutOfRange Thrown in case option contents are truncated.
+    /// @throw BadValue Thrown in case received width of subnet mask value is invalid.
+    void parseWireData(OptionBufferConstIter begin, OptionBufferConstIter end);
+
+    /// @brief Parses a convenient notation of the option data, which may be used in config.
+    ///
+    /// As an alternative to the binary format,
+    /// we provide convenience option definition as a string in format:
+    /// subnet1 - router1 IP addr, subnet2 - router2 IP addr, ..., subnetN - routerN IP addr
+    /// e.g.:
+    /// 10.0.0.0/8 - 10.2.3.1, 10.229.0.128/25 - 10.1.0.3
+    ///
+    /// This notation may be used in the server config, thanks to the possibility of specifying
+    /// data for binary option as a single-quoted text string within double quotes
+    /// (@c csv-format flag must be set to @c false).
+    ///
+    /// @param config_txt convenient notation of the option data received as string
+    ///
+    /// @throw BadValue Thrown in case parser found wrong format of received string.
+    void parseConfigData(const std::string& config_txt);
 };
 
-/// A pointer to the @c OptionClasslessStaticRoute object.
+/// A shared pointer to the @c OptionClasslessStaticRoute object.
 typedef boost::shared_ptr<OptionClasslessStaticRoute> OptionClasslessStaticRoutePtr;
 
 }  // namespace dhcp