%PDF- %PDF-
| Direktori : /proc/thread-self/root/backups/router/usr/local/include/kea/dhcpsrv/ |
| Current File : //proc/thread-self/root/backups/router/usr/local/include/kea/dhcpsrv/cfg_iface.h |
// 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