Kea 3.1.10
iface_mgr.cc
Go to the documentation of this file.
1// Copyright (C) 2011-2026 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#include <config.h>
9#include <asiolink/io_error.h>
11#include <cc/data.h>
12#include <dhcp/dhcp4.h>
13#include <dhcp/dhcp6.h>
14#include <dhcp/dhcp_log.h>
15#include <dhcp/dhcp_messages.h>
16#include <dhcp/iface_mgr.h>
21#include <log/macros.h>
25
26#include <boost/scoped_ptr.hpp>
27
28#include <cstring>
29#include <errno.h>
30#include <fstream>
31#include <functional>
32#include <limits>
33#include <sstream>
34
35#include <arpa/inet.h>
36#include <netinet/in.h>
37#include <sys/ioctl.h>
38#include <string.h>
39
40using namespace std;
41using namespace isc::asiolink;
42using namespace isc::data;
43using namespace isc::util;
44using namespace isc::util::io;
45using namespace isc::util::io::internal;
46namespace ph = std::placeholders;
47
48namespace isc {
49namespace dhcp {
50
53 return (*instancePtr());
54}
55
56const IfaceMgrPtr&
58 static IfaceMgrPtr iface_mgr(new IfaceMgr());
59 return (iface_mgr);
60}
61
62Iface::Iface(const std::string& name, unsigned int ifindex)
63 : name_(name), ifindex_(ifindex), mac_len_(0), hardware_type_(0),
64 flag_loopback_(false), flag_up_(false), flag_running_(false),
65 flag_multicast_(false), flag_broadcast_(false), flags_(0),
66 inactive4_(false), inactive6_(false) {
67 // Sanity checks.
68 if (name.empty()) {
69 isc_throw(BadValue, "Interface name must not be empty");
70 }
71 memset(mac_, 0, sizeof(mac_));
72}
73
74void
76 // Close IPv4 sockets.
77 closeSockets(AF_INET);
78 // Close IPv6 sockets.
79 closeSockets(AF_INET6);
80}
81
82void
83Iface::closeSockets(const uint16_t family) {
84 // Check that the correct 'family' value has been specified.
85 // The possible values are AF_INET or AF_INET6. Note that, in
86 // the current code they are used to differentiate that the
87 // socket is used to transmit IPv4 or IPv6 traffic. However,
88 // the actual family types of the sockets may be different,
89 // e.g. for LPF we are using raw sockets of AF_PACKET family.
90 //
91 // @todo Consider replacing the AF_INET and AF_INET6 with some
92 // enum which will not be confused with the actual socket type.
93 if ((family != AF_INET) && (family != AF_INET6)) {
94 isc_throw(BadValue, "Invalid socket family " << family
95 << " specified when requested to close all sockets"
96 << " which belong to this family");
97 }
98
99 // Search for the socket of the specific type.
100 SocketCollection::iterator sock = sockets_.begin();
101 while (sock != sockets_.end()) {
102 if (sock->family_ == family) {
103 // Close and delete the socket and move to the
104 // next one.
105 close(sock->sockfd_);
106 // Close fallback socket if open.
107 if (sock->fallbackfd_ >= 0) {
108 close(sock->fallbackfd_);
109 }
110 sock = sockets_.erase(sock);
111 } else {
112 // Different type of socket. Let's move
113 // to the next one.
114 ++sock;
115 }
116 }
117}
118
119std::string
121 ostringstream tmp;
122 tmp << name_ << "/" << ifindex_;
123 return (tmp.str());
124}
125
126std::string
128 ostringstream tmp;
129 tmp.fill('0');
130 tmp << hex;
131 for (unsigned i = 0; i < mac_len_; i++) {
132 tmp.width(2);
133 tmp << static_cast<int>(mac_[i]);
134 if (i < mac_len_ - 1) {
135 tmp << ":";
136 }
137 }
138 return (tmp.str());
139}
140
141void Iface::setMac(const uint8_t* mac, size_t len) {
142 if (len > MAX_MAC_LEN) {
143 isc_throw(OutOfRange, "Interface " << getFullName()
144 << " was detected to have link address of length "
145 << len << ", but maximum supported length is "
146 << MAX_MAC_LEN);
147 }
148 mac_len_ = len;
149 if (len > 0) {
150 memcpy(mac_, mac, len);
151 }
152}
153
155 for (AddressCollection::iterator a = addrs_.begin(); a != addrs_.end(); ++a) {
156 if (a->get() == addr) {
157 addrs_.erase(a);
158 return (true);
159 }
160 }
161 return (false);
162}
163
164bool Iface::delSocket(const uint16_t sockfd) {
165 SocketCollection::iterator sock = sockets_.begin();
166 while (sock != sockets_.end()) {
167 if (sock->sockfd_ == sockfd) {
168 close(sockfd);
169 // Close fallback socket if open.
170 if (sock->fallbackfd_ >= 0) {
171 close(sock->fallbackfd_);
172 }
173 sockets_.erase(sock);
174 return (true); //socket found
175 }
176 ++sock;
177 }
178 return (false); // socket not found
179}
180
182 : packet_filter_(new PktFilterInet()),
183 packet_filter6_(new PktFilterInet6()),
184 test_mode_(false), check_thread_id_(true),
185 allow_loopback_(false), family_(AF_INET) {
186 id_ = std::this_thread::get_id();
187
188 // Ensure that PQMs have been created to guarantee we have
189 // default packet queues in place.
190 try {
191 packet_queue_mgr4_.reset(new PacketQueueMgr4());
192 packet_queue_mgr6_.reset(new PacketQueueMgr6());
193 } catch (const std::exception& ex) {
194 isc_throw(Unexpected, "Failed to create PacketQueueManagers: " << ex.what());
195 }
196
197 detect_callback_ = std::bind(&IfaceMgr::checkDetectIfaces, this, ph::_1);
198
199 try {
200
201 // required for sending/receiving packets
202 // let's keep it in front, just in case someone
203 // wants to send anything during initialization
204 detectIfaces();
205
206 } catch (const std::exception& ex) {
207 isc_throw(IfaceDetectError, ex.what());
208 }
209
211}
212
217
219 for (const Address& a : unicasts_) {
220 if (a.get() == addr) {
221 isc_throw(BadValue, "Address " << addr
222 << " already defined on the " << name_ << " interface.");
223 }
224 }
225 unicasts_.push_back(Optional<IOAddress>(addr));
226}
227
228bool
230 // Iterate over existing addresses assigned to the interface.
231 // Try to find the one that is IPv4.
232 for (const Address& addr : getAddresses()) {
233 // If address is IPv4, we assign it to the function argument
234 // and return true.
235 if (addr.get().isV4()) {
236 address = addr.get();
237 return (true);
238 }
239 }
240 // There is no IPv4 address assigned to this interface.
241 return (false);
242}
243
244bool
246 for (const Address& addr : getAddresses()) {
247 if (address == addr.get()) {
248 return (true);
249 }
250 }
251 return (false);
252}
253
254void
256 if (!hasAddress(addr)) {
257 addrs_.push_back(Address(addr));
258 }
259}
260
261void
262Iface::setActive(const IOAddress& address, const bool active) {
263 for (auto& addr : addrs_) {
264 if (address == addr.get()) {
265 addr.unspecified(!active);
266 return;
267 }
268 }
269 isc_throw(BadValue, "specified address " << address << " was not"
270 " found on the interface " << getName());
271}
272
273void
274Iface::setActive(const bool active) {
275 for (auto& addr : addrs_) {
276 addr.unspecified(!active);
277 }
278}
279
280unsigned int
282 uint16_t count = 0;
283 for (const Address& addr : addrs_) {
284 if (!addr.unspecified() && addr.get().isV4()) {
285 ++count;
286 }
287 }
288 return (count);
289}
290
294 result->set("name", Element::create(name_));
295 result->set("index", Element::create(ifindex_));
296 result->set("mac", Element::create(getPlainMac()));
297 result->set("type", Element::create(hardware_type_));
298 result->set("flag-loopback", Element::create(flag_loopback_));
299 result->set("flag-up", Element::create(flag_up_));
300 result->set("flag-running", Element::create(flag_running_));
301 result->set("flag-multicast", Element::create(flag_multicast_));
302 result->set("flag-broadcast", Element::create(flag_broadcast_));
303 bool in_use = IfaceMgr::instance().getFamily() == AF_INET ? !inactive4_ : !inactive6_;
304 result->set("in-use", Element::create(in_use));
306 for (auto const& addr : addrs_) {
307 addrs->add(Element::create(addr.get().toText()));
308 }
309 result->set("addresses", addrs);
310 return (result);
311}
312
314 // Clears bound addresses.
316
317 // Stops the receiver thread if there is one.
319
320 for (const IfacePtr& iface : ifaces_) {
321 iface->closeSockets();
322 }
323}
324
325void IfaceMgr::stopDHCPReceiver(bool clear_queue) {
326 if (isDHCPReceiverRunning()) {
327 dhcp_receiver_->stop();
328 }
329
330 dhcp_receiver_.reset();
331
332 if (clear_queue) {
333 if (getPacketQueue4()) {
334 getPacketQueue4()->clear();
335 }
336
337 if (getPacketQueue6()) {
338 getPacketQueue6()->clear();
339 }
340 }
341}
342
346
350 for (auto const& iface: ifaces_) {
351 result->add(iface->toElement());
352 }
353 return (result);
354}
355
356bool
358 return (packet_filter_->isDirectResponseSupported());
359}
360
361bool
363 return (packet_filter_->isSocketReceivedTimeSupported());
364}
365
366void
368 if (socketfd < 0) {
369 isc_throw(BadValue, "Attempted to install callback for invalid socket "
370 << socketfd);
371 }
372 if (check_thread_id_ && std::this_thread::get_id() != id_) {
374 .arg(socketfd)
375 .arg(std::this_thread::get_id())
376 .arg(id_);
377 }
378 // New entry.
379 SocketCallbackInfo x(socketfd);
380 x.callback_ = callback;
381 std::lock_guard<std::mutex> lock(callbacks_mutex_);
382 auto& idx = callbacks_.get<1>();
383 auto it = idx.find(socketfd);
384 if (it != idx.end()) {
385 // There's such a socket description there already.
386 // Replace it.
388 .arg(socketfd);
389 idx.replace(it, x);
390 return;
391 }
392
393 // Add a new entry to the callbacks vector
394 callbacks_.push_back(x);
395}
396
397void
399 std::lock_guard<std::mutex> lock(callbacks_mutex_);
400 deleteExternalSocketInternal(socketfd);
401}
402
403void
404IfaceMgr::deleteExternalSocketInternal(int socketfd) {
405 if (check_thread_id_ && std::this_thread::get_id() != id_) {
407 .arg(socketfd)
408 .arg(std::this_thread::get_id())
409 .arg(id_);
410 }
411 auto& idx = callbacks_.get<1>();
412 auto it = idx.find(socketfd);
413 if (it == idx.end()) {
415 .arg(socketfd);
416 return;
417 }
418 idx.erase(it);
419}
420
421bool
423 std::lock_guard<std::mutex> lock(callbacks_mutex_);
424 auto const& idx = callbacks_.get<1>();
425 auto const it = idx.find(fd);
426 return (it != idx.end());
427}
428
429bool
431 std::lock_guard<std::mutex> lock(callbacks_mutex_);
432 auto const& idx = callbacks_.get<1>();
433 auto const it = idx.find(fd);
434 if (it != idx.end()) {
435 return (it->unusable_);
436 }
437
438 return (false);
439}
440
441void
443 if (check_thread_id_ && std::this_thread::get_id() != id_) {
445 .arg(std::this_thread::get_id())
446 .arg(id_);
447 }
448 std::lock_guard<std::mutex> lock(callbacks_mutex_);
449 callbacks_.clear();
450}
451
452std::list<int>
454 std::list<int> result;
455 std::lock_guard<std::mutex> lock(callbacks_mutex_);
456 for (SocketCallbackInfo const& s : callbacks_) {
457 result.push_back(s.socket_);
458 }
459 return (result);
460}
461
462void
464 // Do not allow null pointer.
465 if (!packet_filter) {
466 isc_throw(InvalidPacketFilter, "NULL packet filter object specified for"
467 " DHCPv4");
468 }
469 // Different packet filters use different socket types. It does not make
470 // sense to allow the change of packet filter when there are IPv4 sockets
471 // open because they can't be used by the receive/send functions of the
472 // new packet filter. Below, we check that there are no open IPv4 sockets.
473 // If we find at least one, we have to fail. However, caller still has a
474 // chance to replace the packet filter if he closes sockets explicitly.
475 if (hasOpenSocket(AF_INET)) {
476 // There is at least one socket open, so we have to fail.
478 "it is not allowed to set new packet"
479 << " filter when there are open IPv4 sockets - need"
480 << " to close them first");
481 }
482 // Everything is fine, so replace packet filter.
483 packet_filter_ = packet_filter;
484}
485
486void
488 if (!packet_filter) {
489 isc_throw(InvalidPacketFilter, "NULL packet filter object specified for"
490 " DHCPv6");
491 }
492
493 if (hasOpenSocket(AF_INET6)) {
494 // There is at least one socket open, so we have to fail.
496 "it is not allowed to set new packet"
497 << " filter when there are open IPv6 sockets - need"
498 << " to close them first");
499 }
500 // Everything is fine, so replace packet filter.
501 packet_filter6_ = packet_filter;
502}
503
504bool
505IfaceMgr::hasOpenSocket(const uint16_t family) const {
506 // Iterate over all interfaces and search for open sockets.
507 for (const IfacePtr& iface : ifaces_) {
508 for (const SocketInfo& sock : iface->getSockets()) {
509 // Check if the socket matches specified family.
510 if (sock.family_ == family) {
511 // There is at least one socket open, so return.
512 return (true);
513 }
514 }
515 }
516 // There are no open sockets found for the specified family.
517 return (false);
518}
519
520bool
521IfaceMgr::hasOpenSocket(const IOAddress& addr, bool unicast) const {
522 // Fast track for IPv4 using bound addresses.
523 if (addr.isV4() && !bound_address_.empty()) {
524 return (bound_address_.count(addr.toUint32()) != 0);
525 }
526 // Iterate over all interfaces and search for open sockets.
527 for (const IfacePtr& iface : ifaces_) {
528 for (const SocketInfo& sock : iface->getSockets()) {
529 // Check if the socket address matches the specified address or
530 // if address is unspecified (in6addr_any).
531 if (sock.addr_ == addr) {
532 return (true);
533 } else if (sock.addr_.isV6Zero() && !unicast) {
534 // Handle the case that the address is unspecified (any).
535 // This happens only with IPv6 so we do not check IPv4.
536 // In this case, we should check if the specified address
537 // belongs to any of the interfaces.
538 for (const IfacePtr& it : ifaces_) {
539 for (const Iface::Address& a : it->getAddresses()) {
540 if (addr == a.get()) {
541 return (true);
542 }
543 }
544 }
545 // The address does not belongs to any interface.
546 return (false);
547 }
548 }
549 }
550 // There are no open sockets found for the specified family.
551 return (false);
552}
553
554bool
555IfaceMgr::openSockets4(const uint16_t port, const bool use_bcast,
556 IfaceMgrErrorMsgCallback error_handler,
557 const bool skip_opened) {
558 int count = 0;
559 int bcast_num = 0;
560
561 for (const IfacePtr& iface : ifaces_) {
562 // Clear any errors from previous socket opening.
563 iface->clearErrors();
564
565 // If the interface is inactive, there is nothing to do. Simply
566 // proceed to the next detected interface.
567 if (iface->inactive4_) {
568 continue;
569 }
570
571 // If the interface has been specified in the configuration that
572 // it should be used to listen the DHCP traffic we have to check
573 // that the interface configuration is valid and that the interface
574 // is not a loopback interface. In both cases, we want to report
575 // that the socket will not be opened.
576 // Relax the check when the loopback interface was explicitly
577 // allowed
578 if (iface->flag_loopback_ && !allow_loopback_) {
579 IFACEMGR_ERROR(SocketConfigError, error_handler, iface,
580 "must not open socket on the loopback"
581 " interface " << iface->getName());
582 continue;
583 }
584
585 if (!iface->flag_up_) {
586 IFACEMGR_ERROR(SocketConfigError, error_handler, iface,
587 "the interface " << iface->getName()
588 << " is down");
589 continue;
590 }
591
592 if (!iface->flag_running_) {
593 IFACEMGR_ERROR(SocketConfigError, error_handler, iface,
594 "the interface " << iface->getName()
595 << " is not running");
596 continue;
597 }
598
599 IOAddress out_address("0.0.0.0");
600 if (!iface->getAddress4(out_address)) {
601 IFACEMGR_ERROR(SocketConfigError, error_handler, iface,
602 "the interface " << iface->getName()
603 << " has no usable IPv4 addresses configured");
604 continue;
605 }
606
607 for (const Iface::Address& addr : iface->getAddresses()) {
608 // Skip non-IPv4 addresses and those that weren't selected..
609 if (addr.unspecified() || !addr.get().isV4()) {
610 continue;
611 }
612
613 // If selected interface is broadcast capable set appropriate
614 // options on the socket so as it can receive and send broadcast
615 // messages.
616 bool is_open_as_broadcast = iface->flag_broadcast_ && use_bcast;
617
618 // The DHCP server must have means to determine which interface
619 // the broadcast packets are coming from. This is achieved by
620 // binding a socket to the device (interface) and specialized
621 // packet filters (e.g. BPF and LPF) implement this mechanism.
622 // If the PktFilterInet (generic one) is used, the socket is
623 // bound to INADDR_ANY which effectively binds the socket to
624 // all addresses on all interfaces. So, only one of those can
625 // be opened. Currently, the direct response support is
626 // provided by the PktFilterLPF and PktFilterBPF, so by checking
627 // the support for direct response we actually determine that
628 // one of those objects is in use. For all other objects we
629 // assume that binding to the device is not supported and we
630 // cease opening sockets and display the appropriate message.
631 if (is_open_as_broadcast && !isDirectResponseSupported() && bcast_num > 0) {
632 IFACEMGR_ERROR(SocketConfigError, error_handler, iface,
633 "Binding socket to an interface is not"
634 " supported on this OS; therefore only"
635 " one socket listening to broadcast traffic"
636 " can be opened. Sockets will not be opened"
637 " on remaining interfaces");
638 continue;
639 }
640
641 // Skip the address that already has a bound socket. It allows
642 // for preventing bind errors or re-opening sockets.
643 if (!skip_opened || !IfaceMgr::hasOpenSocket(addr.get())) {
644 try {
645 // We haven't open any broadcast sockets yet, so we can
646 // open at least one more or
647 // not broadcast capable, do not set broadcast flags.
648 IfaceMgr::openSocket(iface->getName(), addr.get(), port,
649 is_open_as_broadcast,
650 is_open_as_broadcast);
651 } catch (const Exception& ex) {
652 IFACEMGR_ERROR(SocketConfigError, error_handler, iface,
653 "Failed to open socket on interface "
654 << iface->getName()
655 << ", reason: "
656 << ex.what());
657 continue;
658 }
659 }
660
661 if (is_open_as_broadcast) {
662 // Binding socket to an interface is not supported so we
663 // can't open any more broadcast sockets. Increase the
664 // number of open broadcast sockets.
665 ++bcast_num;
666 }
667
668 ++count;
669 }
670 }
671
672 // If we have open sockets, start the receiver.
673 if (count > 0) {
674 // Collects bound addresses.
676
677 // Starts the receiver thread (if queueing is enabled).
678 startDHCPReceiver(AF_INET);
679 }
680
681 return (count > 0);
682}
683
684bool
685IfaceMgr::openSockets6(const uint16_t port,
686 IfaceMgrErrorMsgCallback error_handler,
687 const bool skip_opened) {
688 int count = 0;
689
690 for (const IfacePtr& iface : ifaces_) {
691 // Clear any errors from previous socket opening.
692 iface->clearErrors();
693
694 // If the interface is inactive, there is nothing to do. Simply
695 // proceed to the next detected interface.
696 if (iface->inactive6_) {
697 continue;
698 }
699
700 // If the interface has been specified in the configuration that
701 // it should be used to listen the DHCP traffic we have to check
702 // that the interface configuration is valid and that the interface
703 // is not a loopback interface. In both cases, we want to report
704 // that the socket will not be opened.
705 // Relax the check when the loopback interface was explicitly
706 // allowed
707 if (iface->flag_loopback_ && !allow_loopback_) {
708 IFACEMGR_ERROR(SocketConfigError, error_handler, iface,
709 "must not open socket on the loopback"
710 " interface " << iface->getName());
711 continue;
712 } else if (!iface->flag_up_) {
713 IFACEMGR_ERROR(SocketConfigError, error_handler, iface,
714 "the interface " << iface->getName()
715 << " is down");
716 continue;
717 } else if (!iface->flag_running_) {
718 IFACEMGR_ERROR(SocketConfigError, error_handler, iface,
719 "the interface " << iface->getName()
720 << " is not running");
721 continue;
722 }
723
724 // Open unicast sockets if there are any unicast addresses defined
725 for (const Iface::Address& addr : iface->getUnicasts()) {
726 // Skip the address that already has a bound socket. It allows
727 // for preventing bind errors or re-opening sockets.
728 // The @ref IfaceMgr::hasOpenSocket(addr) does match the "::"
729 // address on BSD and Solaris on any interface, so we make sure that
730 // that interface actually has opened sockets by checking the number
731 // of sockets to be non zero.
732 if (!skip_opened || !IfaceMgr::hasOpenSocket(addr, true) ||
733 !iface->getSockets().size()) {
734 try {
735 IfaceMgr::openSocket(iface->getName(), addr, port, false, false);
736 } catch (const Exception& ex) {
737 IFACEMGR_ERROR(SocketConfigError, error_handler, iface,
738 "Failed to open unicast socket on interface "
739 << iface->getName()
740 << ", reason: " << ex.what());
741 continue;
742 }
743 }
744
745 count++;
746 }
747
748 for (const Iface::Address& addr : iface->getAddresses()) {
749 // Skip all but V6 addresses.
750 if (!addr.get().isV6()) {
751 continue;
752 }
753
754 // Bind link-local addresses only. Otherwise we bind several sockets
755 // on interfaces that have several global addresses. For examples
756 // with interface with 2 global addresses, we would bind 3 sockets
757 // (one for link-local and two for global). That would result in
758 // getting each message 3 times.
759 if (!addr.get().isV6LinkLocal()) {
760 continue;
761 }
762
763 // Run OS-specific function to open a socket capable of receiving
764 // packets sent to All_DHCP_Relay_Agents_and_Servers multicast
765 // address.
766
767 // Skip the address that already has a bound socket. It allows
768 // for preventing bind errors or re-opening sockets.
769 // The @ref IfaceMgr::hasOpenSocket(addr) does match the "::"
770 // address on BSD and Solaris on any interface, so we make sure that
771 // the interface actually has opened sockets by checking the number
772 // of sockets to be non zero.
773 if (!skip_opened || !IfaceMgr::hasOpenSocket(addr) ||
774 iface->getSockets().size() <= iface->getUnicasts().size()) {
775 try {
776 // Pass a null pointer as an error handler to avoid
777 // suppressing an exception in a system-specific function.
778 IfaceMgr::openMulticastSocket(*iface, addr, port);
779 } catch (const Exception& ex) {
780 IFACEMGR_ERROR(SocketConfigError, error_handler, iface,
781 "Failed to open multicast socket on interface "
782 << iface->getName() << ", reason: " << ex.what());
783 continue;
784 }
785 }
786
787 ++count;
788 }
789 }
790
791 // If we have open sockets, start the receiver.
792 if (count > 0) {
793 // starts the receiver thread (if queueing is enabled).
794 startDHCPReceiver(AF_INET6);
795 }
796 return (count > 0);
797}
798
799void
800IfaceMgr::startDHCPReceiver(const uint16_t family) {
801 if (isDHCPReceiverRunning()) {
802 isc_throw(InvalidOperation, "a receiver thread already exists");
803 }
804
805 switch (family) {
806 case AF_INET:
807 // If the queue doesn't exist, packet queing has been configured
808 // as disabled. If there is no queue, we do not create a receiver.
809 if(!getPacketQueue4()) {
810 return;
811 }
812
813 dhcp_receiver_.reset(new WatchedThread());
814 dhcp_receiver_->start(std::bind(&IfaceMgr::receiveDHCP4Packets, this));
815 break;
816 case AF_INET6:
817 // If the queue doesn't exist, packet queing has been configured
818 // as disabled. If there is no queue, we do not create a receiver.
819 if(!getPacketQueue6()) {
820 return;
821 }
822
823 dhcp_receiver_.reset(new WatchedThread());
824 dhcp_receiver_->start(std::bind(&IfaceMgr::receiveDHCP6Packets, this));
825 break;
826 default:
827 isc_throw (BadValue, "startDHCPReceiver: invalid family: " << family);
828 break;
829 }
830}
831
832void
834 for (const IfacePtr& existing : ifaces_) {
835 if ((existing->getName() == iface->getName()) ||
836 (existing->getIndex() == iface->getIndex())) {
837 isc_throw(Unexpected, "Can't add " << iface->getFullName() <<
838 " when " << existing->getFullName() <<
839 " already exists.");
840 }
841 }
842 ifaces_.push_back(iface);
843}
844
845void
846IfaceMgr::printIfaces(std::ostream& out /*= std::cout*/) {
847 for (const IfacePtr& iface : ifaces_) {
848 const Iface::AddressCollection& addrs = iface->getAddresses();
849
850 out << "Detected interface " << iface->getFullName()
851 << ", hwtype=" << iface->getHWType()
852 << ", mac=" << iface->getPlainMac();
853 out << ", flags=" << hex << iface->flags_ << dec << "("
854 << (iface->flag_loopback_?"LOOPBACK ":"")
855 << (iface->flag_up_?"UP ":"")
856 << (iface->flag_running_?"RUNNING ":"")
857 << (iface->flag_multicast_?"MULTICAST ":"")
858 << (iface->flag_broadcast_?"BROADCAST ":"")
859 << ")" << endl;
860 out << " " << addrs.size() << " addr(s):";
861
862 for (const Iface::Address& addr : addrs) {
863 out << " " << addr.get().toText();
864 }
865 out << endl;
866 }
867}
868
870IfaceCollection::getIface(const unsigned int ifindex) {
871 return (getIfaceInternal(ifindex, MultiThreadingMgr::instance().getMode()));
872}
873
875IfaceCollection::getIface(const std::string& ifname) {
876 return (getIfaceInternal(ifname, MultiThreadingMgr::instance().getMode()));
877}
878
880IfaceCollection::getIfaceInternal(const unsigned int ifindex, const bool need_lock) {
881 if (ifindex == UNSET_IFINDEX) {
882 isc_throw(BadValue, "interface index was not set");
883 }
884 if (need_lock) {
885 lock_guard<mutex> lock(mutex_);
886 if (cache_ && (cache_->getIndex() == ifindex)) {
887 return (cache_);
888 }
889 } else {
890 if (cache_ && (cache_->getIndex() == ifindex)) {
891 return (cache_);
892 }
893 }
894 auto const& idx = ifaces_container_.get<1>();
895 auto it = idx.find(ifindex);
896 if (it == idx.end()) {
897 return (IfacePtr()); // not found
898 }
899 if (need_lock) {
900 lock_guard<mutex> lock(mutex_);
901 cache_ = *it;
902 return (cache_);
903 } else {
904 cache_ = *it;
905 return (cache_);
906 }
907}
908
910IfaceCollection::getIfaceInternal(const std::string& ifname, const bool need_lock) {
911 if (need_lock) {
912 lock_guard<mutex> lock(mutex_);
913 if (cache_ && (cache_->getName() == ifname)) {
914 return (cache_);
915 }
916 } else {
917 if (cache_ && (cache_->getName() == ifname)) {
918 return (cache_);
919 }
920 }
921 auto const& idx = ifaces_container_.get<2>();
922 auto it = idx.find(ifname);
923 if (it == idx.end()) {
924 return (IfacePtr()); // not found
925 }
926 if (need_lock) {
927 lock_guard<mutex> lock(mutex_);
928 cache_ = *it;
929 return (cache_);
930 } else {
931 cache_ = *it;
932 return (cache_);
933 }
934}
935
937IfaceMgr::getIface(const unsigned int ifindex) {
938 return (ifaces_.getIface(ifindex));
939}
940
942IfaceMgr::getIface(const std::string& ifname) {
943 if (ifname.empty()) {
944 return (IfacePtr()); // empty
945 }
946 return (ifaces_.getIface(ifname));
947}
948
951 if (pkt->indexSet()) {
952 return (getIface(pkt->getIndex()));
953 } else {
954 return (getIface(pkt->getIface()));
955 }
956}
957
958void
960 ifaces_.clear();
961}
962
963void
967
968void
969IfaceMgr::handleClosedExternalSocket(SocketCallbackInfoIterator it) {
970 errno = 0;
971 if (fcntl(it->socket_, F_GETFD) < 0 && (errno == EBADF)) {
972 SocketCallbackInfo x(*it);
973 x.unusable_ = true;
974 callbacks_.replace(it, x);
975 isc_throw(SocketFDError, "unexpected state (closed) for fd: " << x.socket_);
976 }
977}
978
979void
980IfaceMgr::handleClosedExternalSockets() {
981 std::lock_guard<std::mutex> lock(callbacks_mutex_);
982 for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
983 if (it->unusable_) {
984 continue;
985 }
986 handleClosedExternalSocket(it);
987 }
988}
989
990void
991IfaceMgr::handleIfaceSocketError(const IfacePtr& iface, const SocketInfo& s) {
992 int error = 0;
993 socklen_t opt_size = sizeof(error);
994 errno = 0;
995 if (getsockopt(s.sockfd_, SOL_SOCKET, SO_ERROR,
996 reinterpret_cast<char*>(&error), &opt_size) < 0) {
997 if ((errno == ENOTSOCK) || (errno == ENOPROTOOPT)) {
998 // Simply not a socket or SO_ERROR is not supported.
999 return;
1000 }
1001 isc_throw(BadValue, "Can't get socket error fd: "
1002 << s.sockfd_ << " - error: " << strerror(errno));
1003 }
1004 if (error > 0) {
1006 .arg(s.sockfd_)
1007 .arg(iface->getFullName())
1008 .arg(strerror(error));
1009 }
1010}
1011
1012void
1014 for (const IfacePtr& iface : ifaces_) {
1015 for (const SocketInfo& sock : iface->getSockets()) {
1016 const IOAddress& addr = sock.addr_;
1017 if (!addr.isV4()) {
1018 continue;
1019 }
1020 if (bound_address_.count(addr.toUint32()) == 0) {
1021 bound_address_.insert(addr);
1022 }
1023 }
1024 }
1025}
1026
1027void
1029 for (const IfacePtr& iface : ifaces_) {
1030 iface->clearUnicasts();
1031 }
1032}
1033
1034int IfaceMgr::openSocket(const std::string& ifname, const IOAddress& addr,
1035 const uint16_t port, const bool receive_bcast,
1036 const bool send_bcast) {
1037 IfacePtr iface = getIface(ifname);
1038 if (!iface) {
1039 isc_throw(BadValue, "There is no " << ifname << " interface present.");
1040 }
1041 int status = 0;
1042 if (addr.isV4()) {
1043 status = openSocket4(*iface, addr, port, receive_bcast, send_bcast);
1044
1045 } else if (addr.isV6()) {
1046 status = openSocket6(*iface, addr, port, receive_bcast);
1047
1048 } else {
1049 isc_throw(BadValue, "Failed to detect family of address: "
1050 << addr);
1051 }
1053 .arg(ifname)
1054 .arg(addr.toText())
1055 .arg(port);
1056 return (status);
1057}
1058
1059int IfaceMgr::openSocketFromIface(const std::string& ifname,
1060 const uint16_t port,
1061 const uint8_t family) {
1062 // Search for specified interface among detected interfaces.
1063 for (const IfacePtr& iface : ifaces_) {
1064 if ((iface->getFullName() != ifname) &&
1065 (iface->getName() != ifname)) {
1066 continue;
1067 }
1068
1069 // Interface is now detected. Search for address on interface
1070 // that matches address family (v6 or v4).
1071 Iface::AddressCollection addrs = iface->getAddresses();
1072 Iface::AddressCollection::iterator addr_it = addrs.begin();
1073 while (addr_it != addrs.end()) {
1074 if (addr_it->get().getFamily() == family) {
1075 // We have interface and address so let's open socket.
1076 // This may cause isc::Unexpected exception.
1077 return (openSocket(iface->getName(), *addr_it, port, false));
1078 }
1079 ++addr_it;
1080 }
1081 // If we are at the end of address collection it means that we found
1082 // interface but there is no address for family specified.
1083 if (addr_it == addrs.end()) {
1084 // Stringify the family value to append it to exception string.
1085 std::string family_name("AF_INET");
1086 if (family == AF_INET6) {
1087 family_name = "AF_INET6";
1088 }
1089 // We did not find address on the interface.
1090 isc_throw(SocketConfigError, "There is no address for interface: "
1091 << ifname << ", port: " << port << ", address "
1092 " family: " << family_name);
1093 }
1094 }
1095 // If we got here it means that we had not found the specified interface.
1096 // Otherwise we would have returned from previous exist points.
1097 isc_throw(BadValue, "There is no " << ifname << " interface present.");
1098}
1099
1101 const uint16_t port) {
1102 // Search through detected interfaces and addresses to match
1103 // local address we got.
1104 for (const IfacePtr& iface : ifaces_) {
1105 for (const Iface::Address& a : iface->getAddresses()) {
1106
1107 // Local address must match one of the addresses
1108 // on detected interfaces. If it does, we have
1109 // address and interface detected so we can open
1110 // socket.
1111 if (a.get() == addr) {
1112 // Open socket using local interface, address and port.
1113 // This may cause isc::Unexpected exception.
1114 return (openSocket(iface->getName(), a, port, false));
1115 }
1116 }
1117 }
1118 // If we got here it means that we did not find specified address
1119 // on any available interface.
1120 isc_throw(BadValue, "There is no such address " << addr);
1121}
1122
1124 const uint16_t port) {
1125 try {
1126 // Get local address to be used to connect to remote location.
1127 IOAddress local_address(getLocalAddress(remote_addr, port));
1128 return openSocketFromAddress(local_address, port);
1129 } catch (const Exception& e) {
1131 }
1132}
1133
1135IfaceMgr::getLocalAddress(const IOAddress& remote_addr, const uint16_t port) {
1136 // Create remote endpoint, we will be connecting to it.
1137 boost::scoped_ptr<const UDPEndpoint>
1138 remote_endpoint(static_cast<const UDPEndpoint*>
1139 (UDPEndpoint::create(IPPROTO_UDP, remote_addr, port)));
1140 if (!remote_endpoint) {
1141 isc_throw(Unexpected, "Unable to create remote endpoint");
1142 }
1143
1144 // Create socket that will be used to connect to remote endpoint.
1145 boost::asio::io_context io_service;
1146 boost::asio::ip::udp::socket sock(io_service);
1147
1148 boost::system::error_code err_code;
1149 // If remote address is broadcast address we have to
1150 // allow this on the socket.
1151 if (remote_addr.isV4() &&
1152 (remote_addr == IOAddress(DHCP_IPV4_BROADCAST_ADDRESS))) {
1153 // Socket has to be open prior to setting the broadcast
1154 // option. Otherwise set_option will complain about
1155 // bad file descriptor.
1156
1157 // @todo: We don't specify interface in any way here. 255.255.255.255
1158 // We can very easily end up with a socket working on a different
1159 // interface.
1160
1161 // zero out the errno to be safe
1162 errno = 0;
1163
1164 sock.open(boost::asio::ip::udp::v4(), err_code);
1165 if (err_code) {
1166 const char* errstr = strerror(errno);
1167 isc_throw(Unexpected, "failed to open UDPv4 socket, reason:"
1168 << errstr);
1169 }
1170 sock.set_option(boost::asio::socket_base::broadcast(true), err_code);
1171 if (err_code) {
1172 sock.close();
1173 isc_throw(Unexpected, "failed to enable broadcast on the socket");
1174 }
1175 }
1176
1177 // Try to connect to remote endpoint and check if attempt is successful.
1178 sock.connect(remote_endpoint->getASIOEndpoint(), err_code);
1179 if (err_code) {
1180 sock.close();
1181 isc_throw(Unexpected, "failed to connect to remote endpoint.");
1182 }
1183
1184 // Once we are connected socket object holds local endpoint.
1185 boost::asio::ip::udp::socket::endpoint_type local_endpoint =
1186 sock.local_endpoint();
1187 boost::asio::ip::address local_address(local_endpoint.address());
1188
1189 // Close the socket.
1190 sock.close();
1191
1192 // Return address of local endpoint.
1193 return IOAddress(local_address);
1194}
1195
1196int
1197IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, const uint16_t port,
1198 const bool receive_bcast, const bool send_bcast) {
1199 // Assuming that packet filter is not null, because its modifier checks it.
1200 SocketInfo info = packet_filter_->openSocket(iface, addr, port,
1201 receive_bcast, send_bcast);
1202 iface.addSocket(info);
1203
1204 return (info.sockfd_);
1205}
1206
1207bool
1209 IfacePtr iface = getIface(pkt);
1210 if (!iface) {
1211 isc_throw(BadValue, "Unable to send DHCPv6 message. Invalid interface ("
1212 << pkt->getIface() << ") specified.");
1213 }
1214
1215 // Assuming that packet filter is not null, because its modifier checks it.
1216 // The packet filter returns an int but in fact it either returns 0 or throws.
1217 return (packet_filter6_->send(*iface, getSocket(pkt), pkt) == 0);
1218}
1219
1220bool
1222 IfacePtr iface = getIface(pkt);
1223 if (!iface) {
1224 isc_throw(BadValue, "Unable to send DHCPv4 message. Invalid interface ("
1225 << pkt->getIface() << ") specified.");
1226 }
1227
1228 // Assuming that packet filter is not null, because its modifier checks it.
1229 // The packet filter returns an int but in fact it either returns 0 or throws.
1230 return (packet_filter_->send(*iface, getSocket(pkt).sockfd_, pkt) == 0);
1231}
1232
1233Pkt4Ptr IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
1234 if (isDHCPReceiverRunning()) {
1235 return (receive4Indirect(timeout_sec, timeout_usec));
1236 }
1237
1238 return (receive4Direct(timeout_sec, timeout_usec));
1239}
1240
1241Pkt4Ptr IfaceMgr::receive4Indirect(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
1242 // Sanity check for microsecond timeout.
1243 if (timeout_usec >= 1000000) {
1244 isc_throw(BadValue, "fractional timeout must be shorter than"
1245 " one million microseconds");
1246 }
1247
1248 fd_event_handler_->clear();
1249
1250 // if there are any callbacks for external sockets registered...
1251 {
1252 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1253 if (!callbacks_.empty()) {
1254 for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1255 if (it->unusable_) {
1256 continue;
1257 }
1258 handleClosedExternalSocket(it);
1259 // Add this socket to listening set
1260 fd_event_handler_->add(it->socket_);
1261 }
1262 }
1263 }
1264
1265 // Add Receiver ready watch socket
1266 fd_event_handler_->add(dhcp_receiver_->getWatchFd(WatchedThread::READY));
1267
1268 // Add Receiver error watch socket
1269 fd_event_handler_->add(dhcp_receiver_->getWatchFd(WatchedThread::ERROR));
1270
1271 // Set timeout for our next select() call. If there are
1272 // no DHCP packets to read, then we'll wait for a finite
1273 // amount of time for an IO event. Otherwise, we'll
1274 // poll (timeout = 0 secs). We need to poll, even if
1275 // DHCP packets are waiting so we don't starve external
1276 // sockets under heavy DHCP load.
1277 if (!getPacketQueue4()->empty()) {
1278 timeout_sec = 0;
1279 timeout_usec = 0;
1280 }
1281
1282 // zero out the errno to be safe
1283 errno = 0;
1284
1285 int result = fd_event_handler_->waitEvent(timeout_sec, timeout_usec);
1286
1287 if ((result == 0) && getPacketQueue4()->empty()) {
1288 // nothing received and timeout has been reached
1289 return (Pkt4Ptr());
1290 } else if (result < 0) {
1291 // In most cases we would like to know whether select() returned
1292 // an error because of a signal being received or for some other
1293 // reason. This is because DHCP servers use signals to trigger
1294 // certain actions, like reconfiguration or graceful shutdown.
1295 // By catching a dedicated exception the caller will know if the
1296 // error returned by the function is due to the reception of the
1297 // signal or for some other reason.
1298 if (errno == EINTR) {
1299 isc_throw(SignalInterruptOnSelect, strerror(errno));
1300 } else if (errno == EBADF) {
1301 handleClosedExternalSockets();
1302 isc_throw(SocketFDError, strerror(EBADF));
1303 }
1304 isc_throw(SocketReadError, strerror(errno));
1305 }
1306
1307 // We only check external sockets if select detected an event.
1308 if (result > 0) {
1309 {
1310 std::lock_guard<std::mutex> lk(receiver_mutex_);
1311 // Check for receiver thread read errors.
1312 if (dhcp_receiver_->isReady(WatchedThread::ERROR)) {
1313 string msg = dhcp_receiver_->getLastError();
1314 dhcp_receiver_->clearReady(WatchedThread::ERROR);
1316 }
1317 }
1318
1319 // Let's find out which external socket has the data
1320 boost::scoped_ptr<SocketCallbackInfo> ex_sock;
1321 bool found = false;
1322 {
1323 std::list<SocketCallbackInfoIterator> to_reloc;
1324 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1325 for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1326 if (it->unusable_) {
1327 continue;
1328 }
1329 handleClosedExternalSocket(it);
1330 if (fd_event_handler_->readReady(it->socket_) ||
1331 fd_event_handler_->hasError(it->socket_)) {
1332 found = true;
1333 to_reloc.push_back(it);
1334
1335 // something received over external socket
1336 if (it->callback_) {
1337 // Note the external socket to call its callback without
1338 // the lock taken so it can be deleted.
1339 ex_sock.reset(new SocketCallbackInfo(*it));
1340 break;
1341 }
1342 }
1343 }
1344 if (found) {
1345 for (auto it : to_reloc) {
1346 callbacks_.relocate(callbacks_.end(), it);
1347 }
1348 }
1349 }
1350
1351 if (ex_sock && ex_sock->callback_) {
1352 // Calling the external socket's callback provides its service
1353 // layer access without integrating any specific features
1354 // in IfaceMgr
1355 ex_sock->callback_(ex_sock->socket_);
1356 }
1357 }
1358
1359 // If we're here it should only be because there are DHCP packets waiting.
1360 std::lock_guard<std::mutex> lk(receiver_mutex_);
1361 Pkt4Ptr pkt = getPacketQueue4()->dequeuePacket();
1362 if (!pkt) {
1363 dhcp_receiver_->clearReady(WatchedThread::READY);
1364 }
1365
1366 return (pkt);
1367}
1368
1369Pkt4Ptr IfaceMgr::receive4Direct(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
1370 // Sanity check for microsecond timeout.
1371 if (timeout_usec >= 1000000) {
1372 isc_throw(BadValue, "fractional timeout must be shorter than"
1373 " one million microseconds");
1374 }
1375
1376 fd_event_handler_->clear();
1377
1383 for (const IfacePtr& iface : ifaces_) {
1384 for (const SocketInfo& s : iface->getSockets()) {
1385 // Only deal with IPv4 addresses.
1386 if (s.addr_.isV4()) {
1387 // Add this socket to listening set
1388 fd_event_handler_->add(s.sockfd_);
1389 }
1390 }
1391 }
1392
1393 // if there are any callbacks for external sockets registered...
1394 {
1395 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1396 if (!callbacks_.empty()) {
1397 for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1398 if (it->unusable_) {
1399 continue;
1400 }
1401 handleClosedExternalSocket(it);
1402 // Add this socket to listening set
1403 fd_event_handler_->add(it->socket_);
1404 }
1405 }
1406 }
1407
1408 // zero out the errno to be safe
1409 errno = 0;
1410
1411 int result = fd_event_handler_->waitEvent(timeout_sec, timeout_usec);
1412
1413 if (result == 0) {
1414 // nothing received and timeout has been reached
1415 return (Pkt4Ptr()); // null
1416 } else if (result < 0) {
1417 // In most cases we would like to know whether select() returned
1418 // an error because of a signal being received or for some other
1419 // reason. This is because DHCP servers use signals to trigger
1420 // certain actions, like reconfiguration or graceful shutdown.
1421 // By catching a dedicated exception the caller will know if the
1422 // error returned by the function is due to the reception of the
1423 // signal or for some other reason.
1424 if (errno == EINTR) {
1425 isc_throw(SignalInterruptOnSelect, strerror(errno));
1426 } else if (errno == EBADF) {
1427 handleClosedExternalSockets();
1428 isc_throw(SocketFDError, strerror(EBADF));
1429 }
1430 isc_throw(SocketReadError, strerror(errno));
1431 }
1432
1433 // Let's find out which socket has the data
1434 boost::scoped_ptr<SocketCallbackInfo> ex_sock;
1435 bool found = false;
1436 {
1437 std::list<SocketCallbackInfoIterator> to_reloc;
1438 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1439 for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1440 if (it->unusable_) {
1441 continue;
1442 }
1443 handleClosedExternalSocket(it);
1444 if (fd_event_handler_->readReady(it->socket_) ||
1445 fd_event_handler_->hasError(it->socket_)) {
1446 found = true;
1447 to_reloc.push_back(it);
1448
1449 // something received over external socket
1450 if (it->callback_) {
1451 // Note the external socket to call its callback without
1452 // the lock taken so it can be deleted.
1453 ex_sock.reset(new SocketCallbackInfo(*it));
1454 break;
1455 }
1456 }
1457 }
1458 if (found) {
1459 for (auto it : to_reloc) {
1460 callbacks_.relocate(callbacks_.end(), it);
1461 }
1462 }
1463 }
1464
1465 if (ex_sock && ex_sock->callback_) {
1466 // Calling the external socket's callback provides its service
1467 // layer access without integrating any specific features
1468 // in IfaceMgr
1469 ex_sock->callback_(ex_sock->socket_);
1470 }
1471
1472 // Let's find out which interface/socket has the data
1473 boost::scoped_ptr<SocketInfo> candidate;
1474 IfacePtr recv_if;
1475 std::list<IfaceCollection::LruIterator> ifaces_to_reloc;
1476 IfaceCollection::LruIndex& iidx = ifaces_.getLru();
1477 for (auto iit = iidx.begin(); iit != iidx.end(); ++iit) {
1478 std::list<Iface::SocketLruIterator> sockets_to_reloc;
1479 Iface::SocketCollection& sockets = (*iit)->getSocketsRef();
1480 Iface::SocketLruIndex& sidx = sockets.get<1>();
1481 for (auto sit = sidx.begin(); sit != sidx.end(); ++sit) {
1482 if (!fd_event_handler_->readReady(sit->sockfd_) &&
1483 !fd_event_handler_->hasError(sit->sockfd_)) {
1484 continue;
1485 }
1486 ifaces_to_reloc.push_back(iit);
1487 sockets_to_reloc.push_back(sit);
1488 if (fd_event_handler_->hasError(sit->sockfd_)) {
1489 handleIfaceSocketError(*iit, *sit);
1490 }
1491 candidate.reset(new SocketInfo(*sit));
1492 break;
1493 }
1494 if (!sockets_to_reloc.empty()) {
1495 for (auto it : sockets_to_reloc) {
1496 sidx.relocate(sidx.end(), it);
1497 }
1498 }
1499 if (candidate) {
1500 recv_if = *iit;
1501 break;
1502 }
1503 }
1504 if (!ifaces_to_reloc.empty()) {
1505 for (auto it : ifaces_to_reloc) {
1506 iidx.relocate(iidx.end(), it);
1507 }
1508 }
1509
1510 if (!candidate || !recv_if) {
1512 return (Pkt4Ptr());
1513 }
1514
1515 // Check that we have something to read.
1516 int len;
1517 if (ioctl(candidate->sockfd_, FIONREAD, &len) < 0) {
1518 isc_throw(SocketReadError, strerror(errno));
1519 }
1520 if (len == 0) {
1521 // Nothing to read.
1522 return (Pkt4Ptr());
1523 }
1524
1525 // Assuming that packet filter is not null, because its modifier checks it.
1526 return (packet_filter_->receive(*recv_if, *candidate));
1527}
1528
1529Pkt6Ptr
1530IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
1531 if (isDHCPReceiverRunning()) {
1532 return (receive6Indirect(timeout_sec, timeout_usec));
1533 }
1534
1535 return (receive6Direct(timeout_sec, timeout_usec));
1536}
1537
1538Pkt6Ptr
1539IfaceMgr::receive6Direct(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */ ) {
1540 // Sanity check for microsecond timeout.
1541 if (timeout_usec >= 1000000) {
1542 isc_throw(BadValue, "fractional timeout must be shorter than"
1543 " one million microseconds");
1544 }
1545
1546 fd_event_handler_->clear();
1547
1553 for (const IfacePtr& iface : ifaces_) {
1554 for (const SocketInfo& s : iface->getSockets()) {
1555 // Only deal with IPv6 addresses.
1556 if (s.addr_.isV6()) {
1557 // Add this socket to listening set
1558 fd_event_handler_->add(s.sockfd_);
1559 }
1560 }
1561 }
1562
1563 // if there are any callbacks for external sockets registered...
1564 {
1565 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1566 if (!callbacks_.empty()) {
1567 for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1568 if (it->unusable_) {
1569 continue;
1570 }
1571 handleClosedExternalSocket(it);
1572 // Add this socket to listening set
1573 fd_event_handler_->add(it->socket_);
1574 }
1575 }
1576 }
1577
1578 // zero out the errno to be safe
1579 errno = 0;
1580
1581 int result = fd_event_handler_->waitEvent(timeout_sec, timeout_usec);
1582
1583 if (result == 0) {
1584 // nothing received and timeout has been reached
1585 return (Pkt6Ptr()); // null
1586 } else if (result < 0) {
1587 // In most cases we would like to know whether select() returned
1588 // an error because of a signal being received or for some other
1589 // reason. This is because DHCP servers use signals to trigger
1590 // certain actions, like reconfiguration or graceful shutdown.
1591 // By catching a dedicated exception the caller will know if the
1592 // error returned by the function is due to the reception of the
1593 // signal or for some other reason.
1594 if (errno == EINTR) {
1595 isc_throw(SignalInterruptOnSelect, strerror(errno));
1596 } else if (errno == EBADF) {
1597 handleClosedExternalSockets();
1598 isc_throw(SocketFDError, strerror(EBADF));
1599 }
1600 isc_throw(SocketReadError, strerror(errno));
1601 }
1602
1603 // Let's find out which socket has the data
1604 boost::scoped_ptr<SocketCallbackInfo> ex_sock;
1605 bool found = false;
1606 {
1607 std::list<SocketCallbackInfoIterator> to_reloc;
1608 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1609 for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1610 if (it->unusable_) {
1611 continue;
1612 }
1613 handleClosedExternalSocket(it);
1614 if (fd_event_handler_->readReady(it->socket_) ||
1615 fd_event_handler_->hasError(it->socket_)) {
1616 found = true;
1617 to_reloc.push_back(it);
1618
1619 // something received over external socket
1620 if (it->callback_) {
1621 // Note the external socket to call its callback without
1622 // the lock taken so it can be deleted.
1623 ex_sock.reset(new SocketCallbackInfo(*it));
1624 break;
1625 }
1626 }
1627 }
1628 if (found) {
1629 for (auto it : to_reloc) {
1630 callbacks_.relocate(callbacks_.end(), it);
1631 }
1632 }
1633 }
1634
1635 if (ex_sock && ex_sock->callback_) {
1636 // Calling the external socket's callback provides its service
1637 // layer access without integrating any specific features
1638 // in IfaceMgr
1639 ex_sock->callback_(ex_sock->socket_);
1640 }
1641
1642 // Let's find out which interface/socket has the data
1643 boost::scoped_ptr<SocketInfo> candidate;
1644 IfacePtr recv_if;
1645 std::list<IfaceCollection::LruIterator> ifaces_to_reloc;
1646 IfaceCollection::LruIndex& iidx = ifaces_.getLru();
1647 for (auto iit = iidx.begin(); iit != iidx.end(); ++iit) {
1648 std::list<Iface::SocketLruIterator> sockets_to_reloc;
1649 Iface::SocketCollection& sockets = (*iit)->getSocketsRef();
1650 Iface::SocketLruIndex& sidx = sockets.get<1>();
1651 for (auto sit = sidx.begin(); sit != sidx.end(); ++sit) {
1652 if (!fd_event_handler_->readReady(sit->sockfd_) &&
1653 !fd_event_handler_->hasError(sit->sockfd_)) {
1654 continue;
1655 }
1656 ifaces_to_reloc.push_back(iit);
1657 sockets_to_reloc.push_back(sit);
1658 if (fd_event_handler_->hasError(sit->sockfd_)) {
1659 handleIfaceSocketError(*iit, *sit);
1660 }
1661 candidate.reset(new SocketInfo(*sit));
1662 break;
1663 }
1664 if (!sockets_to_reloc.empty()) {
1665 for (auto it : sockets_to_reloc) {
1666 sidx.relocate(sidx.end(), it);
1667 }
1668 }
1669 if (candidate) {
1670 recv_if = *iit;
1671 break;
1672 }
1673 }
1674 if (!ifaces_to_reloc.empty()) {
1675 for (auto it : ifaces_to_reloc) {
1676 iidx.relocate(iidx.end(), it);
1677 }
1678 }
1679
1680 if (!candidate) {
1682 return (Pkt6Ptr());
1683 }
1684
1685 // Check that we have something to read.
1686 int len;
1687 if (ioctl(candidate->sockfd_, FIONREAD, &len) < 0) {
1688 isc_throw(SocketReadError, strerror(errno));
1689 }
1690 if (len == 0) {
1691 // Nothing to read.
1692 return (Pkt6Ptr());
1693 }
1694
1695 // Assuming that packet filter is not null, because its modifier checks it.
1696 return (packet_filter6_->receive(*candidate));
1697}
1698
1699Pkt6Ptr
1700IfaceMgr::receive6Indirect(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */ ) {
1701 // Sanity check for microsecond timeout.
1702 if (timeout_usec >= 1000000) {
1703 isc_throw(BadValue, "fractional timeout must be shorter than"
1704 " one million microseconds");
1705 }
1706
1707 fd_event_handler_->clear();
1708
1709 // if there are any callbacks for external sockets registered...
1710 {
1711 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1712 if (!callbacks_.empty()) {
1713 for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1714 if (it->unusable_) {
1715 continue;
1716 }
1717 handleClosedExternalSocket(it);
1718 // Add this socket to listening set
1719 fd_event_handler_->add(it->socket_);
1720 }
1721 }
1722 }
1723
1724 // Add Receiver ready watch socket
1725 fd_event_handler_->add(dhcp_receiver_->getWatchFd(WatchedThread::READY));
1726
1727 // Add Receiver error watch socket
1728 fd_event_handler_->add(dhcp_receiver_->getWatchFd(WatchedThread::ERROR));
1729
1730 // Set timeout for our next select() call. If there are
1731 // no DHCP packets to read, then we'll wait for a finite
1732 // amount of time for an IO event. Otherwise, we'll
1733 // poll (timeout = 0 secs). We need to poll, even if
1734 // DHCP packets are waiting so we don't starve external
1735 // sockets under heavy DHCP load.
1736 if (!getPacketQueue6()->empty()) {
1737 timeout_sec = 0;
1738 timeout_usec = 0;
1739 }
1740
1741 // zero out the errno to be safe
1742 errno = 0;
1743
1744 int result = fd_event_handler_->waitEvent(timeout_sec, timeout_usec);
1745
1746 if ((result == 0) && getPacketQueue6()->empty()) {
1747 // nothing received and timeout has been reached
1748 return (Pkt6Ptr());
1749 } else if (result < 0) {
1750 // In most cases we would like to know whether select() returned
1751 // an error because of a signal being received or for some other
1752 // reason. This is because DHCP servers use signals to trigger
1753 // certain actions, like reconfiguration or graceful shutdown.
1754 // By catching a dedicated exception the caller will know if the
1755 // error returned by the function is due to the reception of the
1756 // signal or for some other reason.
1757 if (errno == EINTR) {
1758 isc_throw(SignalInterruptOnSelect, strerror(errno));
1759 } else if (errno == EBADF) {
1760 handleClosedExternalSockets();
1761 isc_throw(SocketFDError, strerror(EBADF));
1762 }
1763 isc_throw(SocketReadError, strerror(errno));
1764 }
1765
1766 // We only check external sockets if select detected an event.
1767 if (result > 0) {
1768 {
1769 std::lock_guard<std::mutex> lk(receiver_mutex_);
1770 // Check for receiver thread read errors.
1771 if (dhcp_receiver_->isReady(WatchedThread::ERROR)) {
1772 string msg = dhcp_receiver_->getLastError();
1773 dhcp_receiver_->clearReady(WatchedThread::ERROR);
1775 }
1776 }
1777
1778 // Let's find out which external socket has the data
1779 boost::scoped_ptr<SocketCallbackInfo> ex_sock;
1780 bool found = false;
1781 {
1782 std::list<SocketCallbackInfoIterator> to_reloc;
1783 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1784 for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1785 if (it->unusable_) {
1786 continue;
1787 }
1788 handleClosedExternalSocket(it);
1789 if (fd_event_handler_->readReady(it->socket_) ||
1790 fd_event_handler_->hasError(it->socket_)) {
1791 found = true;
1792 to_reloc.push_back(it);
1793
1794 // something received over external socket
1795 if (it->callback_) {
1796 // Note the external socket to call its callback without
1797 // the lock taken so it can be deleted.
1798 ex_sock.reset(new SocketCallbackInfo(*it));
1799 break;
1800 }
1801 }
1802 }
1803 if (found) {
1804 for (auto it : to_reloc) {
1805 callbacks_.relocate(callbacks_.end(), it);
1806 }
1807 }
1808 }
1809
1810 if (ex_sock && ex_sock->callback_) {
1811 // Calling the external socket's callback provides its service
1812 // layer access without integrating any specific features
1813 // in IfaceMgr
1814 ex_sock->callback_(ex_sock->socket_);
1815 }
1816 }
1817
1818 // If we're here it should only be because there are DHCP packets waiting.
1819 std::lock_guard<std::mutex> lk(receiver_mutex_);
1820 Pkt6Ptr pkt = getPacketQueue6()->dequeuePacket();
1821 if (!pkt) {
1822 dhcp_receiver_->clearReady(WatchedThread::READY);
1823 }
1824
1825 return (pkt);
1826}
1827
1828void
1829IfaceMgr::scanReceiveDHCP4Packets() {
1830 // Let's find out which interface/socket has data.
1831 std::list<IfaceCollection::LruIterator> ifaces_to_reloc;
1833 try {
1834 for (auto iit = iidx.begin(); iit != iidx.end(); ++iit) {
1835 std::list<Iface::SocketLruIterator> sockets_to_reloc;
1836 Iface::SocketCollection& sockets = (*iit)->getSocketsRef();
1837 Iface::SocketLruIndex& sidx = sockets.get<1>();
1838 bool to_reloc = false;
1839 try {
1840 for (auto sit = sidx.begin(); sit != sidx.end(); ++sit) {
1841 if (!receiver_fd_event_handler_->readReady(sit->sockfd_) &&
1842 !receiver_fd_event_handler_->hasError(sit->sockfd_)) {
1843 continue;
1844 }
1845 if (!to_reloc) {
1846 ifaces_to_reloc.push_back(iit);
1847 to_reloc = true;
1848 }
1849 sockets_to_reloc.push_back(sit);
1850 if (receiver_fd_event_handler_->hasError(sit->sockfd_)) {
1851 handleIfaceSocketError(*iit, *sit);
1852 }
1853 receiveDHCP4Packet(**iit, *sit);
1854 // Can take time so check one more time the watch socket.
1855 if (dhcp_receiver_->shouldTerminate()) {
1856 isc_throw(ReceiveTerminate, "receiveDHCP4Packet");
1857 }
1858 }
1859 if (!sockets_to_reloc.empty()) {
1860 for (auto it : sockets_to_reloc) {
1861 sidx.relocate(sidx.end(), it);
1862 }
1863 }
1864 } catch (...) {
1865 if (!sockets_to_reloc.empty()) {
1866 for (auto it : sockets_to_reloc) {
1867 sidx.relocate(sidx.end(), it);
1868 }
1869 }
1870 throw;
1871 }
1872 }
1873 if (!ifaces_to_reloc.empty()) {
1874 for (auto it : ifaces_to_reloc) {
1875 iidx.relocate(iidx.end(), it);
1876 }
1877 }
1878 } catch (...) {
1879 if (!ifaces_to_reloc.empty()) {
1880 for (auto it : ifaces_to_reloc) {
1881 iidx.relocate(iidx.end(), it);
1882 }
1883 }
1884 throw;
1885 }
1886}
1887
1888void
1889IfaceMgr::receiveDHCP4Packets() {
1890 receiver_fd_event_handler_->clear();
1891
1892 // Add terminate watch socket.
1893 receiver_fd_event_handler_->add(dhcp_receiver_->getWatchFd(WatchedThread::TERMINATE));
1894
1895 // Add Interface sockets.
1896 for (const IfacePtr& iface : ifaces_) {
1897 for (const SocketInfo& s : iface->getSockets()) {
1898 // Only deal with IPv4 addresses.
1899 if (s.addr_.isV4()) {
1900 // Add this socket to listening set.
1901 receiver_fd_event_handler_->add(s.sockfd_);
1902 }
1903 }
1904 }
1905
1906 for (;;) {
1907 try {
1908 // Check the watch socket.
1909 if (dhcp_receiver_->shouldTerminate()) {
1910 isc_throw(ReceiveTerminate, "entry");
1911 }
1912
1913 // zero out the errno to be safe.
1914 errno = 0;
1915
1916 // Select with null timeouts to wait indefinitely an event
1917 int result = receiver_fd_event_handler_->waitEvent(0, 0, false);
1918
1919 // Re-check the watch socket.
1920 if (dhcp_receiver_->shouldTerminate()) {
1921 isc_throw(ReceiveTerminate, "waitEvent");
1922 }
1923
1924 if (result == 0) {
1925 // nothing received?
1926 continue;
1927 } else if (result < 0) {
1928 // This thread should not get signals?
1929 if (errno != EINTR) {
1930 {
1931 std::lock_guard<std::mutex> lk(receiver_mutex_);
1932 // Signal the error to receive4.
1933 dhcp_receiver_->setError(strerror(errno));
1934 }
1935 // We need to sleep in case of the error condition to
1936 // prevent the thread from tight looping when result
1937 // gets negative.
1938 sleep(1);
1939 }
1940 continue;
1941 }
1942
1943 // Body.
1944 scanReceiveDHCP4Packets();
1945
1946 } catch (const ReceiveTerminate&) {
1947 return;
1948 } catch (const std::exception& ex) {
1949 std::lock_guard<std::mutex> lk(receiver_mutex_);
1950 dhcp_receiver_->setError(string(ex.what()) + " error: " + strerror(errno));
1951 } catch (...) {
1952 std::lock_guard<std::mutex> lk(receiver_mutex_);
1953 dhcp_receiver_->setError("receive failed");
1954 }
1955 }
1956}
1957
1958void
1959IfaceMgr::scanReceiveDHCP6Packets() {
1960 // Let's find out which interface/socket has data.
1961 std::list<IfaceCollection::LruIterator> ifaces_to_reloc;
1962 IfaceCollection::LruIndex& iidx = ifaces_.getLru();
1963 try {
1964 for (auto iit = iidx.begin(); iit != iidx.end(); ++iit) {
1965 std::list<Iface::SocketLruIterator> sockets_to_reloc;
1966 Iface::SocketCollection& sockets = (*iit)->getSocketsRef();
1967 Iface::SocketLruIndex& sidx = sockets.get<1>();
1968 bool to_reloc = false;
1969 try {
1970 for (auto sit = sidx.begin(); sit != sidx.end(); ++sit) {
1971 if (!receiver_fd_event_handler_->readReady(sit->sockfd_) &&
1972 !receiver_fd_event_handler_->hasError(sit->sockfd_)) {
1973 continue;
1974 }
1975 if (!to_reloc) {
1976 ifaces_to_reloc.push_back(iit);
1977 to_reloc = true;
1978 }
1979 sockets_to_reloc.push_back(sit);
1980 if (receiver_fd_event_handler_->hasError(sit->sockfd_)) {
1981 handleIfaceSocketError(*iit, *sit);
1982 }
1983 receiveDHCP6Packet(*sit);
1984 // Can take time so check one more time the watch socket.
1985 if (dhcp_receiver_->shouldTerminate()) {
1986 isc_throw(ReceiveTerminate, "receiveDHCP6Packet");
1987 }
1988 }
1989 if (!sockets_to_reloc.empty()) {
1990 for (auto it : sockets_to_reloc) {
1991 sidx.relocate(sidx.end(), it);
1992 }
1993 }
1994 } catch (...) {
1995 if (!sockets_to_reloc.empty()) {
1996 for (auto it : sockets_to_reloc) {
1997 sidx.relocate(sidx.end(), it);
1998 }
1999 }
2000 throw;
2001 }
2002 }
2003 if (!ifaces_to_reloc.empty()) {
2004 for (auto it : ifaces_to_reloc) {
2005 iidx.relocate(iidx.end(), it);
2006 }
2007 }
2008 } catch (...) {
2009 if (!ifaces_to_reloc.empty()) {
2010 for (auto it : ifaces_to_reloc) {
2011 iidx.relocate(iidx.end(), it);
2012 }
2013 }
2014 throw;
2015 }
2016}
2017
2018void
2019IfaceMgr::receiveDHCP6Packets() {
2020 receiver_fd_event_handler_->clear();
2021
2022 // Add terminate watch socket.
2023 receiver_fd_event_handler_->add(dhcp_receiver_->getWatchFd(WatchedThread::TERMINATE));
2024
2025 // Add Interface sockets.
2026 for (const IfacePtr& iface : ifaces_) {
2027 for (const SocketInfo& s : iface->getSockets()) {
2028 // Only deal with IPv6 addresses.
2029 if (s.addr_.isV6()) {
2030 // Add this socket to listening set.
2031 receiver_fd_event_handler_->add(s.sockfd_);
2032 }
2033 }
2034 }
2035
2036 for (;;) {
2037 try {
2038 // Check the watch socket.
2039 if (dhcp_receiver_->shouldTerminate()) {
2040 isc_throw(ReceiveTerminate, "entry");
2041 }
2042
2043 // zero out the errno to be safe.
2044 errno = 0;
2045
2046 // Select with null timeouts to wait indefinitely an event
2047 int result = receiver_fd_event_handler_->waitEvent(0, 0, false);
2048
2049 // Re-check the watch socket.
2050 if (dhcp_receiver_->shouldTerminate()) {
2051 isc_throw(ReceiveTerminate, "waitEvent");
2052 }
2053
2054 if (result == 0) {
2055 // nothing received?
2056 continue;
2057 } else if (result < 0) {
2058 // This thread should not get signals?
2059 if (errno != EINTR) {
2060 {
2061 std::lock_guard<std::mutex> lk(receiver_mutex_);
2062 // Signal the error to receive6.
2063 dhcp_receiver_->setError(strerror(errno));
2064 }
2065 // We need to sleep in case of the error condition to
2066 // prevent the thread from tight looping when result
2067 // gets negative.
2068 sleep(1);
2069 }
2070 continue;
2071 }
2072
2073 // Body.
2074 scanReceiveDHCP6Packets();
2075
2076 } catch (const ReceiveTerminate&) {
2077 return;
2078 } catch (const std::exception& ex) {
2079 std::lock_guard<std::mutex> lk(receiver_mutex_);
2080 dhcp_receiver_->setError(string(ex.what()) + " error: " + strerror(errno));
2081 } catch (...) {
2082 std::lock_guard<std::mutex> lk(receiver_mutex_);
2083 dhcp_receiver_->setError("receive failed");
2084 }
2085 }
2086}
2087
2088void
2089IfaceMgr::receiveDHCP4Packet(Iface& iface, const SocketInfo& socket_info) {
2090 int len;
2091
2092 int result = ioctl(socket_info.sockfd_, FIONREAD, &len);
2093 if (result < 0) {
2094 std::lock_guard<std::mutex> lk(receiver_mutex_);
2095 // Signal the error to receive4.
2096 dhcp_receiver_->setError(strerror(errno));
2097 return;
2098 }
2099 if (len == 0) {
2100 // Nothing to read.
2101 return;
2102 }
2103
2104 Pkt4Ptr pkt;
2105
2106 try {
2107 pkt = packet_filter_->receive(iface, socket_info);
2108 } catch (const std::exception& ex) {
2109 std::lock_guard<std::mutex> lk(receiver_mutex_);
2110 dhcp_receiver_->setError(ex.what());
2111 } catch (...) {
2112 std::lock_guard<std::mutex> lk(receiver_mutex_);
2113 dhcp_receiver_->setError("packet filter receive() failed");
2114 }
2115
2116 if (pkt) {
2117 std::lock_guard<std::mutex> lk(receiver_mutex_);
2118 getPacketQueue4()->enqueuePacket(pkt, socket_info);
2119 dhcp_receiver_->markReady(WatchedThread::READY);
2120 }
2121}
2122
2123void
2124IfaceMgr::receiveDHCP6Packet(const SocketInfo& socket_info) {
2125 int len;
2126
2127 int result = ioctl(socket_info.sockfd_, FIONREAD, &len);
2128 if (result < 0) {
2129 std::lock_guard<std::mutex> lk(receiver_mutex_);
2130 // Signal the error to receive6.
2131 dhcp_receiver_->setError(strerror(errno));
2132 return;
2133 }
2134 if (len == 0) {
2135 // Nothing to read.
2136 return;
2137 }
2138
2139 Pkt6Ptr pkt;
2140
2141 try {
2142 pkt = packet_filter6_->receive(socket_info);
2143 } catch (const std::exception& ex) {
2144 std::lock_guard<std::mutex> lk(receiver_mutex_);
2145 dhcp_receiver_->setError(ex.what());
2146 } catch (...) {
2147 std::lock_guard<std::mutex> lk(receiver_mutex_);
2148 dhcp_receiver_->setError("packet filter receive() failed");
2149 }
2150
2151 if (pkt) {
2152 std::lock_guard<std::mutex> lk(receiver_mutex_);
2153 getPacketQueue6()->enqueuePacket(pkt, socket_info);
2154 dhcp_receiver_->markReady(WatchedThread::READY);
2155 }
2156}
2157
2158uint16_t
2160 IfacePtr iface = getIface(pkt);
2161 if (!iface) {
2162 isc_throw(IfaceNotFound, "Tried to find socket for non-existent interface");
2163 }
2164
2165 const Iface::SocketCollection& socket_collection = iface->getSockets();
2166
2167 Iface::SocketCollection::const_iterator candidate = socket_collection.end();
2168
2169 Iface::SocketCollection::const_iterator s;
2170 for (s = socket_collection.begin(); s != socket_collection.end(); ++s) {
2171
2172 // We should not merge those conditions for debugging reasons.
2173
2174 // V4 sockets are useless for sending v6 packets.
2175 if (s->family_ != AF_INET6) {
2176 continue;
2177 }
2178
2179 // Sockets bound to multicast address are useless for sending anything.
2180 if (s->addr_.isV6Multicast()) {
2181 continue;
2182 }
2183
2184 if (s->addr_ == pkt->getLocalAddr()) {
2185 // This socket is bound to the source address. This is perfect
2186 // match, no need to look any further.
2187 return (s->sockfd_);
2188 }
2189
2190 // If we don't have any other candidate, this one will do
2191 if (candidate == socket_collection.end()) {
2192 candidate = s;
2193 } else {
2194 // If we want to send something to link-local and the socket is
2195 // bound to link-local or we want to send to global and the socket
2196 // is bound to global, then use it as candidate
2197 if ((pkt->getRemoteAddr().isV6LinkLocal() &&
2198 s->addr_.isV6LinkLocal()) ||
2199 (!pkt->getRemoteAddr().isV6LinkLocal() &&
2200 !s->addr_.isV6LinkLocal())) {
2201 candidate = s;
2202 }
2203 }
2204 }
2205
2206 if (candidate != socket_collection.end()) {
2207 return (candidate->sockfd_);
2208 }
2209
2210 isc_throw(SocketNotFound, "Interface " << iface->getFullName()
2211 << " does not have any suitable IPv6 sockets open.");
2212}
2213
2216 IfacePtr iface = getIface(pkt);
2217 if (!iface) {
2218 isc_throw(IfaceNotFound, "Tried to find socket for non-existent interface");
2219 }
2220
2221 const Iface::SocketCollection& socket_collection = iface->getSockets();
2222 // A candidate being an end of the iterator marks that it is a beginning of
2223 // the socket search and that the candidate needs to be set to the first
2224 // socket found.
2225 Iface::SocketCollection::const_iterator candidate = socket_collection.end();
2226 Iface::SocketCollection::const_iterator s;
2227 for (s = socket_collection.begin(); s != socket_collection.end(); ++s) {
2228 if (s->family_ == AF_INET) {
2229 if (s->addr_ == pkt->getLocalAddr()) {
2230 return (*s);
2231 }
2232
2233 if (candidate == socket_collection.end()) {
2234 candidate = s;
2235 }
2236 }
2237 }
2238
2239 if (candidate == socket_collection.end()) {
2240 isc_throw(SocketNotFound, "Interface " << iface->getFullName()
2241 << " does not have any suitable IPv4 sockets open.");
2242 }
2243
2244 return (*candidate);
2245}
2246
2247bool
2249 if (isDHCPReceiverRunning()) {
2250 isc_throw(InvalidOperation, "Cannot reconfigure queueing"
2251 " while DHCP receiver thread is running");
2252 }
2253
2254 bool enable_queue = false;
2255 if (queue_control) {
2256 try {
2257 enable_queue = data::SimpleParser::getBoolean(queue_control, "enable-queue");
2258 } catch (...) {
2259 // @todo - for now swallow not found errors.
2260 // if not present we assume default
2261 }
2262 }
2263
2264 if (enable_queue) {
2265 // Try to create the queue as configured.
2266 if (family == AF_INET) {
2267 packet_queue_mgr4_->createPacketQueue(queue_control);
2268 } else {
2269 packet_queue_mgr6_->createPacketQueue(queue_control);
2270 }
2271 } else {
2272 // Destroy the current queue (if one), this inherently disables threading.
2273 if (family == AF_INET) {
2274 packet_queue_mgr4_->destroyPacketQueue();
2275 } else {
2276 packet_queue_mgr6_->destroyPacketQueue();
2277 }
2278 }
2279
2280 return (enable_queue);
2281}
2282
2283void
2284Iface::addError(std::string const& message) {
2285 errors_.push_back(message);
2286}
2287
2288void
2290 errors_.clear();
2291}
2292
2293Iface::ErrorBuffer const&
2295 return errors_;
2296}
2297
2298bool
2300 if (test_mode_ && update_only) {
2301 return (false);
2302 }
2303 return (true);
2304}
2305
2306} // end of namespace isc::dhcp
2307} // end of namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a function is called in a prohibited way.
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
A generic exception that is thrown when an unexpected error condition occurs.
static ElementPtr create(const Position &pos=ZERO_POSITION())
Create a NullElement.
Definition data.cc:299
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:354
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:349
static bool getBoolean(isc::data::ConstElementPtr scope, const std::string &name)
Returns a boolean parameter from a scope.
IfacePtr getIface(const unsigned int ifindex)
Lookup by interface index.
Definition iface_mgr.cc:870
LruIndex & getLru()
LRU index.
Definition iface_mgr.h:618
IfaceContainer::nth_index< 3 >::type LruIndex
Type of LRU index.
Definition iface_mgr.h:613
IfaceMgr exception thrown thrown when interface detection fails.
Definition iface_mgr.h:44
Handles network interfaces, transmission and reception.
Definition iface_mgr.h:740
void clearIfaces()
Removes detected interfaces.
Definition iface_mgr.cc:959
bool isExternalSocket(int fd)
Checks if socket's file description is registered.
Definition iface_mgr.cc:422
void deleteExternalSocket(int socketfd)
Deletes external socket.
Definition iface_mgr.cc:398
Pkt6Ptr receive6Indirect(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv6 packets indirectly or data from external sockets.
bool openSockets4(const uint16_t port=DHCP4_SERVER_PORT, const bool use_bcast=true, IfaceMgrErrorMsgCallback error_handler=0, const bool skip_opened=false)
Opens IPv4 sockets on detected interfaces.
Definition iface_mgr.cc:555
void stopDHCPReceiver(bool clear_queue=true)
Stops the DHCP packet receiver.
Definition iface_mgr.cc:325
std::function< void(int fd)> SocketCallback
Defines callback used when data is received over external sockets.
Definition iface_mgr.h:745
int openSocket(const std::string &ifname, const isc::asiolink::IOAddress &addr, const uint16_t port, const bool receive_bcast=false, const bool send_bcast=false)
Opens UDP/IP socket and binds it to address, interface and port.
int openSocketFromAddress(const isc::asiolink::IOAddress &addr, const uint16_t port)
Opens UDP/IP socket and binds to address specified.
void printIfaces(std::ostream &out=std::cout)
Debugging method that prints out all available interfaces.
Definition iface_mgr.cc:846
IfacePtr getIface(const unsigned int ifindex)
Returns interface specified interface index.
Definition iface_mgr.cc:937
int openSocket4(Iface &iface, const isc::asiolink::IOAddress &addr, const uint16_t port, const bool receive_bcast=false, const bool send_bcast=false)
Opens IPv4 socket.
bool openSockets6(const uint16_t port=DHCP6_SERVER_PORT, IfaceMgrErrorMsgCallback error_handler=0, const bool skip_opened=false)
Opens IPv6 sockets on detected interfaces.
Definition iface_mgr.cc:685
BoundAddresses bound_address_
Unordered set of IPv4 bound addresses.
Definition iface_mgr.h:1669
void setPacketFilter(const PktFilterPtr &packet_filter)
Set packet filter object to handle sending and receiving DHCPv4 messages.
Definition iface_mgr.cc:463
int openSocketFromIface(const std::string &ifname, const uint16_t port, const uint8_t family)
Opens UDP/IP socket and binds it to interface specified.
Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets or data from external sockets.
void detectIfaces(bool update_only=false)
Detects network interfaces.
IfaceCollection ifaces_
List of available interfaces.
Definition iface_mgr.h:1666
void startDHCPReceiver(const uint16_t family)
Starts DHCP packet receiver.
Definition iface_mgr.cc:800
void clearUnicasts()
Clears unicast addresses on all interfaces.
virtual bool isSocketReceivedTimeSupported() const
Check if the socket received time is supported.
Definition iface_mgr.cc:362
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition iface_mgr.cc:52
void initializeFDEventHandler()
Initialize the FD event handler;.
Definition iface_mgr.cc:213
bool isDHCPReceiverRunning() const
Returns true if there is a receiver exists and its thread is currently running.
Definition iface_mgr.h:1496
bool hasOpenSocket(const uint16_t family) const
Checks if there is at least one socket of the specified family open.
Definition iface_mgr.cc:505
virtual ~IfaceMgr()
Destructor.
Definition iface_mgr.cc:343
void collectBoundAddresses()
Collect the addresses all sockets are bound to.
isc::data::ElementPtr ifacesToElement() const
Unparses detected interface list.
Definition iface_mgr.cc:348
int openSocket6(Iface &iface, const isc::asiolink::IOAddress &addr, uint16_t port, const bool join_multicast)
Opens IPv6 socket.
uint16_t getFamily() const
Returns address family.
Definition iface_mgr.h:1522
bool configureDHCPPacketQueue(const uint16_t family, data::ConstElementPtr queue_control)
Configures DHCP packet queue.
int openSocketFromRemoteAddress(const isc::asiolink::IOAddress &remote_addr, const uint16_t port)
Opens UDP/IP socket to be used to connect to remote address.
std::list< int > getAllExternalSockets()
Get the list of external sockets.
Definition iface_mgr.cc:453
Pkt6Ptr receive6Direct(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv6 packets directly or data from external sockets.
bool checkDetectIfaces(bool update_only)
Check if the specific system calls used to detect interfaces should be executed.
bool isDirectResponseSupported() const
Check if packet be sent directly to the client having no address.
Definition iface_mgr.cc:357
void clearBoundAddresses()
Clears the addresses all sockets are bound to.
Definition iface_mgr.cc:964
void addExternalSocket(int socketfd, SocketCallback callback)
Adds external socket and a callback.
Definition iface_mgr.cc:367
void addInterface(const IfacePtr &iface)
Adds an interface to list of known interfaces.
Definition iface_mgr.cc:833
IfaceMgr()
Protected constructor.
Definition iface_mgr.cc:181
bool send(const Pkt6Ptr &pkt)
Sends an IPv6 packet.
Pkt4Ptr receive4Indirect(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets indirectly or data from external sockets.
void closeSockets()
Closes all open sockets.
Definition iface_mgr.cc:313
PacketQueue6Ptr getPacketQueue6()
Fetches the DHCPv6 receiver packet queue.
Definition iface_mgr.h:1469
bool isExternalSocketUnusable(int fd)
Checks if socket's file description is registered.
Definition iface_mgr.cc:430
static const IfaceMgrPtr & instancePtr()
Returns pointer to the sole instance of the interface manager.
Definition iface_mgr.cc:57
void deleteAllExternalSockets()
Deletes all external sockets.
Definition iface_mgr.cc:442
std::thread::id id_
Main thread ID.
Definition iface_mgr.h:1663
Pkt4Ptr receive4Direct(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets directly or data from external sockets.
PacketQueue4Ptr getPacketQueue4()
Fetches the DHCPv4 receiver packet queue.
Definition iface_mgr.h:1452
uint16_t getSocket(const isc::dhcp::Pkt6Ptr &pkt)
Return most suitable socket for transmitting specified IPv6 packet.
Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets or data from external sockets.
IfaceMgr exception thrown when there is no suitable interface.
Definition iface_mgr.h:89
Represents a single network interface.
Definition iface_mgr.h:136
std::string getPlainMac() const
Returns link-layer address a plain text.
Definition iface_mgr.cc:127
uint64_t flags_
Interface flags (this value is as is returned by OS, it may mean different things on different OSes).
Definition iface_mgr.h:528
bool inactive4_
Indicates that IPv4 sockets should (true) or should not (false) be opened on this interface.
Definition iface_mgr.h:532
size_t mac_len_
Length of link-layer address (usually 6).
Definition iface_mgr.h:499
void clearErrors()
Clears all errors.
virtual isc::data::ElementPtr toElement() const
Unparse a configuration object.
Definition iface_mgr.cc:292
AddressCollection addrs_
List of assigned addresses.
Definition iface_mgr.h:490
ErrorBuffer const & getErrors() const
Get the consistent list of error messages.
std::vector< std::string > ErrorBuffer
Type definition for a list of error messages.
Definition iface_mgr.h:176
std::string getFullName() const
Returns full interface name as "ifname/ifindex" string.
Definition iface_mgr.cc:120
unsigned int ifindex_
Interface index (a value that uniquely identifies an interface).
Definition iface_mgr.h:487
std::string name_
Network interface name.
Definition iface_mgr.h:484
boost::multi_index_container< SocketInfo, boost::multi_index::indexed_by< boost::multi_index::sequenced<>, boost::multi_index::sequenced<> > > SocketCollection
Type that holds a list of socket information.
Definition iface_mgr.h:167
uint16_t hardware_type_
Hardware type.
Definition iface_mgr.h:502
SocketCollection sockets_
Socket used to send data.
Definition iface_mgr.h:481
const AddressCollection & getAddresses() const
Returns all addresses available on an interface.
Definition iface_mgr.h:300
bool flag_multicast_
Flag specifies if selected interface is multicast capable.
Definition iface_mgr.h:519
void setActive(const isc::asiolink::IOAddress &address, const bool active)
Activates or deactivates address for the interface.
Definition iface_mgr.cc:262
void addError(std::string const &message)
Add an error to the list of messages.
std::string getName() const
Returns interface name.
Definition iface_mgr.h:264
Iface(const std::string &name, unsigned int ifindex)
Iface constructor.
Definition iface_mgr.cc:62
bool delAddress(const isc::asiolink::IOAddress &addr)
Deletes an address from an interface.
Definition iface_mgr.cc:154
bool hasAddress(const isc::asiolink::IOAddress &address) const
Check if the interface has the specified address assigned.
Definition iface_mgr.cc:245
SocketCollection::nth_index< 1 >::type SocketLruIndex
SocketInfo LRU index type.
Definition iface_mgr.h:170
void setMac(const uint8_t *mac, size_t macLen)
Sets MAC address of the interface.
Definition iface_mgr.cc:141
bool flag_running_
Flag specifies if selected interface is running (e.g.
Definition iface_mgr.h:516
bool delSocket(uint16_t sockfd)
Closes socket.
Definition iface_mgr.cc:164
std::list< Address > AddressCollection
Type that defines list of addresses.
Definition iface_mgr.h:146
bool inactive6_
Indicates that IPv6 sockets should (true) or should not (false) be opened on this interface.
Definition iface_mgr.h:536
static const unsigned int MAX_MAC_LEN
Maximum MAC address length (Infiniband uses 20 bytes).
Definition iface_mgr.h:140
bool flag_loopback_
Specifies if selected interface is loopback.
Definition iface_mgr.h:509
void addUnicast(const isc::asiolink::IOAddress &addr)
Adds unicast the server should listen on.
Definition iface_mgr.cc:218
unsigned int countActive4() const
Returns a number of activated IPv4 addresses on the interface.
Definition iface_mgr.cc:281
uint8_t mac_[MAX_MAC_LEN]
Link-layer address.
Definition iface_mgr.h:496
util::Optional< asiolink::IOAddress > Address
Address type.
Definition iface_mgr.h:143
void addAddress(const isc::asiolink::IOAddress &addr)
Adds an address to an interface.
Definition iface_mgr.cc:255
void closeSockets()
Closes all open sockets on interface.
Definition iface_mgr.cc:75
void addSocket(const SocketInfo &sock)
Adds socket descriptor to an interface.
Definition iface_mgr.h:369
bool flag_up_
Specifies if selected interface is up.
Definition iface_mgr.h:512
bool flag_broadcast_
Flag specifies if selected interface is broadcast capable.
Definition iface_mgr.h:522
AddressCollection unicasts_
List of unicast addresses the server should listen on.
Definition iface_mgr.h:493
bool getAddress4(isc::asiolink::IOAddress &address) const
Returns IPv4 address assigned to the interface.
Definition iface_mgr.cc:229
Exception thrown when invalid packet filter object specified.
Definition pkt_filter.h:18
Exception thrown when it is not allowed to set new Packet Filter.
Definition iface_mgr.h:51
Packet Queue Manager for DHCPv4 servers.
Packet Queue Manager for DHCPv6 servers.
A DHCPv6 packet handling class using datagram sockets.
Packet handling class using AF_INET socket family.
Exception thrown when a call to select is interrupted by a signal.
Definition iface_mgr.h:58
IfaceMgr exception thrown thrown when socket opening or configuration failed.
Definition iface_mgr.h:66
IfaceMgr exception thrown when there is an error detected for the respective socket file descriptor.
Definition iface_mgr.h:104
IfaceMgr exception thrown when there is no suitable socket found.
Definition iface_mgr.h:96
IfaceMgr exception thrown thrown when error occurred during reading data from socket.
Definition iface_mgr.h:74
static FDEventHandlerPtr factoryFDEventHandler()
Return an FDEventhandler.
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
A template representing an optional value.
Definition optional.h:37
Provides a thread and controls for monitoring its activities.
#define DHCP_IPV4_BROADCAST_ADDRESS
Definition dhcp4.h:42
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define IFACEMGR_ERROR(ex_type, handler, iface, stream)
A macro which handles an error in IfaceMgr.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition macros.h:32
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition macros.h:26
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition macros.h:14
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:30
boost::shared_ptr< Element > ElementPtr
Definition data.h:29
@ info
Definition db_log.h:120
@ error
Definition db_log.h:118
const isc::log::MessageID DHCP_RECEIVE4_UNKNOWN
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
Definition pkt.h:999
const isc::log::MessageID DHCP_RECEIVE6_UNKNOWN
boost::shared_ptr< IfaceMgr > IfaceMgrPtr
Type definition for the pointer to the IfaceMgr.
Definition iface_mgr.h:725
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition pkt4.h:556
boost::shared_ptr< PktFilter > PktFilterPtr
Pointer to a PktFilter object.
Definition pkt_filter.h:144
boost::shared_ptr< Iface > IfacePtr
Type definition for the pointer to an Iface object.
Definition iface_mgr.h:555
const isc::log::MessageID DHCP_DELETE_EXTERNAL_SOCKET_NOT_FOUND
std::function< void(const std::string &errmsg)> IfaceMgrErrorMsgCallback
This type describes the callback function invoked when error occurs in the IfaceMgr.
Definition iface_mgr.h:732
const isc::log::MessageID DHCP_ADD_EXTERNAL_SOCKET_ALREADY_EXISTS
const isc::log::MessageID DHCP_ADD_EXTERNAL_SOCKET_BAD_THREAD
const isc::log::MessageID DHCP_IFACE_OPEN_SOCKET
constexpr unsigned int UNSET_IFINDEX
A value used to signal that the interface index was not set.
Definition pkt.h:30
const isc::log::MessageID DHCP_DELETE_EXTERNAL_SOCKET_BAD_THREAD
const isc::log::MessageID DHCP_DELETE_ALL_EXTERNAL_SOCKETS_BAD_THREAD
isc::log::Logger dhcp_logger("dhcp")
DHCP library Logger.
Definition dhcp_log.h:21
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition pkt6.h:31
boost::shared_ptr< PktFilter6 > PktFilter6Ptr
Pointer to a PktFilter object.
const isc::log::MessageID DHCP_IFACE_SOCKET_ERROR
const int DBGLVL_TRACE_BASIC
Trace basic operations.
Defines the logger used by the top-level component of kea-lfc.
Keeps callback information for external sockets.
Definition iface_mgr.h:757
SocketCallback callback_
A callback that will be called when data arrives over socket_.
Definition iface_mgr.h:762
Holds information about socket.
Definition socket_info.h:18