1 // Copyright (C) 2011-2021 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 IFACE_MGR_H
8 #define IFACE_MGR_H
9 
10 #include <asiolink/io_address.h>
11 #include <dhcp/dhcp4.h>
12 #include <dhcp/dhcp6.h>
13 #include <dhcp/pkt4.h>
14 #include <dhcp/pkt6.h>
15 #include <dhcp/packet_queue_mgr4.h>
16 #include <dhcp/packet_queue_mgr6.h>
17 #include <dhcp/pkt_filter.h>
18 #include <dhcp/pkt_filter6.h>
19 #include <util/optional.h>
20 #include <util/watch_socket.h>
21 #include <util/watched_thread.h>
22 
23 #include <boost/multi_index/hashed_index.hpp>
24 #include <boost/multi_index/mem_fun.hpp>
25 #include <boost/multi_index/sequenced_index.hpp>
26 #include <boost/multi_index_container.hpp>
27 #include <boost/noncopyable.hpp>
28 #include <boost/scoped_array.hpp>
29 #include <boost/shared_ptr.hpp>
30 
31 #include <functional>
32 #include <list>
33 #include <vector>
34 #include <mutex>
35 
36 namespace isc {
37 
38 namespace dhcp {
39 
40 /// @brief IfaceMgr exception thrown thrown when interface detection fails.
41 class IfaceDetectError : public Exception {
42 public:
IfaceDetectError(const char * file,size_t line,const char * what)43     IfaceDetectError(const char* file, size_t line, const char* what) :
44         isc::Exception(file, line, what) { };
45 };
46 
47 /// @brief Exception thrown when it is not allowed to set new Packet Filter.
48 class PacketFilterChangeDenied : public Exception {
49 public:
PacketFilterChangeDenied(const char * file,size_t line,const char * what)50     PacketFilterChangeDenied(const char* file, size_t line, const char* what) :
51         isc::Exception(file, line, what) { };
52 };
53 
54 /// @brief Exception thrown when a call to select is interrupted by a signal.
55 class SignalInterruptOnSelect : public Exception {
56 public:
SignalInterruptOnSelect(const char * file,size_t line,const char * what)57     SignalInterruptOnSelect(const char* file, size_t line, const char* what) :
58         isc::Exception(file, line, what) { };
59 };
60 
61 /// @brief IfaceMgr exception thrown thrown when socket opening
62 /// or configuration failed.
63 class SocketConfigError : public Exception {
64 public:
SocketConfigError(const char * file,size_t line,const char * what)65     SocketConfigError(const char* file, size_t line, const char* what) :
66         isc::Exception(file, line, what) { };
67 };
68 
69 /// @brief IfaceMgr exception thrown thrown when error occurred during
70 /// reading data from socket.
71 class SocketReadError : public Exception {
72 public:
SocketReadError(const char * file,size_t line,const char * what)73     SocketReadError(const char* file, size_t line, const char* what) :
74         isc::Exception(file, line, what) { };
75 };
76 
77 /// @brief IfaceMgr exception thrown thrown when error occurred during
78 /// sending data through socket.
79 class SocketWriteError : public Exception {
80 public:
SocketWriteError(const char * file,size_t line,const char * what)81     SocketWriteError(const char* file, size_t line, const char* what) :
82         isc::Exception(file, line, what) { };
83 };
84 
85 /// @brief IfaceMgr exception thrown when there is no suitable interface.
86 class IfaceNotFound : public Exception {
87 public:
IfaceNotFound(const char * file,size_t line,const char * what)88     IfaceNotFound(const char* file, size_t line, const char* what) :
89         isc::Exception(file, line, what) { };
90 };
91 
92 /// @brief IfaceMgr exception thrown when there is no suitable socket found.
93 class SocketNotFound : public Exception {
94 public:
SocketNotFound(const char * file,size_t line,const char * what)95     SocketNotFound(const char* file, size_t line, const char* what) :
96         isc::Exception(file, line, what) { };
97 };
98 
99 /// @brief Represents a single network interface
100 ///
101 /// Iface structure represents network interface with all useful
102 /// information, like name, interface index, MAC address and
103 /// list of assigned addresses
104 ///
105 /// This class also holds the pointer to the socket read buffer.
106 /// Functions reading from the socket may utilize this buffer to store the
107 /// data being read from the socket. The advantage of using the
108 /// pre-allocated buffer is that the buffer is allocated only once, rather
109 /// than on every read. In addition, some OS specific code (e.g. BPF)
110 /// may require use of fixed-size buffers. The size of such a buffer is
111 /// returned by the OS kernel when the socket is opened. Hence, it is
112 /// convenient to allocate the buffer when the socket is being opened and
113 /// utilize it throughout the lifetime of the socket.
114 ///
115 /// In order to avoid potentially expensive copies of the @c Iface objects
116 /// holding pre-allocated buffers and multiple containers, this class is
117 /// noncopyable.
118 class Iface : public boost::noncopyable {
119 public:
120 
121     /// Maximum MAC address length (Infiniband uses 20 bytes)
122     static const unsigned int MAX_MAC_LEN = 20;
123 
124     /// @brief Address type.
125     typedef util::Optional<asiolink::IOAddress> Address;
126 
127     /// Type that defines list of addresses
128     typedef std::list<Address> AddressCollection;
129 
130     /// @brief Type that holds a list of socket information.
131     ///
132     /// @warning The type of the container used here must guarantee
133     /// that the iterators do not invalidate when erase() is called.
134     /// This is because, the \ref closeSockets function removes
135     /// elements selectively by calling erase on the element to be
136     /// removed and further iterates through remaining elements.
137     ///
138     /// @todo: Add SocketCollectionConstIter type
139     typedef std::list<SocketInfo> SocketCollection;
140 
141     /// @brief Iface constructor.
142     ///
143     /// Creates Iface object that represents network interface.
144     ///
145     /// @param name name of the interface
146     /// @param ifindex interface index (unique integer identifier)
147     /// @throw BadValue when name is empty.
148     Iface(const std::string& name, unsigned int ifindex);
149 
150     /// @brief Destructor.
~Iface()151     ~Iface() { }
152 
153     /// @brief Closes all open sockets on interface.
154     void closeSockets();
155 
156     /// @brief Closes all IPv4 or IPv6 sockets.
157     ///
158     /// This function closes sockets of the specific 'type' and closes them.
159     /// The 'type' of the socket indicates whether it is used to send IPv4
160     /// or IPv6 packets. The allowed values of the parameter are AF_INET and
161     /// AF_INET6 for IPv4 and IPv6 packets respectively. It is important
162     /// to realize that the actual types of sockets may be different than
163     /// AF_INET for IPv4 packets. This is because, historically the IfaceMgr
164     /// always used AF_INET sockets for IPv4 traffic. This is no longer the
165     /// case when the Direct IPv4 traffic must be supported. In order to support
166     /// direct traffic, the IfaceMgr operates on raw sockets, e.g. AF_PACKET
167     /// family sockets on Linux.
168     ///
169     /// @todo Replace the AF_INET and AF_INET6 values with an enum
170     /// which will not be confused with the actual socket type.
171     ///
172     /// @param family type of the sockets to be closed (AF_INET or AF_INET6)
173     ///
174     /// @throw BadValue if family value is different than AF_INET or AF_INET6.
175     void closeSockets(const uint16_t family);
176 
177     /// @brief Returns full interface name as "ifname/ifindex" string.
178     ///
179     /// @return string with interface name
180     std::string getFullName() const;
181 
182     /// @brief Returns link-layer address a plain text.
183     ///
184     /// @return MAC address as a plain text (string)
185     std::string getPlainMac() const;
186 
187     /// @brief Sets MAC address of the interface.
188     ///
189     /// @param mac pointer to MAC address buffer
190     /// @param macLen length of mac address
191     void setMac(const uint8_t* mac, size_t macLen);
192 
193     /// @brief Returns MAC length.
194     ///
195     /// @return length of MAC address
getMacLen()196     size_t getMacLen() const { return mac_len_; }
197 
198     /// @brief Returns pointer to MAC address.
199     ///
200     /// Note: Returned pointer is only valid as long as the interface object
201     /// that returned it.
getMac()202     const uint8_t* getMac() const { return mac_; }
203 
204     /// @brief Sets flag_*_ fields based on bitmask value returned by OS
205     ///
206     /// @note Implementation of this method is OS-dependent as bits have
207     /// different meaning on each OS.
208     /// We need to make it 64 bits, because Solaris uses 64, not 32 bits.
209     ///
210     /// @param flags bitmask value returned by OS in interface detection
211     void setFlags(uint64_t flags);
212 
213     /// @brief Returns interface index.
214     ///
215     /// @return interface index
getIndex()216     int getIndex() const { return ifindex_; }
217 
218     /// @brief Returns interface name.
219     ///
220     /// @return interface name
getName()221     std::string getName() const { return name_; };
222 
223     /// @brief Sets up hardware type of the interface.
224     ///
225     /// @param type hardware type
setHWType(uint16_t type)226     void setHWType(uint16_t type ) { hardware_type_ = type; }
227 
228     /// @brief Returns hardware type of the interface.
229     ///
230     /// @return hardware type
getHWType()231     uint16_t getHWType() const { return hardware_type_; }
232 
233     /// @brief Returns all addresses available on an interface.
234     ///
235     /// The returned addresses are encapsulated in the @c util::Optional
236     /// class to be able to selectively flag some of the addresses as active
237     /// (when optional value is specified) or inactive (when optional value
238     /// is specified). If the address is marked as active, the
239     /// @c IfaceMgr::openSockets4 method will open socket and bind to this
240     /// address. Otherwise, it will not bind any socket to this address.
241     /// This is useful when an interface has multiple IPv4 addresses assigned.
242     ///
243     /// Care should be taken to not use this collection after Iface object
244     /// ceases to exist. That is easy in most cases as Iface objects are
245     /// created by IfaceMgr that is a singleton an is expected to be
246     /// available at all time. We may revisit this if we ever decide to
247     /// implement dynamic interface detection, but such fancy feature would
248     /// mostly be useful for clients with wifi/vpn/virtual interfaces.
249     ///
250     /// @return collection of addresses
getAddresses()251     const AddressCollection& getAddresses() const { return addrs_; }
252 
253     /// @brief Returns IPv4 address assigned to the interface.
254     ///
255     /// This function looks for an IPv4 address assigned to the interface
256     /// and returns it through the argument.
257     ///
258     /// @param [out] address IPv4 address assigned to the interface.
259     ///
260     /// @return Boolean value which informs whether IPv4 address has been found
261     /// for the interface (if true), or not (false).
262     bool getAddress4(isc::asiolink::IOAddress& address) const;
263 
264     /// @brief Check if the interface has the specified address assigned.
265     ///
266     /// @param address Address to be checked.
267     /// @return true if address is assigned to the interface, false otherwise.
268     bool hasAddress(const isc::asiolink::IOAddress& address) const;
269 
270     /// @brief Adds an address to an interface.
271     ///
272     /// This only adds an address to collection, it does not physically
273     /// configure address on actual network interface.
274     ///
275     /// @param addr address to be added
276     void addAddress(const isc::asiolink::IOAddress& addr);
277 
278     /// @brief Activates or deactivates address for the interface.
279     ///
280     /// This method marks a specified address on the interface active or
281     /// inactive. If the address is marked inactive, the
282     /// @c IfaceMgr::openSockets4 method will NOT open socket for this address.
283     ///
284     /// @param address An address which should be activated, deactivated.
285     /// @param active A boolean flag which indicates that the specified address
286     /// should be active (if true) or inactive (if false).
287     ///
288     /// @throw BadValue if specified address doesn't exist for the interface.
289     void setActive(const isc::asiolink::IOAddress& address, const bool active);
290 
291     /// @brief Activates or deactivates all addresses for the interface.
292     ///
293     /// This method marks all addresses on the interface active or inactive.
294     /// If the address is marked inactive, the @c IfaceMgr::openSockets4
295     /// method will NOT open socket for this address.
296     ///
297     /// @param active A boolean flag which indicates that the addresses
298     /// should be active (if true) or inactive (if false).
299     void setActive(const bool active);
300 
301     /// @brief Returns a number of activated IPv4 addresses on the interface.
302     unsigned int countActive4() const;
303 
304     /// @brief Deletes an address from an interface.
305     ///
306     /// This only deletes address from collection, it does not physically
307     /// remove address configuration from actual network interface.
308     ///
309     /// @param addr address to be removed.
310     ///
311     /// @return true if removal was successful (address was in collection),
312     ///         false otherwise
313     bool delAddress(const isc::asiolink::IOAddress& addr);
314 
315     /// @brief Adds socket descriptor to an interface.
316     ///
317     /// @param sock SocketInfo structure that describes socket.
addSocket(const SocketInfo & sock)318     void addSocket(const SocketInfo& sock) {
319         sockets_.push_back(sock);
320     }
321 
322     /// @brief Closes socket.
323     ///
324     /// Closes socket and removes corresponding SocketInfo structure
325     /// from an interface.
326     ///
327     /// @param sockfd socket descriptor to be closed/removed.
328     /// @return true if there was such socket, false otherwise
329     bool delSocket(uint16_t sockfd);
330 
331     /// @brief Returns collection of all sockets added to interface.
332     ///
333     /// When new socket is created with @ref IfaceMgr::openSocket
334     /// it is added to sockets collection on particular interface.
335     /// If socket is opened by other means (e.g. function that does
336     /// not use @ref IfaceMgr::openSocket) it will not be available
337     /// in this collection. Note that functions like
338     /// @ref IfaceMgr::openSocketFromIface use
339     /// @ref IfaceMgr::openSocket internally.
340     /// The returned reference is only valid during the lifetime of
341     /// the IfaceMgr object that returned it.
342     ///
343     /// @return collection of sockets added to interface
getSockets()344     const SocketCollection& getSockets() const { return sockets_; }
345 
346     /// @brief Removes any unicast addresses
347     ///
348     /// Removes any unicast addresses that the server was configured to
349     /// listen on
clearUnicasts()350     void clearUnicasts() {
351         unicasts_.clear();
352     }
353 
354     /// @brief Adds unicast the server should listen on
355     ///
356     /// @throw BadValue if specified address is already defined on interface
357     /// @param addr unicast address to listen on
358     void addUnicast(const isc::asiolink::IOAddress& addr);
359 
360     /// @brief Returns a container of addresses the server should listen on
361     ///
362     /// @return address collection (may be empty)
getUnicasts()363     const AddressCollection& getUnicasts() const {
364         return unicasts_;
365     }
366 
367     /// @brief Returns the pointer to the buffer used for data reading.
368     ///
369     /// The returned pointer is only valid during the lifetime of the
370     /// object which returns it or until the buffer is resized.
371     /// This function is meant to be used with socket API to gather
372     /// data from the socket.
373     ///
374     /// @return Pointer to the first element of the read buffer or
375     /// NULL if the buffer is empty.
getReadBuffer()376     uint8_t* getReadBuffer() {
377         if (read_buffer_.empty()) {
378             return (0);
379         }
380         return (&read_buffer_[0]);
381     }
382 
383     /// @brief Returns the current size of the socket read buffer.
getReadBufferSize()384     size_t getReadBufferSize() const {
385         return (read_buffer_.size());
386     }
387 
388     /// @brief Reallocates the socket read buffer.
389     ///
390     /// @param new_size New size of the buffer.
resizeReadBuffer(const size_t new_size)391     void resizeReadBuffer(const size_t new_size) {
392         read_buffer_.resize(new_size);
393     }
394 
395 protected:
396     /// Socket used to send data.
397     SocketCollection sockets_;
398 
399     /// Network interface name.
400     std::string name_;
401 
402     /// Interface index (a value that uniquely identifies an interface).
403     int ifindex_;
404 
405     /// List of assigned addresses.
406     AddressCollection addrs_;
407 
408     /// List of unicast addresses the server should listen on
409     AddressCollection unicasts_;
410 
411     /// Link-layer address.
412     uint8_t mac_[MAX_MAC_LEN];
413 
414     /// Length of link-layer address (usually 6).
415     size_t mac_len_;
416 
417     /// Hardware type.
418     uint16_t hardware_type_;
419 
420 public:
421     /// @todo: Make those fields protected once we start supporting more
422     /// than just Linux
423 
424     /// Specifies if selected interface is loopback.
425     bool flag_loopback_;
426 
427     /// Specifies if selected interface is up.
428     bool flag_up_;
429 
430     /// Flag specifies if selected interface is running
431     /// (e.g. cable plugged in, wifi associated).
432     bool flag_running_;
433 
434     /// Flag specifies if selected interface is multicast capable.
435     bool flag_multicast_;
436 
437     /// Flag specifies if selected interface is broadcast capable.
438     bool flag_broadcast_;
439 
440     /// Interface flags (this value is as is returned by OS,
441     /// it may mean different things on different OSes).
442     /// Solaris based os have unsigned long flags field (64 bits).
443     /// It is usually 32 bits, though.
444     uint64_t flags_;
445 
446     /// Indicates that IPv4 sockets should (true) or should not (false)
447     /// be opened on this interface.
448     bool inactive4_;
449 
450     /// Indicates that IPv6 sockets should (true) or should not (false)
451     /// be opened on this interface.
452     bool inactive6_;
453 
454 private:
455 
456     /// @brief The buffer holding the data read from the socket.
457     ///
458     /// See @c Iface manager description for details.
459     std::vector<uint8_t> read_buffer_;
460 };
461 
462 /// @brief Type definition for the pointer to an @c Iface object.
463 typedef boost::shared_ptr<Iface> IfacePtr;
464 
465 /// @brief Collection of pointers to network interfaces.
466 class IfaceCollection {
467 public:
468 
469     /// @brief Multi index container for network interfaces.
470     ///
471     /// This container allows to search for a network interfaces using
472     /// three indexes:
473     ///  - sequenced: used to access elements in the order they have
474     /// been added to the container.
475     ///  - interface index: used to access an interface using its index.
476     ///  - interface name: used to access an interface using its name.
477     /// Note that indexes and names are unique.
478     typedef boost::multi_index_container<
479         // Container comprises elements of IfacePtr type.
480         IfacePtr,
481         // Here we start enumerating various indexes.
482         boost::multi_index::indexed_by<
483             // Sequenced index allows accessing elements in the same way
484             // as elements in std::list. Sequenced is the index #0.
485             boost::multi_index::sequenced<>,
486             // Start definition of index #1.
487             boost::multi_index::hashed_unique<
488                 // Use the interface index as the key.
489                 boost::multi_index::const_mem_fun<
490                     Iface, int, &Iface::getIndex
491                 >
492             >,
493             // Start definition of index #2.
494             boost::multi_index::hashed_unique<
495                 // Use the interface name as the key.
496                 boost::multi_index::const_mem_fun<
497                     Iface, std::string, &Iface::getName
498                 >
499             >
500         >
501     > IfaceContainer;
502 
503     /// @brief Begin iterator.
504     ///
505     /// @return The container sequence begin iterator.
begin()506     IfaceContainer::const_iterator begin() const {
507         return (ifaces_container_.begin());
508     }
509 
510     /// @brief End iterator.
511     ///
512     /// @return The container sequence end iterator.
end()513     IfaceContainer::const_iterator end() const {
514         return (ifaces_container_.end());
515     }
516 
517     /// @brief Empty predicate.
518     ///
519     /// @return If the container is empty true else false.
empty()520     bool empty() const {
521         return (ifaces_container_.empty());
522     }
523 
524     /// @brief Return the number of interfaces.
525     ///
526     /// @return The container size.
size()527     size_t size() const {
528         return (ifaces_container_.size());
529     }
530 
531     /// @brief Clear the collection.
clear()532     void clear() {
533         cache_.reset();
534         ifaces_container_.clear();
535     }
536 
537     /// @brief Adds an interface to the collection.
538     ///
539     /// The interface is added at the end of sequence.
540     ///
541     /// @param iface reference to Iface object.
push_back(const IfacePtr & iface)542     void push_back(const IfacePtr& iface) {
543         ifaces_container_.push_back(iface);
544     }
545 
546     /// @brief Lookup by interface index.
547     ///
548     /// @param ifindex The index of the interface to find.
549     /// @return The interface with the index or null.
550     IfacePtr getIface(uint32_t ifindex);
551 
552     /// @brief Lookup by interface name.
553     ///
554     /// @param ifname The name of the interface to find.
555     /// @return The interface with the name or null.
556     IfacePtr getIface(const std::string& ifname);
557 
558 private:
559     /// @brief Lookup by interface index.
560     ///
561     /// @param ifindex The index of the interface to find.
562     /// @param need_lock True when the cache operation needs to hold the mutex.
563     /// @return The interface with the index or null.
564     IfacePtr getIfaceInternal(uint32_t ifindex, bool need_lock);
565 
566     /// @brief Lookup by interface name.
567     ///
568     /// The mutex must be held when called from a packet processing thread.
569     ///
570     /// @param ifname The name of the interface to find.
571     /// @param need_lock True when the cache operation needs to hold the mutex.
572     /// @return The interface with the name or null.
573     IfacePtr getIfaceInternal(const std::string& ifname, bool need_lock);
574 
575     /// @brief The mutex for protecting the cache from concurrent
576     /// access from packet processing threads.
577     std::mutex mutex_;
578 
579     /// @brief The last interface returned by a lookup method.
580     ///
581     /// A lookup method first tries the cache: if it matches the cache is
582     /// returned without an expensive lookup in the container. If it does
583     /// not match and a value is found in the container the cache is
584     /// updated with this value.
585     /// The cache should perform well when active interfaces are a small
586     /// subset of the whole interface set, or when consecutive packets
587     /// come from the same interface.
588     IfacePtr cache_;
589 
590     /// @brief The container.
591     IfaceContainer ifaces_container_;
592 };
593 
594 /// @brief Type definition for the unordered set of IPv4 bound addresses.
595 ///
596 /// In order to make @c hasOpenSocket with an IPv4 address faster bound
597 /// addresses should be collected after calling @c CfgIface::openSockets.
598 typedef boost::multi_index_container<
599     /// Container comprises elements of asiolink::IOAddress type.
600     asiolink::IOAddress,
601     // Here we start enumerating the only index.
602     boost::multi_index::indexed_by<
603         // Start definition of index #0.
604         boost::multi_index::hashed_unique<
605             // Use the address in its network order integer form as the key.
606             boost::multi_index::const_mem_fun<
607                 asiolink::IOAddress, uint32_t, &asiolink::IOAddress::toUint32
608             >
609         >
610     >
611 > BoundAddresses;
612 
613 /// @brief Forward declaration to the @c IfaceMgr.
614 class IfaceMgr;
615 
616 /// @brief Type definition for the pointer to the @c IfaceMgr.
617 typedef boost::shared_ptr<IfaceMgr> IfaceMgrPtr;
618 
619 /// @brief This type describes the callback function invoked when error occurs
620 /// in the IfaceMgr.
621 ///
622 /// @param errmsg An error message.
623 typedef
624 std::function<void(const std::string& errmsg)> IfaceMgrErrorMsgCallback;
625 
626 /// @brief Handles network interfaces, transmission and reception.
627 ///
628 /// IfaceMgr is an interface manager class that detects available network
629 /// interfaces, configured addresses, link-local addresses, and provides
630 /// API for using sockets.
631 ///
632 class IfaceMgr : public boost::noncopyable {
633 public:
634     /// Defines callback used when data is received over external sockets.
635     /// @param fd socket descriptor of the ready socket
636     typedef std::function<void (int fd)> SocketCallback;
637 
638     /// Keeps callback information for external sockets.
639     struct SocketCallbackInfo {
640         /// Socket descriptor of the external socket.
641         int socket_;
642 
643         /// A callback that will be called when data arrives over socket_.
644         SocketCallback callback_;
645     };
646 
647     /// Defines storage container for callbacks for external sockets
648     typedef std::list<SocketCallbackInfo> SocketCallbackInfoContainer;
649 
650     /// @brief Packet reception buffer size
651     ///
652     /// RFC 8415 states that server responses may be
653     /// fragmented if they are over MTU. There is no
654     /// text whether client's packets may be larger
655     /// than 1500. For now, we can assume that
656     /// we don't support packets larger than 1500.
657     static const uint32_t RCVBUFSIZE = 1500;
658 
659     /// IfaceMgr is a singleton class. This method returns reference
660     /// to its sole instance.
661     ///
662     /// @return the only existing instance of interface manager
663     static IfaceMgr& instance();
664 
665     /// @brief Returns pointer to the sole instance of the interface manager.
666     ///
667     /// This method returns the pointer to the instance of the interface manager
668     /// which can be held in singleton objects that depend on it. This will
669     /// eliminate issues with the static deinitialization fiasco between this
670     /// object and dependent singleton objects.
671     ///
672     /// The @c IfaceMgr::instance method should be considered deprecated.
673     ///
674     /// @return Shared pointer to the @c IfaceMgr instance.
675     static const IfaceMgrPtr& instancePtr();
676 
677     /// @brief Destructor.
678     ///
679     /// Closes open sockets.
680     virtual ~IfaceMgr();
681 
682     /// @brief Sets or clears the test mode for @c IfaceMgr.
683     ///
684     /// Various unit test may set this flag to true, to indicate that the
685     /// @c IfaceMgr is in the test mode. There are places in the code that
686     /// modify the behavior depending if the @c IfaceMgr is in the test
687     /// mode or not.
688     ///
689     /// @param test_mode A flag which indicates that the @c IfaceMgr is in the
690     /// test mode (if true), or not (if false).
setTestMode(const bool test_mode)691     void setTestMode(const bool test_mode) {
692         test_mode_ = test_mode;
693     }
694 
695     /// @brief Checks if the @c IfaceMgr is in the test mode.
696     ///
697     /// @return true if the @c IfaceMgr is in the test mode, false otherwise.
isTestMode()698     bool isTestMode() const {
699         return (test_mode_);
700     }
701 
702     /// @brief Allows or disallows the loopback interface
703     ///
704     /// By default the loopback interface is not considered when opening
705     /// sockets. This flag provides a way to relax this constraint.
706     ///
setAllowLoopBack(const bool allow_loopback)707     void setAllowLoopBack(const bool allow_loopback) {
708         allow_loopback_ = allow_loopback;
709     }
710 
711     /// @brief Check if packet be sent directly to the client having no address.
712     ///
713     /// Checks if IfaceMgr can send DHCPv4 packet to the client
714     /// who hasn't got address assigned. If this is not supported
715     /// broadcast address should be used to send response to
716     /// the client.
717     ///
718     /// @return true if direct response is supported.
719     bool isDirectResponseSupported() const;
720 
721     /// @brief Returns interface specified interface index
722     ///
723     /// @param ifindex index of searched interface
724     ///
725     /// @return interface with requested index (or null if no such
726     ///         interface is present)
727     ///
728     IfacePtr getIface(int ifindex);
729 
730     /// @brief Returns interface with specified interface name
731     ///
732     /// @param ifname name of searched interface
733     ///
734     /// @return interface with requested name (or null if no such
735     ///         interface is present)
736     IfacePtr getIface(const std::string& ifname);
737 
738     /// @brief Returns interface with specified packet
739     ///
740     /// @note When the interface index is set (@c Pkt::indexSet
741     ///       returns true) it is searched for, if it is not set
742     ///       the name instead is searched for.
743     ///
744     /// @param pkt packet with interface index and name
745     ///
746     /// @return interface with packet interface index or name
747     ///         (or null if no such interface is present)
748     IfacePtr getIface(const PktPtr& pkt);
749 
750     /// @brief Returns container with all interfaces.
751     ///
752     /// This reference is only valid as long as IfaceMgr is valid. However,
753     /// since IfaceMgr is a singleton and is expected to be destroyed after
754     /// main() function completes, you should not worry much about this.
755     ///
756     /// @return container with all interfaces.
getIfaces()757     const IfaceCollection& getIfaces() { return (ifaces_); }
758 
759     /// @brief Removes detected interfaces.
760     ///
761     /// This method removes all detected interfaces. This method should be
762     /// used by unit tests to supply a custom set of interfaces. For example:
763     /// a unit test may create a pool of fake interfaces and use the custom
764     /// @c PktFilter class to mimic socket operation on these interfaces.
765     void clearIfaces();
766 
767     /// @brief Detects network interfaces.
768     ///
769     /// This method will eventually detect available interfaces. For now
770     /// it offers stub implementation. First interface name and link-local
771     /// IPv6 address is read from interfaces.txt file.
772     void detectIfaces();
773 
774     /// @brief Clears unicast addresses on all interfaces.
775     void clearUnicasts();
776 
777     /// @brief Clears the addresses all sockets are bound to.
778     void clearBoundAddresses();
779 
780     /// @brief Collect the addresses all sockets are bound to.
781     void collectBoundAddresses();
782 
783     /// @brief Return most suitable socket for transmitting specified IPv6 packet.
784     ///
785     /// This method takes Pkt6Ptr (see overloaded implementation that takes
786     /// Pkt4Ptr) and chooses appropriate socket to send it. This method
787     /// may throw if specified packet does not have outbound interface specified,
788     /// no such interface exists, or specified interface does not have any
789     /// appropriate sockets open.
790     ///
791     /// @param pkt a packet to be transmitted
792     ///
793     /// @return a socket descriptor
794     /// @throw SocketNotFound If no suitable socket found.
795     /// @throw IfaceNotFound If interface is not set for the packet.
796     uint16_t getSocket(const isc::dhcp::Pkt6Ptr& pkt);
797 
798     /// @brief Return most suitable socket for transmitting specified IPv4 packet.
799     ///
800     /// This method uses the local address assigned to the packet and tries
801     /// to match it with addresses to which sockets are bound for the particular
802     /// interface. If the match is not found, the method returns the first IPv4
803     /// socket found for the particular interface. In case, there are no IPv4
804     /// sockets assigned to the interface the exception is thrown.
805     ///
806     /// @param pkt A packet to be transmitted. It must hold a local address and
807     /// a valid pointer to the interface.
808     ///
809     /// @return A structure describing a socket.
810     /// @throw SocketNotFound if no suitable socket found.
811     SocketInfo getSocket(const isc::dhcp::Pkt4Ptr& pkt);
812 
813     /// Debugging method that prints out all available interfaces.
814     ///
815     /// @param out specifies stream to print list of interfaces to
816     void printIfaces(std::ostream& out = std::cout);
817 
818     /// @brief Sends an IPv6 packet.
819     ///
820     /// Sends an IPv6 packet. All parameters for actual transmission are specified in
821     /// Pkt6 structure itself. That includes destination address, src/dst port
822     /// and interface over which data will be sent.
823     ///
824     /// @param pkt packet to be sent
825     ///
826     /// @throw isc::BadValue if invalid interface specified in the packet.
827     /// @throw isc::dhcp::SocketWriteError if sendmsg() failed to send packet.
828     /// @return true if sending was successful
829     bool send(const Pkt6Ptr& pkt);
830 
831     /// @brief Sends an IPv4 packet.
832     ///
833     /// Sends an IPv4 packet. All parameters for actual transmission are specified
834     /// in Pkt4 structure itself. That includes destination address, src/dst
835     /// port and interface over which data will be sent.
836     ///
837     /// @param pkt a packet to be sent
838     ///
839     /// @throw isc::BadValue if invalid interface specified in the packet.
840     /// @throw isc::dhcp::SocketWriteError if sendmsg() failed to send packet.
841     /// @return true if sending was successful
842     bool send(const Pkt4Ptr& pkt);
843 
844     /// @brief Receive IPv4 packets or data from external sockets
845     ///
846     /// Wrapper around calls to either @c receive4Direct or @c
847     /// receive4Indirect.  The former is called when packet queuing is
848     /// disabled, the latter when it is enabled.
849     ///
850     /// @param timeout_sec specifies integral part of the timeout (in seconds)
851     /// @param timeout_usec specifies fractional part of the timeout
852     /// (in microseconds)
853     ///
854     /// @return Pkt4 object representing received packet (or null)
855     Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec = 0);
856 
857     /// @brief Receive IPv4 packets or data from external sockets
858     ///
859     /// Wrapper around calls to either @c receive4Direct or @c
860     /// receive4Indirect.  The former is called when packet queuing is
861     /// disabled, the latter when it is enabled.
862     ///
863     /// @param timeout_sec specifies integral part of the timeout (in seconds)
864     /// @param timeout_usec specifies fractional part of the timeout
865     /// (in microseconds)
866     ///
867     /// @return Pkt4 object representing received packet (or null)
868     Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec = 0);
869 
870     /// Opens UDP/IP socket and binds it to address, interface and port.
871     ///
872     /// Specific type of socket (UDP/IPv4 or UDP/IPv6) depends on passed addr
873     /// family.
874     ///
875     /// @param ifname name of the interface
876     /// @param addr address to be bound.
877     /// @param port UDP port.
878     /// @param receive_bcast configure IPv4 socket to receive broadcast
879     /// messages or IPv6 socket to join multicast group.
880     /// @param send_bcast configure IPv4 socket to send broadcast messages.
881     /// This parameter is ignored for IPv6 sockets.
882     ///
883     /// Method will throw if socket creation, socket binding or multicast
884     /// join fails.
885     ///
886     /// @return socket descriptor, if socket creation, binding and multicast
887     /// group join were all successful.
888     int openSocket(const std::string& ifname,
889                    const isc::asiolink::IOAddress& addr,
890                    const uint16_t port,
891                    const bool receive_bcast = false,
892                    const bool send_bcast = false);
893 
894     /// @brief Opens UDP/IP socket and binds it to interface specified.
895     ///
896     /// This method differs from \ref openSocket in that it does not require
897     /// the specification of a local address to which socket will be bound.
898     /// Instead, the method searches through the addresses on the specified
899     /// interface and selects one that matches the address family.
900     ///
901     /// @note This method does not join the socket to the multicast group.
902     ///
903     /// @param ifname name of the interface
904     /// @param port UDP port
905     /// @param family address family (AF_INET or AF_INET6)
906     /// @return socket descriptor, if socket creation and binding was
907     /// successful.
908     /// @throw isc::Unexpected if failed to create and bind socket.
909     /// @throw isc::BadValue if there is no address on specified interface
910     /// that belongs to given family.
911     int openSocketFromIface(const std::string& ifname,
912                             const uint16_t port,
913                             const uint8_t family);
914 
915     /// @brief Opens UDP/IP socket and binds to address specified
916     ///
917     /// This methods differs from \ref openSocket in that it does not require
918     /// the specification of the interface to which the socket will be bound.
919     ///
920     /// @note This method does not join the socket to the multicast group.
921     ///
922     /// @param addr address to be bound
923     /// @param port UDP port
924     /// @return socket descriptor, if socket creation and binding was
925     /// successful.
926     /// @throw isc::Unexpected if failed to create and bind socket
927     /// @throw isc::BadValue if specified address is not available on
928     /// any interface
929     int openSocketFromAddress(const isc::asiolink::IOAddress& addr,
930                               const uint16_t port);
931 
932     /// @brief Opens UDP/IP socket to be used to connect to remote address
933     ///
934     /// This method identifies the local address to be used to connect to the
935     /// remote address specified as argument.  Once the local address is
936     /// identified, \ref openSocket is called to open a socket and bind it to
937     /// the interface, address and port.
938     ///
939     /// @note This method does not join the socket to a multicast group.
940     ///
941     /// @param remote_addr remote address to connect to
942     /// @param port UDP port
943     /// @return socket descriptor, if socket creation and binding was
944     /// successful.
945     /// @throw isc::Unexpected if failed to create and bind socket
946     int openSocketFromRemoteAddress(const isc::asiolink::IOAddress& remote_addr,
947                                     const uint16_t port);
948 
949 
950     /// @brief Opens IPv6 sockets on detected interfaces.
951     ///
952     /// This method opens sockets only on interfaces which have the
953     /// @c inactive6_ field set to false (are active). If the interface is active
954     /// but it is not running, it is down, or is a loopback interface when
955     /// loopback is not allowed, an error is reported.
956     ///
957     /// If sockets were successfully opened, it calls @ startDHCPReceiver to
958     /// start the receiver thread (if packet queueing is enabled).
959     ///
960     /// On the systems with multiple interfaces, it is often desired that the
961     /// failure to open a socket on a particular interface doesn't cause a
962     /// fatal error and sockets should be opened on remaining interfaces.
963     /// However, the warning about the failure for the particular socket should
964     /// be communicated to the caller. The libdhcp++ is a common library with
965     /// no logger associated with it. Most of the functions in this library
966     /// communicate errors via exceptions. In case of openSockets6 function
967     /// exception must not be thrown if the function is supposed to continue
968     /// opening sockets, despite an error. Therefore, if such a behavior is
969     /// desired, the error handler function can be passed as a parameter.
970     /// This error handler is called (if present) with an error string.
971     /// Typically, error handler will simply log an error using an application
972     /// logger, but it can do more sophisticated error handling too.
973     ///
974     /// @todo It is possible that additional parameters will have to be added
975     /// to the error handler, e.g. Iface if it was really supposed to do
976     /// some more sophisticated error handling.
977     ///
978     /// If the error handler is not installed (is null), the exception is thrown
979     /// for each failure (default behavior).
980     ///
981     /// @warning This function does not check if there has been any sockets
982     /// already open by the @c IfaceMgr. Therefore a caller should call
983     /// @c IfaceMgr::closeSockets() before calling this function.
984     /// If there are any sockets open, the function may either throw an
985     /// exception or invoke an error handler on attempt to bind the new socket
986     /// to the same address and port.
987     ///
988     /// @param port specifies port number (usually DHCP6_SERVER_PORT)
989     /// @param error_handler A pointer to an error handler function which is
990     /// called by the openSockets6 when it fails to open a socket. This
991     /// parameter can be null to indicate that the callback should not be used.
992     ///
993     /// @throw SocketOpenFailure if tried and failed to open socket.
994     /// @return true if any sockets were open
995     bool openSockets6(const uint16_t port = DHCP6_SERVER_PORT,
996                       IfaceMgrErrorMsgCallback error_handler = 0);
997 
998     /// @brief Opens IPv4 sockets on detected interfaces.
999     ///
1000     /// This method opens sockets only on interfaces which have the
1001     /// @c inactive4_ field set to false (are active). If the interface is active
1002     /// but it is not running, it is down, or is a loopback interface when
1003     /// loopback is not allowed, an error is reported.
1004     ///
1005     /// The type of the socket being open depends on the selected Packet Filter
1006     /// represented by a class derived from @c isc::dhcp::PktFilter abstract
1007     /// class.
1008     ///
1009     /// If sockets were successfully opened, it calls @ startDHCPReceiver to
1010     /// start the receiver thread (if packet queueing is enabled).
1011     ///
1012     /// It is possible to specify whether sockets should be broadcast capable.
1013     /// In most of the cases, the sockets should support broadcast traffic, e.g.
1014     /// DHCPv4 server and relay need to listen to broadcast messages sent by
1015     /// clients. If the socket has to be open on the particular interface, this
1016     /// interface must have broadcast flag set. If this condition is not met,
1017     /// the socket will be created in the unicast-only mode. If there are
1018     /// multiple broadcast-capable interfaces present, they may be all open
1019     /// in a broadcast mode only if the OS supports SO_BINDTODEVICE (bind socket
1020     /// to a device) socket option. If this option is not supported, only the
1021     /// first broadcast-capable socket will be opened in the broadcast mode.
1022     /// The error will be reported for sockets being opened on other interfaces.
1023     /// If the socket is bound to a device (interface), the broadcast traffic
1024     /// sent to this interface will be received on this interface only.
1025     /// This allows the DHCPv4 server or relay to detect the interface on which
1026     /// the broadcast message has been received. This interface is later used
1027     /// to send a response.
1028     ///
1029     /// On the systems with multiple interfaces, it is often desired that the
1030     /// failure to open a socket on a particular interface doesn't cause a
1031     /// fatal error and sockets should be opened on remaining interfaces.
1032     /// However, the warning about the failure for the particular socket should
1033     /// be communicated to the caller. The libdhcp++ is a common library with
1034     /// no logger associated with it. Most of the functions in this library
1035     /// communicate errors via exceptions. In case of openSockets4 function
1036     /// exception must not be thrown if the function is supposed to continue
1037     /// opening sockets, despite an error. Therefore, if such a behavior is
1038     /// desired, the error handler function can be passed as a parameter.
1039     /// This error handler is called (if present) with an error string.
1040     /// Typically, error handler will simply log an error using an application
1041     /// logger, but it can do more sophisticated error handling too.
1042     ///
1043     /// @todo It is possible that additional parameters will have to be added
1044     /// to the error handler, e.g. Iface if it was really supposed to do
1045     /// some more sophisticated error handling.
1046     ///
1047     /// If the error handler is not installed (is null), the exception is thrown
1048     /// for each failure (default behavior).
1049     ///
1050     /// @warning This function does not check if there has been any sockets
1051     /// already open by the @c IfaceMgr. Therefore a caller should call
1052     /// @c IfaceMgr::closeSockets() before calling this function.
1053     /// If there are any sockets open, the function may either throw an
1054     /// exception or invoke an error handler on attempt to bind the new socket
1055     /// to the same address and port.
1056     ///
1057     /// @param port specifies port number (usually DHCP4_SERVER_PORT)
1058     /// @param use_bcast configure sockets to support broadcast messages.
1059     /// @param error_handler A pointer to an error handler function which is
1060     /// called by the openSockets4 when it fails to open a socket. This
1061     /// parameter can be null to indicate that the callback should not be used.
1062     ///
1063     /// @throw SocketOpenFailure if tried and failed to open socket and callback
1064     /// function hasn't been specified.
1065     /// @return true if any sockets were open
1066     bool openSockets4(const uint16_t port = DHCP4_SERVER_PORT,
1067                       const bool use_bcast = true,
1068                       IfaceMgrErrorMsgCallback error_handler = 0);
1069 
1070     /// @brief Closes all open sockets.
1071     ///
1072     /// It calls @c stopDHCPReceiver to stop the receiver thread and then
1073     /// it closes all open interface sockets.
1074     ///
1075     /// Is used in destructor, but also from Dhcpv4Srv and Dhcpv6Srv classes.
1076     void closeSockets();
1077 
1078     /// @brief Returns number of detected interfaces.
1079     ///
1080     /// @return number of detected interfaces
countIfaces()1081     uint16_t countIfaces() { return ifaces_.size(); }
1082 
1083     /// @brief Adds external socket and a callback
1084     ///
1085     /// Specifies external socket and a callback that will be called
1086     /// when data will be received over that socket.
1087     ///
1088     /// @param socketfd socket descriptor
1089     /// @param callback callback function
1090     void addExternalSocket(int socketfd, SocketCallback callback);
1091 
1092     /// @brief Deletes external socket
1093     ///
1094     /// @param socketfd socket descriptor
1095     void deleteExternalSocket(int socketfd);
1096 
1097     /// @brief Scans registered socket set and removes any that are invalid.
1098     ///
1099     /// Walks the list of registered external sockets and tests each for
1100     /// validity.  If any are found to be invalid they are removed. This is
1101     /// primarily a self-defense mechanism against hook libs or other users
1102     /// of external sockets that may leave a closed socket registered by
1103     /// mistake.
1104     ///
1105     /// @return A count of the sockets purged.
1106     int purgeBadSockets();
1107 
1108     /// @brief Deletes all external sockets.
1109     void deleteAllExternalSockets();
1110 
1111     /// @brief Set packet filter object to handle sending and receiving DHCPv4
1112     /// messages.
1113     ///
1114     /// Packet filter objects provide means for the @c IfaceMgr to open sockets
1115     /// for IPv4 packets reception and sending. This function sets custom packet
1116     /// filter (represented by a class derived from PktFilter) to be used by
1117     /// @c IfaceMgr. Note that there must be no IPv4 sockets open when this
1118     /// function is called. Call closeSockets(AF_INET) to close all hanging IPv4
1119     /// sockets opened by the current packet filter object.
1120     ///
1121     /// @param packet_filter A pointer to the new packet filter object to be
1122     /// used by @c IfaceMgr.
1123     ///
1124     /// @throw InvalidPacketFilter if provided packet filter object is null.
1125     /// @throw PacketFilterChangeDenied if there are open IPv4 sockets.
1126     void setPacketFilter(const PktFilterPtr& packet_filter);
1127 
1128     /// @brief Set packet filter object to handle sending and receiving DHCPv6
1129     /// messages.
1130     ///
1131     /// Packet filter objects provide means for the @c IfaceMgr to open sockets
1132     /// for IPv6 packets reception and sending. This function sets the new
1133     /// instance of the packet filter which will be used by @c IfaceMgr to send
1134     /// and receive DHCPv6 messages, until replaced by another packet filter.
1135     ///
1136     /// It is required that DHCPv6 messages are send and received using methods
1137     /// of the same object that was used to open socket. Therefore, it is
1138     /// required that all IPv6 sockets are closed prior to calling this
1139     /// function. Call closeSockets(AF_INET6) to close all hanging IPv6 sockets
1140     /// opened by the current packet filter object.
1141     ///
1142     /// @param packet_filter A pointer to the new packet filter object to be
1143     /// used by @c IfaceMgr.
1144     ///
1145     /// @throw isc::dhcp::InvalidPacketFilter if specified object is null.
1146     /// @throw isc::dhcp::PacketFilterChangeDenied if there are open IPv6
1147     /// sockets.
1148     void setPacketFilter(const PktFilter6Ptr& packet_filter);
1149 
1150     /// @brief Set Packet Filter object to handle send/receive packets.
1151     ///
1152     /// This function sets Packet Filter object to be used by IfaceMgr,
1153     /// appropriate for the current OS. Setting the argument to 'true'
1154     /// indicates that function should set a packet filter class
1155     /// which supports direct responses to clients having no address
1156     /// assigned yet. Filters picked by this function will vary, depending
1157     /// on the OS being used. There is no guarantee that there is an
1158     /// implementation that supports this feature on a particular OS.
1159     /// If there isn't, the PktFilterInet object will be set. If the
1160     /// argument is set to 'false', PktFilterInet object instance will
1161     /// be set as the Packet Filter regardless of the OS type.
1162     ///
1163     /// @param direct_response_desired specifies whether the Packet Filter
1164     /// object being set should support direct traffic to the host
1165     /// not having address assigned.
1166     void setMatchingPacketFilter(const bool direct_response_desired = false);
1167 
1168     /// @brief Adds an interface to list of known interfaces.
1169     ///
1170     /// @param iface reference to Iface object.
1171     /// @note This function must be public because it has to be callable
1172     /// from unit tests.
1173     /// @throw Unexpected when name or index already exists.
1174     void addInterface(const IfacePtr& iface);
1175 
1176     /// @brief Checks if there is at least one socket of the specified family
1177     /// open.
1178     ///
1179     /// @param family A socket family.
1180     ///
1181     /// @return true if there is at least one socket open, false otherwise.
1182     bool hasOpenSocket(const uint16_t family) const;
1183 
1184     /// @brief Checks if there is a socket open and bound to an address.
1185     ///
1186     /// This function checks if one of the sockets opened by the IfaceMgr is
1187     /// bound to the IP address specified as the method parameter. If the
1188     /// socket is bound to the port (and address is unspecified), the
1189     /// method will check if the address passed in the argument is configured
1190     /// on an interface.
1191     ///
1192     /// @param addr Address of the socket being searched.
1193     ///
1194     /// @return true if there is a socket bound to the specified address.
1195     bool hasOpenSocket(const isc::asiolink::IOAddress& addr) const;
1196 
1197     /// @brief Fetches the DHCPv4 packet queue manager
1198     ///
1199     /// @return pointer to the packet queue mgr
getPacketQueueMgr4()1200     PacketQueueMgr4Ptr getPacketQueueMgr4() {
1201         return (packet_queue_mgr4_);
1202     }
1203 
1204     /// @brief Fetches the DHCPv4 receiver packet queue.
1205     ///
1206     /// Incoming packets are read by the receiver thread and
1207     /// added to this queue. @c receive4() dequeues and
1208     /// returns them.
1209     /// @return pointer to the packet queue
getPacketQueue4()1210     PacketQueue4Ptr getPacketQueue4() {
1211         return (packet_queue_mgr4_->getPacketQueue());
1212     }
1213 
1214     /// @brief Fetches the DHCPv6 packet queue manager
1215     ///
1216     /// @return pointer to the packet queue mgr
getPacketQueueMgr6()1217     PacketQueueMgr6Ptr getPacketQueueMgr6() {
1218         return (packet_queue_mgr6_);
1219     }
1220 
1221     /// @brief Fetches the DHCPv6 receiver packet queue.
1222     ///
1223     /// Incoming packets are read by the receiver thread and
1224     /// added to this queue. @c receive6() dequeues and
1225     /// returns them.
1226     /// @return pointer to the packet queue
getPacketQueue6()1227     PacketQueue6Ptr getPacketQueue6() {
1228         return (packet_queue_mgr6_->getPacketQueue());
1229     }
1230 
1231     /// @brief Starts DHCP packet receiver.
1232     ///
1233     /// Starts the DHCP packet receiver thread for the given.
1234     /// protocol, AF_NET or AF_INET6, if the packet queue
1235     /// exists, otherwise it simply returns.
1236     ///
1237     /// @param family indicates which receiver to start,
1238     /// (AF_INET or AF_INET6)
1239     ///
1240     /// @throw Unexpected if the thread already exists.
1241     void startDHCPReceiver(const uint16_t family);
1242 
1243     /// @brief Stops the DHCP packet receiver.
1244     ///
1245     /// If the thread exists, it is stopped, deleted, and
1246     /// the packet queue is flushed.
1247     void stopDHCPReceiver();
1248 
1249     /// @brief Returns true if there is a receiver exists and its
1250     /// thread is currently running.
isDHCPReceiverRunning()1251     bool isDHCPReceiverRunning() const {
1252         return (dhcp_receiver_ != 0 && dhcp_receiver_->isRunning());
1253     }
1254 
1255     /// @brief Configures DHCP packet queue
1256     ///
1257     /// If the given configuration enables packet queueing, then the
1258     /// appropriate queue is created. Otherwise, the existing queue is
1259     /// destroyed. If the receiver thread is running when this function
1260     /// is invoked, it will throw.
1261     ///
1262     /// @param family indicates which receiver to start,
1263     /// (AF_INET or AF_INET6)
1264     /// @param queue_control configuration containing "dhcp-queue-control"
1265     /// content
1266     /// @return true if packet queueuing has been enabled, false otherwise
1267     /// @throw InvalidOperation if the receiver thread is currently running.
1268     bool configureDHCPPacketQueue(const uint16_t family,
1269                                   data::ConstElementPtr queue_control);
1270 
1271     /// @brief Convenience method for adding an descriptor to a set
1272     ///
1273     /// @param fd descriptor to add
1274     /// @param[out] maxfd maximum fd value in the set.  If the new fd is
1275     /// larger than it's current value, it will be updated to new fd value
1276     /// @param sockets pointer to the set of sockets
1277     /// @throw BadValue if sockets is null
1278     static void addFDtoSet(int fd, int& maxfd, fd_set* sockets);
1279 
1280     // don't use private, we need derived classes in tests
1281 protected:
1282 
1283     /// @brief Protected constructor.
1284     ///
1285     /// Protected constructor. This is a singleton class. We don't want
1286     /// anyone to create instances of IfaceMgr. Use instance() method instead.
1287     IfaceMgr();
1288 
1289     /// @brief Opens IPv4 socket.
1290     ///
1291     /// Please do not use this method directly. Use openSocket instead.
1292     ///
1293     /// This method may throw exception if socket creation fails.
1294     ///
1295     /// @param iface reference to interface structure.
1296     /// @param addr an address the created socket should be bound to
1297     /// @param port a port that created socket should be bound to
1298     /// @param receive_bcast configure socket to receive broadcast messages
1299     /// @param send_bcast configure socket to send broadcast messages.
1300     ///
1301     /// @return socket descriptor
1302     int openSocket4(Iface& iface, const isc::asiolink::IOAddress& addr,
1303                     const uint16_t port, const bool receive_bcast = false,
1304                     const bool send_bcast = false);
1305 
1306     /// @brief Receive IPv4 packets directly or data from external sockets.
1307     ///
1308     /// Attempts to receive a single DHCPv4 message over any of the open
1309     /// IPv4 sockets. If reception is successful and all information about
1310     /// its sender is obtained, an Pkt4 object is created and returned.
1311     ///
1312     /// This method also checks if data arrived over registered external socket.
1313     /// This data may be of a different protocol family than AF_INET.
1314     ///
1315     /// @param timeout_sec specifies integral part of the timeout (in seconds)
1316     /// @param timeout_usec specifies fractional part of the timeout
1317     /// (in microseconds)
1318     ///
1319     /// @throw isc::BadValue if timeout_usec is greater than one million
1320     /// @throw isc::dhcp::SocketReadError if error occurred when receiving a
1321     /// packet.
1322     /// @throw isc::dhcp::SignalInterruptOnSelect when a call to select() is
1323     /// interrupted by a signal.
1324     ///
1325     /// @return Pkt4 object representing received packet (or null)
1326     Pkt4Ptr receive4Direct(uint32_t timeout_sec, uint32_t timeout_usec = 0);
1327 
1328     /// @brief Receive IPv4 packets indirectly or data from external sockets.
1329     ///
1330     /// Attempts to receive a single DHCPv4 message from the packet queue.
1331     /// The queue is populated by the receiver thread.  If a packet is waiting
1332     /// in the queue, a Pkt4 returned.
1333     ///
1334     /// This method also checks if data arrived over registered external socket.
1335     /// This data may be of a different protocol family than AF_INET.
1336     ///
1337     /// @param timeout_sec specifies integral part of the timeout (in seconds)
1338     /// @param timeout_usec specifies fractional part of the timeout
1339     /// (in microseconds)
1340     ///
1341     /// @throw isc::BadValue if timeout_usec is greater than one million
1342     /// @throw isc::dhcp::SocketReadError if error occurred when receiving a
1343     /// packet.
1344     /// @throw isc::dhcp::SignalInterruptOnSelect when a call to select() is
1345     /// interrupted by a signal.
1346     ///
1347     /// @return Pkt4 object representing received packet (or null)
1348     Pkt4Ptr receive4Indirect(uint32_t timeout_sec, uint32_t timeout_usec = 0);
1349 
1350     /// @brief Opens IPv6 socket.
1351     ///
1352     /// Please do not use this method directly. Use openSocket instead.
1353     ///
1354     /// This method may throw exception if socket creation fails.
1355     ///
1356     /// @param iface reference to interface structure.
1357     /// @param addr an address the created socket should be bound to
1358     /// @param port a port that created socket should be bound to
1359     /// @param join_multicast A boolean parameter which indicates whether
1360     /// socket should join All_DHCP_Relay_Agents_and_servers multicast
1361     /// group.
1362     ///
1363     /// @return socket descriptor
1364     int openSocket6(Iface& iface, const isc::asiolink::IOAddress& addr,
1365                     uint16_t port, const bool join_multicast);
1366 
1367     /// @brief Receive IPv6 packets directly or data from external sockets.
1368     ///
1369     /// Attempts to receive a single DHCPv6 message over any of the open
1370     /// IPv6 sockets. If reception is successful and all information about
1371     /// its sender is obtained, an Pkt6 object is created and returned.
1372     ///
1373     /// This method also checks if data arrived over registered external socket.
1374     /// This data may be of a different protocol family than AF_INET.
1375     ///
1376     /// @param timeout_sec specifies integral part of the timeout (in seconds)
1377     /// @param timeout_usec specifies fractional part of the timeout
1378     /// (in microseconds)
1379     ///
1380     /// @throw isc::BadValue if timeout_usec is greater than one million
1381     /// @throw isc::dhcp::SocketReadError if error occurred when receiving a
1382     /// packet.
1383     /// @throw isc::dhcp::SignalInterruptOnSelect when a call to select() is
1384     /// interrupted by a signal.
1385     ///
1386     /// @return Pkt6 object representing received packet (or null)
1387     Pkt6Ptr receive6Direct(uint32_t timeout_sec, uint32_t timeout_usec = 0);
1388 
1389     /// @brief Receive IPv6 packets indirectly or data from external sockets.
1390     ///
1391     /// Attempts to receive a single DHCPv6 message from the packet queue.
1392     /// The queue is populated by the receiver thread.  If a packet is waiting
1393     /// in the queue, a Pkt6 returned.
1394     ///
1395     /// This method also checks if data arrived over registered external socket.
1396     /// This data may be of a different protocol family than AF_INET.
1397     ///
1398     /// @param timeout_sec specifies integral part of the timeout (in seconds)
1399     /// @param timeout_usec specifies fractional part of the timeout
1400     /// (in microseconds)
1401     ///
1402     /// @throw isc::BadValue if timeout_usec is greater than one million
1403     /// @throw isc::dhcp::SocketReadError if error occurred when receiving a
1404     /// packet.
1405     /// @throw isc::dhcp::SignalInterruptOnSelect when a call to select() is
1406     /// interrupted by a signal.
1407     ///
1408     /// @return Pkt6 object representing received packet (or null)
1409     Pkt6Ptr receive6Indirect(uint32_t timeout_sec, uint32_t timeout_usec = 0);
1410 
1411 
1412     /// @brief Stub implementation of network interface detection.
1413     ///
1414     /// This implementations reads a single line from interfaces.txt file
1415     /// and pretends to detect such interface. First interface name and
1416     /// link-local IPv6 address or IPv4 address is read from the
1417     /// interfaces.txt file.
1418     void stubDetectIfaces();
1419 
1420     /// @brief List of available interfaces
1421     IfaceCollection ifaces_;
1422 
1423     /// @brief Unordered set of IPv4 bound addresses.
1424     BoundAddresses bound_address_;
1425 
1426     // TODO: Also keep this interface on Iface once interface detection
1427     // is implemented. We may need it e.g. to close all sockets on
1428     // specific interface
1429     //int recvsock_; // TODO: should be fd_set eventually, but we have only
1430     //int sendsock_; // 2 sockets for now. Will do for until next release
1431 
1432     // We can't use the same socket, as receiving socket
1433     // is bound to multicast address. And we all know what happens
1434     // to people who try to use multicast as source address.
1435 
1436 private:
1437     /// @brief Identifies local network address to be used to
1438     /// connect to remote address.
1439     ///
1440     /// This method identifies local network address that can be used
1441     /// to connect to remote address specified.
1442     /// It first creates socket and makes attempt to connect
1443     /// to remote location via this socket. If connection
1444     /// is established successfully, the local address to which
1445     /// socket is bound is returned.
1446     ///
1447     /// @param remote_addr remote address to connect to
1448     /// @param port port to be used
1449     /// @return local address to be used to connect to remote address
1450     /// @throw isc::Unexpected if unable to identify local address
1451     isc::asiolink::IOAddress
1452     getLocalAddress(const isc::asiolink::IOAddress& remote_addr,
1453                     const uint16_t port);
1454 
1455 
1456     /// @brief Open an IPv6 socket with multicast support.
1457     ///
1458     /// This function opens a socket capable of receiving messages sent to
1459     /// the All_DHCP_Relay_Agents_and_Servers (ff02::1:2) multicast address.
1460     /// The socket is bound to the in6addr_any address and the IPV6_JOIN_GROUP
1461     /// option is set to point to the ff02::1:2 multicast address.
1462     ///
1463     /// @note This function is intended to be called internally by the
1464     /// @c IfaceMgr::openSockets6. It is not intended to be called from any
1465     /// other function.
1466     ///
1467     /// @param iface Interface on which socket should be open.
1468     /// @param addr Link-local address to bind the socket to.
1469     /// @param port Port number to bind socket to.
1470     /// @param error_handler Error handler function to be called when an
1471     /// error occurs during opening a socket, or null if exception should
1472     /// be thrown upon error.
1473     bool openMulticastSocket(Iface& iface,
1474                              const isc::asiolink::IOAddress& addr,
1475                              const uint16_t port,
1476                              IfaceMgrErrorMsgCallback error_handler = 0);
1477 
1478     /// @brief DHCPv4 receiver method.
1479     ///
1480     /// Loops forever reading DHCPv4 packets from the interface sockets
1481     /// and adds them to the packet queue.  It monitors the "terminate"
1482     /// watch socket, and exits if it is marked ready.  This is method
1483     /// is used as the worker function in the thread created by @c
1484     /// startDHCP4Receiver().  It currently uses select() to monitor
1485     /// socket readiness.  If the select errors out (other than EINTR),
1486     /// it marks the "error" watch socket as ready.
1487     void receiveDHCP4Packets();
1488 
1489     /// @brief Receives a single DHCPv4 packet from an interface socket
1490     ///
1491     /// Called by @c receiveDHPC4Packets when a socket fd is flagged as
1492     /// ready. It uses the DHCPv4 packet filter to receive a single packet
1493     /// from the given interface socket, adds it to the packet queue, and
1494     /// marks the "receive" watch socket ready. If an error occurs during
1495     /// the read, the "error" watch socket is marked ready.
1496     ///
1497     /// @param iface interface
1498     /// @param socket_info structure holding socket information
1499     void receiveDHCP4Packet(Iface& iface, const SocketInfo& socket_info);
1500 
1501     /// @brief DHCPv6 receiver method.
1502     ///
1503     /// Loops forever reading DHCPv6 packets from the interface sockets
1504     /// and adds them to the packet queue.  It monitors the "terminate"
1505     /// watch socket, and exits if it is marked ready.  This is method
1506     /// is used as the worker function in the thread created by @c
1507     /// startDHCP6Receiver().  It currently uses select() to monitor
1508     /// socket readiness.  If the select errors out (other than EINTR),
1509     /// it marks the "error" watch socket as ready.
1510     void receiveDHCP6Packets();
1511 
1512     /// @brief Receives a single DHCPv6 packet from an interface socket
1513     ///
1514     /// Called by @c receiveDHPC6Packets when a socket fd is flagged as
1515     /// ready. It uses the DHCPv6 packet filter to receive a single packet
1516     /// from the given interface socket, adds it to the packet queue, and
1517     /// marks the "receive" watch socket ready. If an error occurs during
1518     /// the read, the "error" watch socket is marked ready.
1519     ///
1520     /// @param socket_info structure holding socket information
1521     void receiveDHCP6Packet(const SocketInfo& socket_info);
1522 
1523     /// @brief Deletes external socket with the callbacks_mutex_ taken
1524     ///
1525     /// @param socketfd socket descriptor
1526     void deleteExternalSocketInternal(int socketfd);
1527 
1528     /// Holds instance of a class derived from PktFilter, used by the
1529     /// IfaceMgr to open sockets and send/receive packets through these
1530     /// sockets. It is possible to supply custom object using
1531     /// setPacketFilter method. Various Packet Filters differ mainly by using
1532     /// different types of sockets, e.g. SOCK_DGRAM,  SOCK_RAW and different
1533     /// families, e.g. AF_INET, AF_PACKET etc. Another possible type of
1534     /// Packet Filter is the one used for unit testing, which doesn't
1535     /// open sockets but rather mimics their behavior (mock object).
1536     PktFilterPtr packet_filter_;
1537 
1538     /// Holds instance of a class derived from PktFilter6, used by the
1539     /// IfaceMgr to manage sockets used to send and receive DHCPv6
1540     /// messages. It is possible to supply a custom object using
1541     /// setPacketFilter method.
1542     PktFilter6Ptr packet_filter6_;
1543 
1544     /// @brief Contains list of callbacks for external sockets
1545     SocketCallbackInfoContainer callbacks_;
1546 
1547     /// @brief Mutex to protect callbacks_ against concurrent access
1548     std::mutex callbacks_mutex_;
1549 
1550     /// @brief Indicates if the IfaceMgr is in the test mode.
1551     bool test_mode_;
1552 
1553     /// @brief Allows to use loopback
1554     bool allow_loopback_;
1555 
1556     /// @brief Manager for DHCPv4 packet implementations and queues
1557     PacketQueueMgr4Ptr packet_queue_mgr4_;
1558 
1559     /// @brief Manager for DHCPv6 packet implementations and queues
1560     PacketQueueMgr6Ptr packet_queue_mgr6_;
1561 
1562     /// DHCP packet receiver.
1563     isc::util::WatchedThreadPtr dhcp_receiver_;
1564 };
1565 
1566 }; // namespace isc::dhcp
1567 }; // namespace isc
1568 
1569 #endif // IFACE_MGR_H
1570