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