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