]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3074] WIP new class for v4 option 121
authorPiotrek Zadroga <piotrek@isc.org>
Mon, 9 Oct 2023 20:12:12 +0000 (22:12 +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 a4899fcdfdba789165fe11e4902dfafcf235d049..6d0110f2350b2d52b91caebbd43d65d0b161f041 100644 (file)
@@ -4,14 +4,25 @@
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-#include "option_classless_static_route.h"
+#include <config.h>
+
+#include <option_classless_static_route.h>
+
+using namespace isc::asiolink;
+using namespace isc::util;
 
 namespace isc {
 namespace dhcp {
 
+OptionClasslessStaticRoute::OptionClasslessStaticRoute(OptionBufferConstIter begin,
+                                                       OptionBufferConstIter end)
+    : Option(V4, DHO_CLASSLESS_STATIC_ROUTE) {
+    unpack(begin, end);
+}
+
 OptionPtr
 OptionClasslessStaticRoute::clone() const {
-    return Option::clone();
+    return (cloneInternal<OptionClasslessStaticRoute>());
 }
 
 void
@@ -20,9 +31,28 @@ OptionClasslessStaticRoute::pack(isc::util::OutputBuffer& buf, bool check) const
 }
 
 void
-OptionClasslessStaticRoute::unpack(OptionBufferConstIter begin,
-                                              OptionBufferConstIter end) {
-    Option::unpack(begin, end);
+OptionClasslessStaticRoute::unpack(OptionBufferConstIter begin, OptionBufferConstIter end) {
+    if (distance(begin, end) % (V4ADDRESS_LEN * 3)) {
+        isc_throw(OutOfRange, "DHCPv4 OptionClasslessStaticRoute "
+                                  << type_ << " has invalid length=" << distance(begin, end)
+                                  << ", must be divisible by 12.");
+    }
+
+    while (begin != end) {
+        const uint8_t* ptr = &(*begin);
+        auto subnet_nr = IOAddress(readUint32(ptr, distance(begin, end)));
+        begin += V4ADDRESS_LEN;
+
+        uint32_t subnet_mask = readUint32(ptr, distance(begin, end));
+        uint8_t mask_width = calcMaskWidth(subnet_mask);
+        begin += V4ADDRESS_LEN;
+
+        auto router_addr = IOAddress(readUint32(ptr, distance(begin, end)));
+        begin += V4ADDRESS_LEN;
+
+        StaticRouteTuple route = std::make_tuple(subnet_nr, PrefixLen(mask_width), router_addr);
+        addRoute(route);
+    }
 }
 
 std::string
@@ -35,6 +65,43 @@ OptionClasslessStaticRoute::len() const {
     return Option::len();
 }
 
+uint8_t
+OptionClasslessStaticRoute::calcMaskWidth(uint32_t subnet_mask) {
+    uint8_t len = 0;
+    while (subnet_mask) {
+        if (subnet_mask & 0x80000000) {
+            ++len;
+            subnet_mask <<= 1;
+            continue;
+        }
+
+        break;
+    }
+
+    return (len);
+}
+
+void
+OptionClasslessStaticRoute::addRoute(StaticRouteTuple& route) {
+    static_routes_.push_back(route);
+}
+
+std::vector<uint8_t>
+OptionClasslessStaticRoute::encodeDestinationDescriptor(StaticRouteTuple& route) {
+    auto subnet = get<0>(route).toBytes();
+    auto mask_width= get<1>(route).asUint8();
+    std::vector<uint8_t> res;
+    res.push_back(mask_width);
+    if (mask_width == 0) {
+        return (res);
+    }
+
+    uint8_t significant_octets = mask_width / 8 + (mask_width % 8 != 0);
+    res.insert(res.end(), subnet.begin(), subnet.begin() + significant_octets);
+
+    return (res);
+}
+
 }  // namespace dhcp
 }  // namespace isc
 
index bfc0337cd4a292898b8a406fd782a3e98e36656c..7fe44efa765645abdbb1ccc1d36167322401f56b 100644 (file)
@@ -9,16 +9,29 @@
 
 #include <dhcp/dhcp4.h>
 #include <dhcp/option.h>
+#include <dhcp/option_data_types.h>
 
 namespace isc {
 namespace dhcp {
 
+/// @brief Defines a tuple of Subnet number, Subnet mask width and IPv4 router address.
+typedef std::tuple<asiolink::IOAddress, PrefixLen, asiolink::IOAddress> StaticRouteTuple;
+
+/// @brief Represents DHCPv4 Classless Static Route %Option (code 121).
 class OptionClasslessStaticRoute : public Option {
 public:
-    /// @brief Constructor
-    OptionClasslessStaticRoute() : Option(V4, DHO_CLASSLESS_STATIC_ROUTE) {
+    /// @brief Empty Constructor
+    OptionClasslessStaticRoute() : Option(V4, DHO_CLASSLESS_STATIC_ROUTE) {}
 
-    }
+    /// @brief Constructor of the %Option from on-wire data.
+    ///
+    /// This constructor creates an instance of the option using a buffer with
+    /// on-wire data. It may throw an exception if the @c unpack method throws.
+    ///
+    /// @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.
+    OptionClasslessStaticRoute(OptionBufferConstIter begin, OptionBufferConstIter end);
 
     /// @brief Copies this option and returns a pointer to the copy.
     ///
@@ -35,13 +48,14 @@ public:
     /// @param check flag which indicates if checking the option length is
     /// required (used only in V4)
     ///
-    /// @throw InvalidOptionDnrDomainName Thrown when Option's mandatory field ADN is empty.
-    void pack(util::OutputBuffer& buf, bool check = false) const override;
+    /// @throw
+    void pack(util::OutputBuffer& buf, bool check = true) const override;
 
     /// @brief Parses received wire data buffer.
     ///
     /// @param begin iterator to first byte of option data
     /// @param end iterator to end of option data (first byte after option end)
+    /// @throw
     void unpack(OptionBufferConstIter begin, OptionBufferConstIter end) override;
 
     /// @brief Returns string representation of the option.
@@ -57,8 +71,29 @@ public:
     /// @return length of the option
     uint16_t len() const override;
 
+    /// @brief Adds static route to collection of all static routes.
+    /// @param route A tuple defining new static route
+    void addRoute(StaticRouteTuple& route);
+
+private:
+    /// @brief Container holding all static routes.
+    std::vector<StaticRouteTuple> static_routes_;
+
+    /// @brief Calculates subnet mask width from given uint_32 representation of subnet mask.
+    /// @param subnet_mask uint_32 representation of a subnet mask IPv4 address
+    /// @return width of subnet mask in a range of 0-32
+    static uint8_t calcMaskWidth(uint32_t subnet_mask);
+
+    /// @brief Encodes destination descriptor as per RFC3442.
+    /// @param route static route tuple
+    /// @return Contents of the destination descriptor as a vector
+    /// of bytes in network-byte order.
+    static std::vector<uint8_t> encodeDestinationDescriptor(StaticRouteTuple& route) ;
 };
 
+/// A pointer to the @c OptionClasslessStaticRoute object.
+typedef boost::shared_ptr<OptionClasslessStaticRoute> OptionClasslessStaticRoutePtr;
+
 }  // namespace dhcp
 }  // namespace isc