summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcpsrv/cfg_iface.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib/dhcpsrv/cfg_iface.h509
1 files changed, 509 insertions, 0 deletions
diff --git a/src/lib/dhcpsrv/cfg_iface.h b/src/lib/dhcpsrv/cfg_iface.h
new file mode 100644
index 0000000..2ee8443
--- /dev/null
+++ b/src/lib/dhcpsrv/cfg_iface.h
@@ -0,0 +1,509 @@
+// Copyright (C) 2014-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 CFG_IFACE_H
+#define CFG_IFACE_H
+
+#include <asiolink/io_address.h>
+#include <dhcp/iface_mgr.h>
+#include <util/reconnect_ctl.h>
+#include <cc/cfg_to_element.h>
+#include <cc/user_context.h>
+#include <boost/shared_ptr.hpp>
+#include <map>
+#include <set>
+#include <string>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Exception thrown when duplicated interface names specified.
+class DuplicateIfaceName : public Exception {
+public:
+ DuplicateIfaceName(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
+/// @brief Exception thrown when specified interface name is invalid.
+class InvalidIfaceName : public Exception {
+public:
+ InvalidIfaceName(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
+/// @brief Exception thrown when specified interface doesn't exist in a system.
+class NoSuchIface : public Exception {
+public:
+ NoSuchIface(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
+/// @brief Exception thrown when duplicated address specified.
+class DuplicateAddress : public Exception {
+public:
+ DuplicateAddress(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
+/// @brief Exception thrown when specified unicast address is not assigned
+/// to the interface specified.
+class NoSuchAddress : public Exception {
+public:
+ NoSuchAddress(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
+/// @brief Exception thrown when invalid socket type has been specified
+/// for the given family.
+class InvalidSocketType : public Exception {
+public:
+ InvalidSocketType(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
+/// @brief Represents selection of interfaces for DHCP server.
+///
+/// This class manages selection of interfaces on which the DHCP server is
+/// listening to queries. The interfaces are selected in the server
+/// configuration by their names or by the pairs of interface names and
+/// addresses, e.g. eth0/2001:db8:1::1 (DHCPv6) or e.g. eth0/192.168.8.1
+/// (DHCPv4).
+///
+/// This class also accepts "wildcard" interface name which, if specified,
+/// instructs the server to listen on all available interfaces.
+///
+/// Once interfaces have been specified the sockets (either IPv4 or IPv6)
+/// can be opened by calling @c CfgIface::openSockets function. Kea
+/// offers configuration parameters to control the types of sockets to be
+/// opened by the DHCPv4 server. In small deployments it is requires that
+/// the server can handle messages from the directly connected clients
+/// which don't have an address yet. Unicasting the response to such
+/// client is possible by the use of raw sockets. In larger deployments
+/// it is often the case that whole traffic is received via relays, and
+/// in such case the use of UDP sockets is preferred. The type of the
+/// sockets to be opened is specified using one of the
+/// @c CfgIface::useSocketType method variants. The @c CfgIface::SocketType
+/// enumeration specifies the possible values.
+///
+/// @warning This class makes use of the AF_INET and AF_INET6 family literals,
+/// but it doesn't verify that the address family value passed as @c uint16_t
+/// parameter is equal to one of them. It is a callers responsibility to
+/// guarantee that the address family value is correct.
+///
+/// The interface name is passed as an argument of the @ref CfgIface::use
+/// function which controls the selection of the interface on which the
+/// DHCP queries should be received by the server. The interface name
+/// passed as the argument of this function may appear in one of the following
+/// formats:
+/// - interface-name, e.g. eth0
+/// - interface-name/address, e.g. eth0/2001:db8:1::1 or eth0/192.168.8.1
+///
+/// Extraneous spaces surrounding the interface name and/or address
+/// are accepted. For example: eth0 / 2001:db8:1::1 will be accepted.
+///
+/// When only interface name is specified (without an address) it is allowed
+/// to use the "wildcard" interface name (*) which indicates that the server
+/// should open sockets on all interfaces. When IPv6 is in use, the sockets
+/// will be bound to the link local addresses. Wildcard interface names are
+/// not allowed when specifying a unicast address. For example:
+/// */2001:db8:1::1 is not allowed.
+///
+/// The DHCPv6 configuration accepts simultaneous use of the "interface-name"
+/// and "interface-name/address" tuple for the same interface, e.g.
+/// "eth0", "eth0/2001:db8:1::1" specifies that the server should open a
+/// socket and bind to link local address as well as open a socket bound to
+/// the specified unicast address.
+///
+/// The DHCPv4 configuration doesn't accept the simultaneous use of the
+/// "interface-name" and the "interface-name/address" tuple for the
+/// given interface. When the "interface-name" is specified it implies
+/// that the sockets will be opened on for all addresses configured on
+/// this interface. If the tuple of "interface-name/address" is specified
+/// there will be only one socket opened and bound to the specified address.
+/// This socket will be configured to listen to the broadcast messages
+/// reaching the interface as well as unicast messages sent to the address
+/// to which it is bound. It is allowed to select multiple addresses on the
+/// particular interface explicitly, e.g. "eth0/192.168.8.1",
+/// "eth0/192.168.8.2".
+class CfgIface : public isc::data::UserContext, public isc::data::CfgToElement {
+public:
+
+ /// @brief Socket type used by the DHCPv4 server.
+ enum SocketType {
+ /// Raw socket, used for direct DHCPv4 traffic.
+ SOCKET_RAW,
+ /// Datagram socket, i.e. IP/UDP socket.
+ SOCKET_UDP
+ };
+
+ /// @brief Indicates how outbound interface is selected for relayed traffic.
+ enum OutboundIface {
+ /// Server sends responses over the same interface on which queries are
+ /// received.
+ SAME_AS_INBOUND,
+ /// Server uses routing to determine the right interface to send response.
+ USE_ROUTING
+ };
+
+ /// @brief Keyword used to enable all interfaces.
+ ///
+ /// This keyword can be used instead of the interface name to specify
+ /// that DHCP server should listen on all interfaces.
+ static const char* ALL_IFACES_KEYWORD;
+
+ /// @brief Constructor.
+ CfgIface();
+
+ /// @brief Convenience function which closes all open sockets.
+ /// It stops the receiver thread too.
+ void closeSockets() const;
+
+ /// @brief Compares two @c CfgIface objects for equality.
+ ///
+ /// @param other An object to be compared with this object.
+ ///
+ /// @return true if objects are equal, false otherwise.
+ bool equals(const CfgIface& other) const;
+
+ /// @brief Tries to open sockets on selected interfaces.
+ ///
+ /// This function opens sockets bound to link-local address as well as
+ /// sockets bound to unicast address. See @c CfgIface::use function
+ /// documentation for details how to specify interfaces and unicast
+ /// addresses to bind the sockets to.
+ /// This function starts the family receiver.
+ ///
+ /// @param family Address family (AF_INET or AF_INET6).
+ /// @param port Port number to be used to bind sockets to.
+ /// @param use_bcast A boolean flag which indicates if the broadcast
+ /// traffic should be received through the socket. This parameter is
+ /// ignored for IPv6.
+ void openSockets(const uint16_t family, const uint16_t port,
+ const bool use_bcast = true);
+
+ /// @brief Puts the interface configuration into default state.
+ ///
+ /// This function removes interface names from the set.
+ void reset();
+
+ /// @brief Select interface to be used to receive DHCP traffic.
+ ///
+ /// @ref CfgIface for a detail explanation of the interface name argument.
+ ///
+ /// @param family Address family (AF_INET or AF_INET6).
+ /// @param iface_name Explicit interface name, a wildcard name (*) of
+ /// the interface(s) or the pair of interface/unicast-address to be used
+ /// to receive DHCP traffic.
+ ///
+ /// @throw InvalidIfaceName If the interface name is incorrect, e.g. empty.
+ /// @throw NoSuchIface If the specified interface is not present.
+ /// @throw NoSuchAddress If the specified unicast address is not assigned
+ /// to the interface.
+ /// @throw DuplicateIfaceName If the interface is already selected, i.e.
+ /// @throw IOError when specified unicast address is invalid.
+ /// @c CfgIface::use has been already called for this interface.
+ void use(const uint16_t family, const std::string& iface_name);
+
+ /// @brief Sets the specified socket type to be used by the server.
+ ///
+ /// Supported socket types for DHCPv4 are:
+ /// - @c SOCKET_RAW
+ /// - @c SOCKET_UDP
+ ///
+ /// @param family Address family (AF_INET or AF_INET6).
+ /// @param socket_type Socket type.
+ ///
+ /// @throw InvalidSocketType if the unsupported socket type has been
+ /// specified for the address family. Currently, the socket type
+ /// can only be selected for the AF_INET family.
+ void useSocketType(const uint16_t family, const SocketType& socket_type);
+
+ /// @brief Sets the specified socket type specified in textual format.
+ ///
+ /// The following names of the socket types are currently supported, and
+ /// can be passed in the @c socket_type parameter:
+ /// - raw - for raw sockets,
+ /// - udp - for the IP/UDP datagram sockets,
+ ///
+ /// @param family Address family (AF_INET or AF_INET6)
+ /// @param socket_type_name Socket type in the textual format.
+ ///
+ /// @throw InvalidSocketType if the unsupported socket type has been
+ /// specified for the address family. Currently, the socket type
+ /// can only be selected for the AF_INET family.
+ void useSocketType(const uint16_t family,
+ const std::string& socket_type_name);
+
+ /// @brief Returns DHCP socket type used by the server.
+ SocketType getSocketType() const {
+ return (socket_type_);
+ }
+
+ /// @brief Returns the socket type in the textual format.
+ std::string socketTypeToText() const;
+
+ /// @brief Sets outbound interface selection mode.
+ ///
+ /// @param outbound_iface New outbound interface selection mode setting.
+ void setOutboundIface(const OutboundIface& outbound_iface);
+
+ /// @brief Returns outbound interface selection mode.
+ ///
+ /// @return Outbound interface selection mode.
+ OutboundIface getOutboundIface() const;
+
+ /// @brief Returns outbound interface selection mode as string.
+ ///
+ /// @return text representation of the outbound interface selection mode.
+ std::string outboundTypeToText() const;
+
+ /// @brief Converts text to outbound interface selection mode.
+ ///
+ /// @param txt either 'same-as-inbound' or 'use-routing'
+ /// @return Outbound interface selection mode.
+ static OutboundIface textToOutboundIface(const std::string& txt);
+
+ /// @brief Converts the socket type in the textual format to the type
+ /// represented by the @c SocketType.
+ ///
+ /// @throw InvalidSocketType if the specified value of the @c socket_type_name
+ /// is invalid.
+ SocketType textToSocketType(const std::string& socket_type_name) const;
+
+ /// @brief Equality operator.
+ ///
+ /// @param other Object to be compared with this object.
+ ///
+ /// @return true if objects are equal, false otherwise.
+ bool operator==(const CfgIface& other) const {
+ return (equals(other));
+ }
+
+ /// @brief Inequality operator.
+ ///
+ /// @param other Object to be compared with this object.
+ ///
+ /// @return true if objects are not equal, false otherwise.
+ bool operator!=(const CfgIface& other) const {
+ return (!equals(other));
+ }
+
+ /// @brief Unparse a configuration object
+ ///
+ /// @return a pointer to unparsed configuration
+ virtual isc::data::ElementPtr toElement() const;
+
+ /// @brief Set the re-detect flag
+ ///
+ /// @param re_detect the new value of the flag
+ void setReDetect(bool re_detect) {
+ re_detect_ = re_detect;
+ }
+
+ /// @brief Set flag that Kea must successfully bind all socket services on init.
+ ///
+ /// @param require_all true if all sockets must be bound, false otherwise.
+ void setServiceSocketsRequireAll(bool require_all) {
+ service_socket_require_all_ = require_all;
+ }
+
+ /// @brief Indicates that Kea must successfully bind all socket services on init.
+ ///
+ /// @return true if all sockets must be bound, false otherwise.
+ bool getServiceSocketsRequireAll() const {
+ return (service_socket_require_all_);
+ }
+
+ /// @brief Set the socket service binding retry interval between attempts.
+ ///
+ /// @param interval Milliseconds between attempts.
+ void setServiceSocketsRetryWaitTime(uint32_t interval) {
+ service_sockets_retry_wait_time_ = interval;
+ }
+
+ /// @brief Indicates the socket service binding retry interval between attempts.
+ ///
+ /// @return Milliseconds between attempts.
+ uint32_t getServiceSocketsRetryWaitTime() const {
+ return (service_sockets_retry_wait_time_);
+ }
+
+ /// @brief Set a maximum number of service sockets bind attempts.
+ ///
+ /// @param max_retries Number of attempts. The value 0 disables retries.
+ void setServiceSocketsMaxRetries(uint32_t max_retries) {
+ service_sockets_max_retries_ = max_retries;
+ }
+
+ /// @brief Indicates the maximum number of service sockets bind attempts.
+ ///
+ /// @return Number of attempts.
+ uint32_t getServiceSocketsMaxRetries() const {
+ return (service_sockets_max_retries_);
+ }
+
+ /// @brief Get the reconnect controller.
+ ///
+ /// @return the reconnect controller
+ util::ReconnectCtlPtr getReconnectCtl() const {
+ return (reconnect_ctl_);
+ }
+
+ /// @brief Represents a callback invoked if all retries of the
+ /// opening sockets fail.
+ typedef std::function<void(util::ReconnectCtlPtr)> OpenSocketsFailedCallback;
+
+ /// @brief Optional callback function to invoke if all retries of the
+ /// opening sockets fail.
+ static OpenSocketsFailedCallback open_sockets_failed_callback_;
+
+private:
+
+ /// @brief Checks if multiple IPv4 addresses has been activated on any
+ /// interface.
+ ///
+ /// This method is useful to check if the current configuration uses
+ /// multiple IPv4 addresses on any interface. This is important when
+ /// using raw sockets to receive messages from the clients because
+ /// each packet may be received multiple times when it is sent from
+ /// a directly connected client. If this is the case, a warning must
+ /// be logged.
+ ///
+ /// @return true if multiple addresses are activated on any interface,
+ /// false otherwise.
+ static bool multipleAddressesPerInterfaceActive();
+
+ /// @brief Selects or deselects interfaces.
+ ///
+ /// This function selects all interfaces to receive DHCP traffic or
+ /// deselects all interfaces so as none of them receives a DHCP traffic.
+ ///
+ /// @param family Address family (AF_INET or AF_INET6).
+ /// @param inactive A boolean value which indicates if all interfaces
+ /// (except loopback) should be selected or deselected.
+ /// @param loopback_inactive A boolean value which indicates if loopback
+ /// interface should be selected or deselected.
+ /// should be deselected/inactive (true) or selected/active (false).
+ void setState(const uint16_t family, const bool inactive,
+ const bool loopback_inactive) const;
+
+ /// @brief Selects or deselects addresses on the interface.
+ ///
+ /// This function selects all address on the interface to receive DHCP
+ /// traffic or deselects all addresses so as none of them receives the
+ /// DHCP traffic.
+ ///
+ /// @param family Address family (AF_INET or AF_INET6).
+ /// @param active A boolean value which indicates if all addresses should
+ /// be active (if true), or inactive (if false).
+ /// @param iface An interface on which addresses are selected/deselected.
+ void setIfaceAddrsState(const uint16_t family, const bool active,
+ Iface& iface) const;
+
+ /// @brief Error handler for executed when opening a socket fail.
+ ///
+ /// A pointer to this function is passed to the @c IfaceMgr::openSockets4
+ /// or @c IfaceMgr::openSockets6. These functions call this handler when
+ /// they fail to open a socket. The handler logs an error passed in the
+ /// parameter.
+ ///
+ /// @param errmsg Error message being logged by the function.
+ static void socketOpenErrorHandler(const std::string& errmsg);
+
+ /// @brief Calls a family-specific function to open sockets.
+ ///
+ /// It is a static function for a safe call from a CfgIface instance or a
+ /// timer handler.
+ ///
+ /// @param family Address family (AF_INET or AF_INET6).
+ /// @param port Port number to be used to bind sockets to.
+ /// @param can_use_bcast A boolean flag which indicates if the broadcast
+ /// traffic should be received through the socket and the raw sockets are
+ /// used. For the UDP sockets, we only handle the relayed (unicast)
+ /// traffic. This parameter is ignored for IPv6.
+ /// @param skip_opened Omits the already opened sockets (doesn't try to
+ /// re-bind).
+ /// @return Pair of boolean flags. The first boolean is true if at least
+ /// one socket is successfully opened, and the second is true if no errors
+ /// occur.
+ static std::pair<bool, bool> openSocketsForFamily(const uint16_t family,
+ const uint16_t port,
+ const bool can_use_bcast,
+ const bool skip_opened);
+
+ /// @brief Creates a ReconnectCtl based on the configuration's
+ /// retry parameters.
+ ///
+ /// @return The reconnect control created using the configuration
+ /// parameters.
+ util::ReconnectCtlPtr makeReconnectCtl() const;
+
+ /// Calls the @c CfgIface::openSocketsForFamily function and retry it if
+ /// socket opening fails.
+ ///
+ /// @param reconnect_ctl Used to manage socket reconnection.
+ /// @param family Address family (AF_INET or AF_INET6).
+ /// @param port Port number to be used to bind sockets to.
+ /// @param can_use_bcast A boolean flag which indicates if the broadcast
+ /// traffic should be received through the socket and the raw sockets are
+ /// used. For the UDP sockets, we only handle the relayed (unicast)
+ /// traffic. This parameter is ignored for IPv6.
+ ///
+ /// @return True if at least one socket opened successfully.
+ static bool openSocketsWithRetry(util::ReconnectCtlPtr reconnect_ctl,
+ const uint16_t family, const uint16_t port,
+ const bool can_use_bcast);
+
+ /// @brief Represents a set of interface names.
+ typedef std::set<std::string> IfaceSet;
+
+ /// @brief A set of interface names specified by the user.
+ IfaceSet iface_set_;
+
+ /// @brief A map of interfaces and addresses to which the server
+ /// should bind sockets.
+ typedef std::multimap<std::string, asiolink::IOAddress> ExplicitAddressMap;
+
+ /// @brief A map which holds the pairs of interface names and addresses
+ /// for which the sockets should be opened.
+ ExplicitAddressMap address_map_;
+
+ /// @brief A boolean value which indicates that the wildcard interface name
+ /// has been specified (*).
+ bool wildcard_used_;
+
+ /// @brief A type of the sockets used by the DHCP server.
+ SocketType socket_type_;
+
+ /// @brief A boolean value which reflects current re-detect setting
+ bool re_detect_;
+
+ /// @brief A boolean value indicates that Kea must successfully bind all socket services on init
+ bool service_socket_require_all_;
+
+ /// @brief An interval between attempts to retry the socket service binding.
+ uint32_t service_sockets_retry_wait_time_;
+
+ /// @brief A maximum number of attempts to bind the service sockets.
+ uint32_t service_sockets_max_retries_;
+
+ /// @brief Indicates how outbound interface is selected for relayed traffic.
+ OutboundIface outbound_iface_;
+
+ /// @brief Used to manage socket reconnection.
+ util::ReconnectCtlPtr reconnect_ctl_;
+};
+
+/// @brief A pointer to the @c CfgIface .
+typedef boost::shared_ptr<CfgIface> CfgIfacePtr;
+
+/// @brief A pointer to the const @c CfgIface.
+typedef boost::shared_ptr<const CfgIface> ConstCfgIfacePtr;
+
+}
+}
+
+#endif // CFG_IFACE_H