1 // Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC") 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, v. 2.0. If a copy of the MPL was not distributed with this 5 // file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 7 #ifndef CFG_IFACE_H 8 #define CFG_IFACE_H 9 10 #include <asiolink/io_address.h> 11 #include <dhcp/iface_mgr.h> 12 #include <cc/cfg_to_element.h> 13 #include <cc/user_context.h> 14 #include <boost/shared_ptr.hpp> 15 #include <map> 16 #include <set> 17 #include <string> 18 19 namespace isc { 20 namespace dhcp { 21 22 /// @brief Exception thrown when duplicated interface names specified. 23 class DuplicateIfaceName : public Exception { 24 public: DuplicateIfaceName(const char * file,size_t line,const char * what)25 DuplicateIfaceName(const char* file, size_t line, const char* what) : 26 isc::Exception(file, line, what) { }; 27 }; 28 29 /// @brief Exception thrown when specified interface name is invalid. 30 class InvalidIfaceName : public Exception { 31 public: InvalidIfaceName(const char * file,size_t line,const char * what)32 InvalidIfaceName(const char* file, size_t line, const char* what) : 33 isc::Exception(file, line, what) { }; 34 }; 35 36 /// @brief Exception thrown when specified interface doesn't exist in a system. 37 class NoSuchIface : public Exception { 38 public: NoSuchIface(const char * file,size_t line,const char * what)39 NoSuchIface(const char* file, size_t line, const char* what) : 40 isc::Exception(file, line, what) { }; 41 }; 42 43 /// @brief Exception thrown when duplicated address specified. 44 class DuplicateAddress : public Exception { 45 public: DuplicateAddress(const char * file,size_t line,const char * what)46 DuplicateAddress(const char* file, size_t line, const char* what) : 47 isc::Exception(file, line, what) { }; 48 }; 49 50 /// @brief Exception thrown when specified unicast address is not assigned 51 /// to the interface specified. 52 class NoSuchAddress : public Exception { 53 public: NoSuchAddress(const char * file,size_t line,const char * what)54 NoSuchAddress(const char* file, size_t line, const char* what) : 55 isc::Exception(file, line, what) { }; 56 }; 57 58 /// @brief Exception thrown when invalid socket type has been specified 59 /// for the given family. 60 class InvalidSocketType : public Exception { 61 public: InvalidSocketType(const char * file,size_t line,const char * what)62 InvalidSocketType(const char* file, size_t line, const char* what) : 63 isc::Exception(file, line, what) { }; 64 }; 65 66 /// @brief Represents selection of interfaces for DHCP server. 67 /// 68 /// This class manages selection of interfaces on which the DHCP server is 69 /// listening to queries. The interfaces are selected in the server 70 /// configuration by their names or by the pairs of interface names and 71 /// addresses, e.g. eth0/2001:db8:1::1 (DHCPv6) or e.g. eth0/192.168.8.1 72 /// (DHCPv4). 73 /// 74 /// This class also accepts "wildcard" interface name which, if specified, 75 /// instructs the server to listen on all available interfaces. 76 /// 77 /// Once interfaces have been specified the sockets (either IPv4 or IPv6) 78 /// can be opened by calling @c CfgIface::openSockets function. Kea 79 /// offers configuration parameters to control the types of sockets to be 80 /// opened by the DHCPv4 server. In small deployments it is requires that 81 /// the server can handle messages from the directly connected clients 82 /// which don't have an address yet. Unicasting the response to such 83 /// client is possible by the use of raw sockets. In larger deployments 84 /// it is often the case that whole traffic is received via relays, and 85 /// in such case the use of UDP sockets is preferred. The type of the 86 /// sockets to be opened is specified using one of the 87 /// @c CfgIface::useSocketType method variants. The @c CfgIface::SocketType 88 /// enumeration specifies the possible values. 89 /// 90 /// @warning This class makes use of the AF_INET and AF_INET6 family literals, 91 /// but it doesn't verify that the address family value passed as @c uint16_t 92 /// parameter is equal to one of them. It is a callers responsibility to 93 /// guarantee that the address family value is correct. 94 /// 95 /// The interface name is passed as an argument of the @ref CfgIface::use 96 /// function which controls the selection of the interface on which the 97 /// DHCP queries should be received by the server. The interface name 98 /// passed as the argument of this function may appear in one of the following 99 /// formats: 100 /// - interface-name, e.g. eth0 101 /// - interface-name/address, e.g. eth0/2001:db8:1::1 or eth0/192.168.8.1 102 /// 103 /// Extraneous spaces surrounding the interface name and/or address 104 /// are accepted. For example: eth0 / 2001:db8:1::1 will be accepted. 105 /// 106 /// When only interface name is specified (without an address) it is allowed 107 /// to use the "wildcard" interface name (*) which indicates that the server 108 /// should open sockets on all interfaces. When IPv6 is in use, the sockets 109 /// will be bound to the link local addresses. Wildcard interface names are 110 /// not allowed when specifying a unicast address. For example: 111 /// */2001:db8:1::1 is not allowed. 112 /// 113 /// The DHCPv6 configuration accepts simultaneous use of the "interface-name" 114 /// and "interface-name/address" tuple for the same interface, e.g. 115 /// "eth0", "eth0/2001:db8:1::1" specifies that the server should open a 116 /// socket and bind to link local address as well as open a socket bound to 117 /// the specified unicast address. 118 /// 119 /// The DHCPv4 configuration doesn't accept the simultaneous use of the 120 /// "interface-name" and the "interface-name/address" tuple for the 121 /// given interface. When the "interface-name" is specified it implies 122 /// that the sockets will be opened on for all addresses configured on 123 /// this interface. If the tuple of "interface-name/address" is specified 124 /// there will be only one socket opened and bound to the specified address. 125 /// This socket will be configured to listen to the broadcast messages 126 /// reaching the interface as well as unicast messages sent to the address 127 /// to which it is bound. It is allowed to select multiple addresses on the 128 /// particular interface explicitly, e.g. "eth0/192.168.8.1", 129 /// "eth0/192.168.8.2". 130 class CfgIface : public isc::data::UserContext, public isc::data::CfgToElement { 131 public: 132 133 /// @brief Socket type used by the DHCPv4 server. 134 enum SocketType { 135 /// Raw socket, used for direct DHCPv4 traffic. 136 SOCKET_RAW, 137 /// Datagram socket, i.e. IP/UDP socket. 138 SOCKET_UDP 139 }; 140 141 /// @brief Indicates how outbound interface is selected for relayed traffic. 142 enum OutboundIface { 143 /// Server sends responses over the same interface on which queries are 144 /// received. 145 SAME_AS_INBOUND, 146 /// Server uses routing to determine the right interface to send response. 147 USE_ROUTING 148 }; 149 150 /// @brief Keyword used to enable all interfaces. 151 /// 152 /// This keyword can be used instead of the interface name to specify 153 /// that DHCP server should listen on all interfaces. 154 static const char* ALL_IFACES_KEYWORD; 155 156 /// @brief Constructor. 157 CfgIface(); 158 159 /// @brief Convenience function which closes all open sockets. 160 /// It stops the receiver thread too. 161 void closeSockets() const; 162 163 /// @brief Compares two @c CfgIface objects for equality. 164 /// 165 /// @param other An object to be compared with this object. 166 /// 167 /// @return true if objects are equal, false otherwise. 168 bool equals(const CfgIface& other) const; 169 170 /// @brief Tries to open sockets on selected interfaces. 171 /// 172 /// This function opens sockets bound to link-local address as well as 173 /// sockets bound to unicast address. See @c CfgIface::use function 174 /// documentation for details how to specify interfaces and unicast 175 /// addresses to bind the sockets to. 176 /// This function starts the family receiver. 177 /// 178 /// @param family Address family (AF_INET or AF_INET6). 179 /// @param port Port number to be used to bind sockets to. 180 /// @param use_bcast A boolean flag which indicates if the broadcast 181 /// traffic should be received through the socket. This parameter is 182 /// ignored for IPv6. 183 void openSockets(const uint16_t family, const uint16_t port, 184 const bool use_bcast = true) const; 185 186 /// @brief Puts the interface configuration into default state. 187 /// 188 /// This function removes interface names from the set. 189 void reset(); 190 191 /// @brief Select interface to be used to receive DHCP traffic. 192 /// 193 /// @ref CfgIface for a detail explanation of the interface name argument. 194 /// 195 /// @param family Address family (AF_INET or AF_INET6). 196 /// @param iface_name Explicit interface name, a wildcard name (*) of 197 /// the interface(s) or the pair of interface/unicast-address to be used 198 /// to receive DHCP traffic. 199 /// 200 /// @throw InvalidIfaceName If the interface name is incorrect, e.g. empty. 201 /// @throw NoSuchIface If the specified interface is not present. 202 /// @throw NoSuchAddress If the specified unicast address is not assigned 203 /// to the interface. 204 /// @throw DuplicateIfaceName If the interface is already selected, i.e. 205 /// @throw IOError when specified unicast address is invalid. 206 /// @c CfgIface::use has been already called for this interface. 207 void use(const uint16_t family, const std::string& iface_name); 208 209 /// @brief Sets the specified socket type to be used by the server. 210 /// 211 /// Supported socket types for DHCPv4 are: 212 /// - @c SOCKET_RAW 213 /// - @c SOCKET_UDP 214 /// 215 /// @param family Address family (AF_INET or AF_INET6). 216 /// @param socket_type Socket type. 217 /// 218 /// @throw InvalidSocketType if the unsupported socket type has been 219 /// specified for the address family. Currently, the socket type 220 /// can only be selected for the AF_INET family. 221 void useSocketType(const uint16_t family, const SocketType& socket_type); 222 223 /// @brief Sets the specified socket type specified in textual format. 224 /// 225 /// The following names of the socket types are currently supported, and 226 /// can be passed in the @c socket_type parameter: 227 /// - raw - for raw sockets, 228 /// - udp - for the IP/UDP datagram sockets, 229 /// 230 /// @param family Address family (AF_INET or AF_INET6) 231 /// @param socket_type_name Socket type in the textual format. 232 /// 233 /// @throw InvalidSocketType if the unsupported socket type has been 234 /// specified for the address family. Currently, the socket type 235 /// can only be selected for the AF_INET family. 236 void useSocketType(const uint16_t family, 237 const std::string& socket_type_name); 238 239 /// @brief Returns DHCP socket type used by the server. getSocketType()240 SocketType getSocketType() const { 241 return (socket_type_); 242 } 243 244 /// @brief Returns the socket type in the textual format. 245 std::string socketTypeToText() const; 246 247 /// @brief Sets outbound interface selection mode. 248 /// 249 /// @param outbound_iface New outbound interface selection mode setting. 250 void setOutboundIface(const OutboundIface& outbound_iface); 251 252 /// @brief Returns outbound interface selection mode. 253 /// 254 /// @return Outbound interface selection mode. 255 OutboundIface getOutboundIface() const; 256 257 /// @brief Returns outbound interface selection mode as string. 258 /// 259 /// @return text representation of the outbound interface selection mode. 260 std::string outboundTypeToText() const; 261 262 /// @brief Converts text to outbound interface selection mode. 263 /// 264 /// @param txt either 'same-as-inbound' or 'use-routing' 265 /// @return Outbound interface selection mode. 266 static OutboundIface textToOutboundIface(const std::string& txt); 267 268 /// @brief Converts the socket type in the textual format to the type 269 /// represented by the @c SocketType. 270 /// 271 /// @throw InvalidSocketType if the specified value of the @c socket_type_name 272 /// is invalid. 273 SocketType textToSocketType(const std::string& socket_type_name) const; 274 275 /// @brief Equality operator. 276 /// 277 /// @param other Object to be compared with this object. 278 /// 279 /// @return true if objects are equal, false otherwise. 280 bool operator==(const CfgIface& other) const { 281 return (equals(other)); 282 } 283 284 /// @brief Inequality operator. 285 /// 286 /// @param other Object to be compared with this object. 287 /// 288 /// @return true if objects are not equal, false otherwise. 289 bool operator!=(const CfgIface& other) const { 290 return (!equals(other)); 291 } 292 293 /// @brief Unparse a configuration object 294 /// 295 /// @return a pointer to unparsed configuration 296 virtual isc::data::ElementPtr toElement() const; 297 298 /// @brief Set the re-detect flag 299 /// 300 /// @param re_detect the new value of the flag setReDetect(bool re_detect)301 void setReDetect(bool re_detect) { 302 re_detect_ = re_detect; 303 } 304 305 private: 306 307 /// @brief Checks if multiple IPv4 addresses has been activated on any 308 /// interface. 309 /// 310 /// This method is useful to check if the current configuration uses 311 /// multiple IPv4 addresses on any interface. This is important when 312 /// using raw sockets to receive messages from the clients because 313 /// each packet may be received multiple times when it is sent from 314 /// a directly connected client. If this is the case, a warning must 315 /// be logged. 316 /// 317 /// @return true if multiple addresses are activated on any interface, 318 /// false otherwise. 319 bool multipleAddressesPerInterfaceActive() const; 320 321 /// @brief Selects or deselects interfaces. 322 /// 323 /// This function selects all interfaces to receive DHCP traffic or 324 /// deselects all interfaces so as none of them receives a DHCP traffic. 325 /// 326 /// @param family Address family (AF_INET or AF_INET6). 327 /// @param inactive A boolean value which indicates if all interfaces 328 /// (except loopback) should be selected or deselected. 329 /// @param loopback_inactive A boolean value which indicates if loopback 330 /// interface should be selected or deselected. 331 /// should be deselected/inactive (true) or selected/active (false). 332 void setState(const uint16_t family, const bool inactive, 333 const bool loopback_inactive) const; 334 335 /// @brief Selects or deselects addresses on the interface. 336 /// 337 /// This function selects all address on the interface to receive DHCP 338 /// traffic or deselects all addresses so as none of them receives the 339 /// DHCP traffic. 340 /// 341 /// @param family Address family (AF_INET or AF_INET6). 342 /// @param active A boolean value which indicates if all addresses should 343 /// be active (if true), or inactive (if false). 344 /// @param iface An interface on which addresses are selected/deselected. 345 void setIfaceAddrsState(const uint16_t family, const bool active, 346 Iface& iface) const; 347 348 /// @brief Error handler for executed when opening a socket fail. 349 /// 350 /// A pointer to this function is passed to the @c IfaceMgr::openSockets4 351 /// or @c IfaceMgr::openSockets6. These functions call this handler when 352 /// they fail to open a socket. The handler logs an error passed in the 353 /// parameter. 354 /// 355 /// @param errmsg Error message being logged by the function. 356 static void socketOpenErrorHandler(const std::string& errmsg); 357 358 /// @brief Represents a set of interface names. 359 typedef std::set<std::string> IfaceSet; 360 361 /// @brief A set of interface names specified by the user. 362 IfaceSet iface_set_; 363 364 /// @brief A map of interfaces and addresses to which the server 365 /// should bind sockets. 366 typedef std::multimap<std::string, asiolink::IOAddress> ExplicitAddressMap; 367 368 /// @brief A map which holds the pairs of interface names and addresses 369 /// for which the sockets should be opened. 370 ExplicitAddressMap address_map_; 371 372 /// @brief A boolean value which indicates that the wildcard interface name 373 /// has been specified (*). 374 bool wildcard_used_; 375 376 /// @brief A type of the sockets used by the DHCP server. 377 SocketType socket_type_; 378 379 /// @brief A boolean value which reflects current re-detect setting 380 bool re_detect_; 381 382 /// @brief Indicates how outbound interface is selected for relayed traffic. 383 OutboundIface outbound_iface_; 384 }; 385 386 /// @brief A pointer to the @c CfgIface . 387 typedef boost::shared_ptr<CfgIface> CfgIfacePtr; 388 389 /// @brief A pointer to the const @c CfgIface. 390 typedef boost::shared_ptr<const CfgIface> ConstCfgIfacePtr; 391 392 } 393 } 394 395 #endif // CFG_IFACE_H 396