summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcp/libdhcp++.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/dhcp/libdhcp++.h')
-rw-r--r--src/lib/dhcp/libdhcp++.h452
1 files changed, 452 insertions, 0 deletions
diff --git a/src/lib/dhcp/libdhcp++.h b/src/lib/dhcp/libdhcp++.h
new file mode 100644
index 0000000..81f7e84
--- /dev/null
+++ b/src/lib/dhcp/libdhcp++.h
@@ -0,0 +1,452 @@
+// Copyright (C) 2011-2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// 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/.
+
+#ifndef LIBDHCP_H
+#define LIBDHCP_H
+
+#include <dhcp/option_definition.h>
+#include <dhcp/option_space_container.h>
+#include <dhcp/option_space.h>
+#include <dhcp/pkt4.h>
+#include <dhcp/pkt6.h>
+#include <util/buffer.h>
+#include <util/staged_value.h>
+
+#include <iostream>
+#include <stdint.h>
+#include <string>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief A pointer to a ScopedPktOptionsCopy object instantiated using Pkt4.
+typedef ScopedPktOptionsCopy<Pkt4> ScopedPkt4OptionsCopy;
+/// @brief A pointer to a ScopedPktOptionsCopy object instantiated using Pkt6.
+typedef ScopedPktOptionsCopy<Pkt6> ScopedPkt6OptionsCopy;
+/// @brief A pointer to a ScopedSubOptionsCopy object.
+typedef std::shared_ptr<ScopedSubOptionsCopy> ScopedOptionsCopyPtr;
+/// @brief A container of ScopedOptionsCopyPtr objects.
+typedef std::vector<ScopedOptionsCopyPtr> ScopedOptionsCopyContainer;
+
+struct ManagedScopedOptionsCopyContainer {
+ /// @brief Constructor.
+ ManagedScopedOptionsCopyContainer() {
+ }
+
+ /// @brief Destructor.
+ ~ManagedScopedOptionsCopyContainer() {
+ // Destroy the scoped options in same order so that parent options
+ // (stored last) are kept alive longer.
+ for (auto& scoped : scoped_options_) {
+ scoped.reset();
+ }
+ }
+
+ /// @brief The container.
+ ScopedOptionsCopyContainer scoped_options_;
+};
+
+class LibDHCP {
+
+public:
+
+ /// Map of factory functions.
+ typedef std::map<unsigned short, Option::Factory*> FactoryMap;
+
+ /// @brief Returns collection of option definitions.
+ ///
+ /// This method returns a collection of option definitions for a specified
+ /// option space.
+ ///
+ /// @param space Option space.
+ ///
+ /// @return Pointer to a collection of option definitions.
+ static const OptionDefContainerPtr getOptionDefs(const std::string& space);
+
+ /// @brief Return the first option definition matching a
+ /// particular option code.
+ ///
+ /// @param space option space.
+ /// @param code option code.
+ ///
+ /// @return reference to an option definition being requested
+ /// or NULL pointer if option definition has not been found.
+ static OptionDefinitionPtr getOptionDef(const std::string& space,
+ const uint16_t code);
+
+ /// @brief Return the definition of option having a specified name.
+ ///
+ /// @param space option space.
+ /// @param name Option name.
+ ///
+ /// @return Pointer to the option definition or NULL pointer if option
+ /// definition has not been found.
+ static OptionDefinitionPtr getOptionDef(const std::string& space,
+ const std::string& name);
+
+ /// @brief Returns vendor option definition for a given vendor-id and code
+ ///
+ /// @param u universe (V4 or V6)
+ /// @param vendor_id enterprise-id for a given vendor
+ /// @param code option code
+ /// @return reference to an option definition being requested
+ /// or NULL pointer if option definition has not been found.
+ static OptionDefinitionPtr getVendorOptionDef(const Option::Universe u,
+ const uint32_t vendor_id,
+ const uint16_t code);
+
+ /// @brief Returns vendor option definition for a given vendor-id and
+ /// option name.
+ ///
+ /// @param u Universe (V4 or V6)
+ /// @param vendor_id Enterprise-id for a given vendor
+ /// @param name Option name.
+ ///
+ /// @return A pointer to an option definition or NULL pointer if
+ /// no option definition found.
+ static OptionDefinitionPtr getVendorOptionDef(const Option::Universe u,
+ const uint32_t vendor_id,
+ const std::string& name);
+
+
+ /// @brief Returns runtime (non-standard) option definition by space and
+ /// option code.
+ ///
+ /// @param space Option space name.
+ /// @param code Option code.
+ ///
+ /// @return Pointer to option definition or NULL if it doesn't exist.
+ static OptionDefinitionPtr getRuntimeOptionDef(const std::string& space,
+ const uint16_t code);
+
+ /// @brief Returns runtime (non-standard) option definition by space and
+ /// option name.
+ ///
+ /// @param space Option space name.
+ /// @param name Option name.
+ ///
+ /// @return Pointer to option definition or NULL if it doesn't exist.
+ static OptionDefinitionPtr getRuntimeOptionDef(const std::string& space,
+ const std::string& name);
+
+ /// @brief Returns runtime (non-standard) option definitions for specified
+ /// option space name.
+ ///
+ /// @param space Option space name.
+ ///
+ /// @return Pointer to the container holding option definitions or NULL.
+ static OptionDefContainerPtr getRuntimeOptionDefs(const std::string& space);
+
+ /// @brief Returns last resort option definition by space and option code.
+ ///
+ /// @param space Option space name.
+ /// @param code Option code.
+ ///
+ /// @return Pointer to option definition or NULL if it doesn't exist.
+ static OptionDefinitionPtr getLastResortOptionDef(const std::string& space,
+ const uint16_t code);
+
+ /// @brief Returns last resort option definition by space and option name.
+ ///
+ /// @param space Option space name.
+ /// @param name Option name.
+ ///
+ /// @return Pointer to option definition or NULL if it doesn't exist.
+ static OptionDefinitionPtr getLastResortOptionDef(const std::string& space,
+ const std::string& name);
+
+ /// @brief Returns last resort option definitions for specified option
+ /// space name.
+ ///
+ /// @param space Option space name.
+ ///
+ /// @return Pointer to the container holding option definitions or NULL.
+ static OptionDefContainerPtr getLastResortOptionDefs(const std::string& space);
+
+ /// @brief Checks if an option unpacking has to be deferred.
+ ///
+ /// DHCPv4 option 43 and 224-254 unpacking is done after classification.
+ ///
+ /// @param space Option space name.
+ /// @param code Option code.
+ ///
+ /// @return True if option processing should be deferred.
+ static bool shouldDeferOptionUnpack(const std::string& space,
+ const uint16_t code);
+
+ /// @brief Factory function to create instance of option.
+ ///
+ /// Factory method creates instance of specified option. The option
+ /// to be created has to have corresponding factory function
+ /// registered with \ref LibDHCP::OptionFactoryRegister.
+ ///
+ /// @param u universe of the option (V4 or V6)
+ /// @param type option-type
+ /// @param buf option-buffer
+ ///
+ /// @return instance of option.
+ ///
+ /// @throw isc::InvalidOperation if there is no factory function registered
+ /// for the specified option type.
+ static isc::dhcp::OptionPtr optionFactory(isc::dhcp::Option::Universe u,
+ uint16_t type,
+ const OptionBuffer& buf);
+
+ /// @brief Stores DHCPv4 options in a buffer.
+ ///
+ /// Stores all options defined in options containers in a on-wire
+ /// format in output buffer specified by buf.
+ ///
+ /// May throw different exceptions if option assembly fails. There
+ /// may be different reasons (option too large, option malformed,
+ /// too many options etc.)
+ ///
+ /// This is v4 specific version, which stores DHCP message type first,
+ /// and the Relay Agent Information option and END options last. This
+ /// function is initially called to pack the options for a packet in
+ /// @ref Pkt4::pack(). That call leads to it being called recursively in
+ /// @ref Option::packOptions(). Thus the logic used to output the
+ /// message type should only be executed by the top-most. This is governed
+ /// by the parameter top, below.
+ ///
+ /// @param buf output buffer (assembled options will be stored here)
+ /// @param options collection of options to store to
+ /// @param top indicates if this is the first call to pack the options.
+ /// When true logic to emit the message type first is executed. It
+ /// defaults to false.
+ /// @param check indicates if the code should be more flexible with
+ /// PAD and END options. If true, PAD and END options will not be parsed.
+ /// This is useful for partial parsing and slightly broken packets.
+ static void packOptions4(isc::util::OutputBuffer& buf,
+ const isc::dhcp::OptionCollection& options,
+ bool top = false, bool check = true);
+
+ /// @brief Split long options in multiple options with the same option code
+ /// (RFC3396).
+ ///
+ /// @param options The option container which needs to be updated with split
+ /// options.
+ /// @param scopedOptions temporary storage for options that are going to be
+ /// split. See @ref ScopedPktOptionsCopy for explanation.
+ /// @param used The size of the buffer that has already been used by the
+ /// parent option effectively shrinking the maximum supported length for
+ /// each options in the container.
+ /// @return True if any option has been split, false otherwise.
+ static bool splitOptions4(isc::dhcp::OptionCollection& options,
+ ScopedOptionsCopyContainer& scopedOptions,
+ uint32_t used = 0);
+
+ /// @brief Stores DHCPv6 options in a buffer.
+ ///
+ /// Stores all options defined in options containers in a on-wire
+ /// format in output buffer specified by buf.
+ ///
+ /// May throw different exceptions if option assembly fails. There
+ /// may be different reasons (option too large, option malformed,
+ /// too many options etc.)
+ ///
+ /// Currently there's no special logic in it. Options are stored in
+ /// the order of their option codes.
+ ///
+ /// @param buf output buffer (assembled options will be stored here)
+ /// @param options collection of options to store to
+ static void packOptions6(isc::util::OutputBuffer& buf,
+ const isc::dhcp::OptionCollection& options);
+
+ /// @brief Parses provided buffer as DHCPv6 options and creates
+ /// Option objects.
+ ///
+ /// Parses provided buffer and stores created Option objects in
+ /// options container. The last two parameters are optional and
+ /// are used in relay parsing. If they are specified, relay-msg
+ /// option is not created, but rather those two parameters are
+ /// specified to point out where the relay-msg option resides and
+ /// what is its length. This is a performance optimization that
+ /// avoids unnecessary copying of potentially large relay-msg
+ /// option. It is not used for anything, except in the next
+ /// iteration its content will be treated as buffer to be parsed.
+ ///
+ /// @param buf Buffer to be parsed.
+ /// @param option_space A name of the option space which holds definitions
+ /// to be used to parse options in the packets.
+ /// @param options Reference to option container. Options will be
+ /// put here.
+ /// @param relay_msg_offset reference to a size_t structure. If specified,
+ /// offset to beginning of relay_msg option will be stored in it.
+ /// @param relay_msg_len reference to a size_t structure. If specified,
+ /// length of the relay_msg option will be stored in it.
+ /// @return offset to the first byte after the last successfully
+ /// parsed option
+ ///
+ /// @note This function throws when an option type is defined more
+ /// than once, and it calls option building routines which can throw.
+ /// Partial parsing does not throw: it is the responsibility of the
+ /// caller to handle this condition.
+ static size_t unpackOptions6(const OptionBuffer& buf,
+ const std::string& option_space,
+ isc::dhcp::OptionCollection& options,
+ size_t* relay_msg_offset = 0,
+ size_t* relay_msg_len = 0);
+
+ /// @brief Fuse multiple options with the same option code in long options
+ /// (RFC3396).
+ ///
+ /// @param options The option container which needs to be updated with fused
+ /// options.
+ /// @return True if any option has been fused, false otherwise.
+ static bool fuseOptions4(isc::dhcp::OptionCollection& options);
+
+ /// @brief Parses provided buffer as DHCPv4 options and creates
+ /// Option objects.
+ ///
+ /// Parses provided buffer and stores created Option objects
+ /// in options container.
+ ///
+ /// @param buf Buffer to be parsed.
+ /// @param option_space A name of the option space which holds definitions
+ /// to be used to parse options in the packets.
+ /// @param options Reference to option container. Options will be
+ /// put here.
+ /// @param deferred Reference to an option code list. Options which
+ /// processing is deferred will be put here.
+ /// @param flexible_pad_end Parse options 0 and 255 as PAD and END
+ /// when they are not defined in the option space.
+ /// @return offset to the first byte after the last successfully
+ /// parsed option or the offset of the DHO_END option type.
+ ///
+ /// The unpackOptions6 note applies too.
+ static size_t unpackOptions4(const OptionBuffer& buf,
+ const std::string& option_space,
+ isc::dhcp::OptionCollection& options,
+ std::list<uint16_t>& deferred,
+ bool flexible_pad_end = false);
+
+ /// Registers factory method that produces options of specific option types.
+ ///
+ /// @throw isc::BadValue if provided the type is already registered, has
+ /// too large a value or an invalid universe is specified.
+ ///
+ /// @param u universe of the option (V4 or V6)
+ /// @param type option-type
+ /// @param factory function pointer
+ static void OptionFactoryRegister(Option::Universe u,
+ uint16_t type,
+ Option::Factory * factory);
+
+ /// @brief Returns option definitions for given universe and vendor
+ ///
+ /// @param u option universe
+ /// @param vendor_id enterprise-id of a given vendor
+ ///
+ /// @return a container for a given vendor (or NULL if no option
+ /// definitions are defined)
+ static const OptionDefContainerPtr getVendorOptionDefs(Option::Universe u,
+ const uint32_t vendor_id);
+
+ /// @brief Parses provided buffer as DHCPv6 vendor options and creates
+ /// Option objects.
+ ///
+ /// Parses provided buffer and stores created Option objects
+ /// in options container.
+ ///
+ /// @param vendor_id enterprise-id of the vendor
+ /// @param buf Buffer to be parsed.
+ /// @param options Reference to option container. Suboptions will be
+ /// put here.
+ /// @return offset to the first byte after the last successfully
+ /// parsed suboption
+ ///
+ /// @note unpackVendorOptions6 throws when it fails to parse a suboption
+ /// so the return value is currently always the buffer length.
+ static size_t unpackVendorOptions6(const uint32_t vendor_id,
+ const OptionBuffer& buf,
+ isc::dhcp::OptionCollection& options);
+
+ /// @brief Parses provided buffer as DHCPv4 vendor options and creates
+ /// Option objects.
+ ///
+ /// Parses provided buffer and stores created Option objects
+ /// in options container.
+ ///
+ /// @param vendor_id enterprise-id of the vendor
+ /// @param buf Buffer to be parsed.
+ /// @param options Reference to option container. Suboptions will be
+ /// put here.
+ /// @return offset to the first byte after the last successfully
+ /// parsed suboption
+ ///
+ /// The unpackVendorOptions6 note applies
+ static size_t unpackVendorOptions4(const uint32_t vendor_id,
+ const OptionBuffer& buf,
+ isc::dhcp::OptionCollection& options);
+
+
+ /// @brief Copies option definitions created at runtime.
+ ///
+ /// Copied option definitions will be used as "runtime" option definitions.
+ /// A typical use case is to set option definitions specified by the user
+ /// in the server configuration. These option definitions should be removed
+ /// or replaced with new option definitions upon reconfiguration.
+ ///
+ /// @param defs Const reference to a container holding option definitions
+ /// grouped by option spaces.
+ static void setRuntimeOptionDefs(const OptionDefSpaceContainer& defs);
+
+ /// @brief Removes runtime option definitions.
+ static void clearRuntimeOptionDefs();
+
+ /// @brief Reverts uncommitted changes to runtime option definitions.
+ static void revertRuntimeOptionDefs();
+
+ /// @brief Commits runtime option definitions.
+ static void commitRuntimeOptionDefs();
+
+ /// @brief Converts option space name to vendor id.
+ ///
+ /// If the option space name is specified in the following format:
+ /// "vendor-X" where X is an uint32_t number, it is assumed to be
+ /// a vendor space and the uint32_t number is returned by this function.
+ /// If the option space name is invalid this method will return 0, which
+ /// is not a valid vendor-id, to signal an error.
+ ///
+ /// @todo remove this function once when the conversion is dealt by the
+ /// appropriate functions returning options by option space names.
+ ///
+ /// @param option_space Option space name.
+ /// @return vendor id.
+ static uint32_t optionSpaceToVendorId(const std::string& option_space);
+
+private:
+
+ /// Initialize DHCP option definitions.
+ ///
+ /// The method creates option definitions for all DHCP options.
+ ///
+ /// @throw std::bad alloc if system went out of memory.
+ /// @throw MalformedOptionDefinition if any of the definitions
+ /// are incorrect. This is programming error.
+ static bool initOptionDefs();
+
+ /// flag which indicates initialization state
+ static bool initialized_;
+
+ /// pointers to factories that produce DHCPv6 options
+ static FactoryMap v4factories_;
+
+ /// pointers to factories that produce DHCPv6 options
+ static FactoryMap v6factories_;
+
+ /// Container that holds option definitions for various option spaces.
+ static OptionDefContainers option_defs_;
+
+ /// Container for additional option definitions created in runtime.
+ static util::StagedValue<OptionDefSpaceContainer> runtime_option_defs_;
+};
+
+}
+}
+
+#endif // LIBDHCP_H