Kea 3.3.1
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_ && !isMainThread()) {
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_ && !isMainThread()) {
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_ && !isMainThread()) {
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) {
1511 if (!found) {
1513 }
1514 return (Pkt4Ptr());
1515 }
1516
1517 // Check that we have something to read.
1518 int len;
1519 if (ioctl(candidate->sockfd_, FIONREAD, &len) < 0) {
1520 isc_throw(SocketReadError, strerror(errno));
1521 }
1522 if (len == 0) {
1523 // Nothing to read.
1524 return (Pkt4Ptr());
1525 }
1526
1527 // Assuming that packet filter is not null, because its modifier checks it.
1528 return (packet_filter_->receive(*recv_if, *candidate));
1529}
1530
1531Pkt6Ptr
1532IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
1533 if (isDHCPReceiverRunning()) {
1534 return (receive6Indirect(timeout_sec, timeout_usec));
1535 }
1536
1537 return (receive6Direct(timeout_sec, timeout_usec));
1538}
1539
1540Pkt6Ptr
1541IfaceMgr::receive6Direct(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */ ) {
1542 // Sanity check for microsecond timeout.
1543 if (timeout_usec >= 1000000) {
1544 isc_throw(BadValue, "fractional timeout must be shorter than"
1545 " one million microseconds");
1546 }
1547
1548 fd_event_handler_->clear();
1549
1555 for (const IfacePtr& iface : ifaces_) {
1556 for (const SocketInfo& s : iface->getSockets()) {
1557 // Only deal with IPv6 addresses.
1558 if (s.addr_.isV6()) {
1559 // Add this socket to listening set
1560 fd_event_handler_->add(s.sockfd_);
1561 }
1562 }
1563 }
1564
1565 // if there are any callbacks for external sockets registered...
1566 {
1567 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1568 if (!callbacks_.empty()) {
1569 for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1570 if (it->unusable_) {
1571 continue;
1572 }
1573 handleClosedExternalSocket(it);
1574 // Add this socket to listening set
1575 fd_event_handler_->add(it->socket_);
1576 }
1577 }
1578 }
1579
1580 // zero out the errno to be safe
1581 errno = 0;
1582
1583 int result = fd_event_handler_->waitEvent(timeout_sec, timeout_usec);
1584
1585 if (result == 0) {
1586 // nothing received and timeout has been reached
1587 return (Pkt6Ptr()); // null
1588 } else if (result < 0) {
1589 // In most cases we would like to know whether select() returned
1590 // an error because of a signal being received or for some other
1591 // reason. This is because DHCP servers use signals to trigger
1592 // certain actions, like reconfiguration or graceful shutdown.
1593 // By catching a dedicated exception the caller will know if the
1594 // error returned by the function is due to the reception of the
1595 // signal or for some other reason.
1596 if (errno == EINTR) {
1597 isc_throw(SignalInterruptOnSelect, strerror(errno));
1598 } else if (errno == EBADF) {
1599 handleClosedExternalSockets();
1600 isc_throw(SocketFDError, strerror(EBADF));
1601 }
1602 isc_throw(SocketReadError, strerror(errno));
1603 }
1604
1605 // Let's find out which socket has the data
1606 boost::scoped_ptr<SocketCallbackInfo> ex_sock;
1607 bool found = false;
1608 {
1609 std::list<SocketCallbackInfoIterator> to_reloc;
1610 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1611 for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1612 if (it->unusable_) {
1613 continue;
1614 }
1615 handleClosedExternalSocket(it);
1616 if (fd_event_handler_->readReady(it->socket_) ||
1617 fd_event_handler_->hasError(it->socket_)) {
1618 found = true;
1619 to_reloc.push_back(it);
1620
1621 // something received over external socket
1622 if (it->callback_) {
1623 // Note the external socket to call its callback without
1624 // the lock taken so it can be deleted.
1625 ex_sock.reset(new SocketCallbackInfo(*it));
1626 break;
1627 }
1628 }
1629 }
1630 if (found) {
1631 for (auto it : to_reloc) {
1632 callbacks_.relocate(callbacks_.end(), it);
1633 }
1634 }
1635 }
1636
1637 if (ex_sock && ex_sock->callback_) {
1638 // Calling the external socket's callback provides its service
1639 // layer access without integrating any specific features
1640 // in IfaceMgr
1641 ex_sock->callback_(ex_sock->socket_);
1642 }
1643
1644 // Let's find out which interface/socket has the data
1645 boost::scoped_ptr<SocketInfo> candidate;
1646 IfacePtr recv_if;
1647 std::list<IfaceCollection::LruIterator> ifaces_to_reloc;
1648 IfaceCollection::LruIndex& iidx = ifaces_.getLru();
1649 for (auto iit = iidx.begin(); iit != iidx.end(); ++iit) {
1650 std::list<Iface::SocketLruIterator> sockets_to_reloc;
1651 Iface::SocketCollection& sockets = (*iit)->getSocketsRef();
1652 Iface::SocketLruIndex& sidx = sockets.get<1>();
1653 for (auto sit = sidx.begin(); sit != sidx.end(); ++sit) {
1654 if (!fd_event_handler_->readReady(sit->sockfd_) &&
1655 !fd_event_handler_->hasError(sit->sockfd_)) {
1656 continue;
1657 }
1658 ifaces_to_reloc.push_back(iit);
1659 sockets_to_reloc.push_back(sit);
1660 if (fd_event_handler_->hasError(sit->sockfd_)) {
1661 handleIfaceSocketError(*iit, *sit);
1662 }
1663 candidate.reset(new SocketInfo(*sit));
1664 break;
1665 }
1666 if (!sockets_to_reloc.empty()) {
1667 for (auto it : sockets_to_reloc) {
1668 sidx.relocate(sidx.end(), it);
1669 }
1670 }
1671 if (candidate) {
1672 recv_if = *iit;
1673 break;
1674 }
1675 }
1676 if (!ifaces_to_reloc.empty()) {
1677 for (auto it : ifaces_to_reloc) {
1678 iidx.relocate(iidx.end(), it);
1679 }
1680 }
1681
1682 if (!candidate) {
1683 if (!found) {
1685 }
1686 return (Pkt6Ptr());
1687 }
1688
1689 // Check that we have something to read.
1690 int len;
1691 if (ioctl(candidate->sockfd_, FIONREAD, &len) < 0) {
1692 isc_throw(SocketReadError, strerror(errno));
1693 }
1694 if (len == 0) {
1695 // Nothing to read.
1696 return (Pkt6Ptr());
1697 }
1698
1699 // Assuming that packet filter is not null, because its modifier checks it.
1700 return (packet_filter6_->receive(*candidate));
1701}
1702
1703Pkt6Ptr
1704IfaceMgr::receive6Indirect(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */ ) {
1705 // Sanity check for microsecond timeout.
1706 if (timeout_usec >= 1000000) {
1707 isc_throw(BadValue, "fractional timeout must be shorter than"
1708 " one million microseconds");
1709 }
1710
1711 fd_event_handler_->clear();
1712
1713 // if there are any callbacks for external sockets registered...
1714 {
1715 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1716 if (!callbacks_.empty()) {
1717 for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1718 if (it->unusable_) {
1719 continue;
1720 }
1721 handleClosedExternalSocket(it);
1722 // Add this socket to listening set
1723 fd_event_handler_->add(it->socket_);
1724 }
1725 }
1726 }
1727
1728 // Add Receiver ready watch socket
1729 fd_event_handler_->add(dhcp_receiver_->getWatchFd(WatchedThread::READY));
1730
1731 // Add Receiver error watch socket
1732 fd_event_handler_->add(dhcp_receiver_->getWatchFd(WatchedThread::ERROR));
1733
1734 // Set timeout for our next select() call. If there are
1735 // no DHCP packets to read, then we'll wait for a finite
1736 // amount of time for an IO event. Otherwise, we'll
1737 // poll (timeout = 0 secs). We need to poll, even if
1738 // DHCP packets are waiting so we don't starve external
1739 // sockets under heavy DHCP load.
1740 if (!getPacketQueue6()->empty()) {
1741 timeout_sec = 0;
1742 timeout_usec = 0;
1743 }
1744
1745 // zero out the errno to be safe
1746 errno = 0;
1747
1748 int result = fd_event_handler_->waitEvent(timeout_sec, timeout_usec);
1749
1750 if ((result == 0) && getPacketQueue6()->empty()) {
1751 // nothing received and timeout has been reached
1752 return (Pkt6Ptr());
1753 } else if (result < 0) {
1754 // In most cases we would like to know whether select() returned
1755 // an error because of a signal being received or for some other
1756 // reason. This is because DHCP servers use signals to trigger
1757 // certain actions, like reconfiguration or graceful shutdown.
1758 // By catching a dedicated exception the caller will know if the
1759 // error returned by the function is due to the reception of the
1760 // signal or for some other reason.
1761 if (errno == EINTR) {
1762 isc_throw(SignalInterruptOnSelect, strerror(errno));
1763 } else if (errno == EBADF) {
1764 handleClosedExternalSockets();
1765 isc_throw(SocketFDError, strerror(EBADF));
1766 }
1767 isc_throw(SocketReadError, strerror(errno));
1768 }
1769
1770 // We only check external sockets if select detected an event.
1771 if (result > 0) {
1772 {
1773 std::lock_guard<std::mutex> lk(receiver_mutex_);
1774 // Check for receiver thread read errors.
1775 if (dhcp_receiver_->isReady(WatchedThread::ERROR)) {
1776 string msg = dhcp_receiver_->getLastError();
1777 dhcp_receiver_->clearReady(WatchedThread::ERROR);
1779 }
1780 }
1781
1782 // Let's find out which external socket has the data
1783 boost::scoped_ptr<SocketCallbackInfo> ex_sock;
1784 bool found = false;
1785 {
1786 std::list<SocketCallbackInfoIterator> to_reloc;
1787 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1788 for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1789 if (it->unusable_) {
1790 continue;
1791 }
1792 handleClosedExternalSocket(it);
1793 if (fd_event_handler_->readReady(it->socket_) ||
1794 fd_event_handler_->hasError(it->socket_)) {
1795 found = true;
1796 to_reloc.push_back(it);
1797
1798 // something received over external socket
1799 if (it->callback_) {
1800 // Note the external socket to call its callback without
1801 // the lock taken so it can be deleted.
1802 ex_sock.reset(new SocketCallbackInfo(*it));
1803 break;
1804 }
1805 }
1806 }
1807 if (found) {
1808 for (auto it : to_reloc) {
1809 callbacks_.relocate(callbacks_.end(), it);
1810 }
1811 }
1812 }
1813
1814 if (ex_sock && ex_sock->callback_) {
1815 // Calling the external socket's callback provides its service
1816 // layer access without integrating any specific features
1817 // in IfaceMgr
1818 ex_sock->callback_(ex_sock->socket_);
1819 }
1820 }
1821
1822 // If we're here it should only be because there are DHCP packets waiting.
1823 std::lock_guard<std::mutex> lk(receiver_mutex_);
1824 Pkt6Ptr pkt = getPacketQueue6()->dequeuePacket();
1825 if (!pkt) {
1826 dhcp_receiver_->clearReady(WatchedThread::READY);
1827 }
1828
1829 return (pkt);
1830}
1831
1832void
1833IfaceMgr::scanReceiveDHCP4Packets() {
1834 // Let's find out which interface/socket has data.
1835 std::list<IfaceCollection::LruIterator> ifaces_to_reloc;
1837 try {
1838 for (auto iit = iidx.begin(); iit != iidx.end(); ++iit) {
1839 std::list<Iface::SocketLruIterator> sockets_to_reloc;
1840 Iface::SocketCollection& sockets = (*iit)->getSocketsRef();
1841 Iface::SocketLruIndex& sidx = sockets.get<1>();
1842 bool to_reloc = false;
1843 try {
1844 for (auto sit = sidx.begin(); sit != sidx.end(); ++sit) {
1845 if (!receiver_fd_event_handler_->readReady(sit->sockfd_) &&
1846 !receiver_fd_event_handler_->hasError(sit->sockfd_)) {
1847 continue;
1848 }
1849 if (!to_reloc) {
1850 ifaces_to_reloc.push_back(iit);
1851 to_reloc = true;
1852 }
1853 sockets_to_reloc.push_back(sit);
1854 if (receiver_fd_event_handler_->hasError(sit->sockfd_)) {
1855 handleIfaceSocketError(*iit, *sit);
1856 }
1857 receiveDHCP4Packet(**iit, *sit);
1858 // Can take time so check one more time the watch socket.
1859 if (dhcp_receiver_->shouldTerminate()) {
1860 isc_throw(ReceiveTerminate, "receiveDHCP4Packet");
1861 }
1862 }
1863 if (!sockets_to_reloc.empty()) {
1864 for (auto it : sockets_to_reloc) {
1865 sidx.relocate(sidx.end(), it);
1866 }
1867 }
1868 } catch (...) {
1869 if (!sockets_to_reloc.empty()) {
1870 for (auto it : sockets_to_reloc) {
1871 sidx.relocate(sidx.end(), it);
1872 }
1873 }
1874 throw;
1875 }
1876 }
1877 if (!ifaces_to_reloc.empty()) {
1878 for (auto it : ifaces_to_reloc) {
1879 iidx.relocate(iidx.end(), it);
1880 }
1881 }
1882 } catch (...) {
1883 if (!ifaces_to_reloc.empty()) {
1884 for (auto it : ifaces_to_reloc) {
1885 iidx.relocate(iidx.end(), it);
1886 }
1887 }
1888 throw;
1889 }
1890}
1891
1892void
1893IfaceMgr::receiveDHCP4Packets() {
1894 receiver_fd_event_handler_->clear();
1895
1896 // Add terminate watch socket.
1897 receiver_fd_event_handler_->add(dhcp_receiver_->getWatchFd(WatchedThread::TERMINATE));
1898
1899 // Add Interface sockets.
1900 for (const IfacePtr& iface : ifaces_) {
1901 for (const SocketInfo& s : iface->getSockets()) {
1902 // Only deal with IPv4 addresses.
1903 if (s.addr_.isV4()) {
1904 // Add this socket to listening set.
1905 receiver_fd_event_handler_->add(s.sockfd_);
1906 }
1907 }
1908 }
1909
1910 for (;;) {
1911 try {
1912 // Check the watch socket.
1913 if (dhcp_receiver_->shouldTerminate()) {
1914 isc_throw(ReceiveTerminate, "entry");
1915 }
1916
1917 // zero out the errno to be safe.
1918 errno = 0;
1919
1920 // Select with null timeouts to wait indefinitely an event
1921 int result = receiver_fd_event_handler_->waitEvent(0, 0, false);
1922
1923 // Re-check the watch socket.
1924 if (dhcp_receiver_->shouldTerminate()) {
1925 isc_throw(ReceiveTerminate, "waitEvent");
1926 }
1927
1928 if (result == 0) {
1929 // nothing received?
1930 continue;
1931 } else if (result < 0) {
1932 // This thread should not get signals?
1933 if (errno != EINTR) {
1934 {
1935 std::lock_guard<std::mutex> lk(receiver_mutex_);
1936 // Signal the error to receive4.
1937 dhcp_receiver_->setError(strerror(errno));
1938 }
1939 // We need to sleep in case of the error condition to
1940 // prevent the thread from tight looping when result
1941 // gets negative.
1942 sleep(1);
1943 }
1944 continue;
1945 }
1946
1947 // Body.
1948 scanReceiveDHCP4Packets();
1949
1950 } catch (const ReceiveTerminate&) {
1951 return;
1952 } catch (const std::exception& ex) {
1953 std::lock_guard<std::mutex> lk(receiver_mutex_);
1954 dhcp_receiver_->setError(string(ex.what()) + " error: " + strerror(errno));
1955 } catch (...) {
1956 std::lock_guard<std::mutex> lk(receiver_mutex_);
1957 dhcp_receiver_->setError("receive failed");
1958 }
1959 }
1960}
1961
1962void
1963IfaceMgr::scanReceiveDHCP6Packets() {
1964 // Let's find out which interface/socket has data.
1965 std::list<IfaceCollection::LruIterator> ifaces_to_reloc;
1966 IfaceCollection::LruIndex& iidx = ifaces_.getLru();
1967 try {
1968 for (auto iit = iidx.begin(); iit != iidx.end(); ++iit) {
1969 std::list<Iface::SocketLruIterator> sockets_to_reloc;
1970 Iface::SocketCollection& sockets = (*iit)->getSocketsRef();
1971 Iface::SocketLruIndex& sidx = sockets.get<1>();
1972 bool to_reloc = false;
1973 try {
1974 for (auto sit = sidx.begin(); sit != sidx.end(); ++sit) {
1975 if (!receiver_fd_event_handler_->readReady(sit->sockfd_) &&
1976 !receiver_fd_event_handler_->hasError(sit->sockfd_)) {
1977 continue;
1978 }
1979 if (!to_reloc) {
1980 ifaces_to_reloc.push_back(iit);
1981 to_reloc = true;
1982 }
1983 sockets_to_reloc.push_back(sit);
1984 if (receiver_fd_event_handler_->hasError(sit->sockfd_)) {
1985 handleIfaceSocketError(*iit, *sit);
1986 }
1987 receiveDHCP6Packet(*sit);
1988 // Can take time so check one more time the watch socket.
1989 if (dhcp_receiver_->shouldTerminate()) {
1990 isc_throw(ReceiveTerminate, "receiveDHCP6Packet");
1991 }
1992 }
1993 if (!sockets_to_reloc.empty()) {
1994 for (auto it : sockets_to_reloc) {
1995 sidx.relocate(sidx.end(), it);
1996 }
1997 }
1998 } catch (...) {
1999 if (!sockets_to_reloc.empty()) {
2000 for (auto it : sockets_to_reloc) {
2001 sidx.relocate(sidx.end(), it);
2002 }
2003 }
2004 throw;
2005 }
2006 }
2007 if (!ifaces_to_reloc.empty()) {
2008 for (auto it : ifaces_to_reloc) {
2009 iidx.relocate(iidx.end(), it);
2010 }
2011 }
2012 } catch (...) {
2013 if (!ifaces_to_reloc.empty()) {
2014 for (auto it : ifaces_to_reloc) {
2015 iidx.relocate(iidx.end(), it);
2016 }
2017 }
2018 throw;
2019 }
2020}
2021
2022void
2023IfaceMgr::receiveDHCP6Packets() {
2024 receiver_fd_event_handler_->clear();
2025
2026 // Add terminate watch socket.
2027 receiver_fd_event_handler_->add(dhcp_receiver_->getWatchFd(WatchedThread::TERMINATE));
2028
2029 // Add Interface sockets.
2030 for (const IfacePtr& iface : ifaces_) {
2031 for (const SocketInfo& s : iface->getSockets()) {
2032 // Only deal with IPv6 addresses.
2033 if (s.addr_.isV6()) {
2034 // Add this socket to listening set.
2035 receiver_fd_event_handler_->add(s.sockfd_);
2036 }
2037 }
2038 }
2039
2040 for (;;) {
2041 try {
2042 // Check the watch socket.
2043 if (dhcp_receiver_->shouldTerminate()) {
2044 isc_throw(ReceiveTerminate, "entry");
2045 }
2046
2047 // zero out the errno to be safe.
2048 errno = 0;
2049
2050 // Select with null timeouts to wait indefinitely an event
2051 int result = receiver_fd_event_handler_->waitEvent(0, 0, false);
2052
2053 // Re-check the watch socket.
2054 if (dhcp_receiver_->shouldTerminate()) {
2055 isc_throw(ReceiveTerminate, "waitEvent");
2056 }
2057
2058 if (result == 0) {
2059 // nothing received?
2060 continue;
2061 } else if (result < 0) {
2062 // This thread should not get signals?
2063 if (errno != EINTR) {
2064 {
2065 std::lock_guard<std::mutex> lk(receiver_mutex_);
2066 // Signal the error to receive6.
2067 dhcp_receiver_->setError(strerror(errno));
2068 }
2069 // We need to sleep in case of the error condition to
2070 // prevent the thread from tight looping when result
2071 // gets negative.
2072 sleep(1);
2073 }
2074 continue;
2075 }
2076
2077 // Body.
2078 scanReceiveDHCP6Packets();
2079
2080 } catch (const ReceiveTerminate&) {
2081 return;
2082 } catch (const std::exception& ex) {
2083 std::lock_guard<std::mutex> lk(receiver_mutex_);
2084 dhcp_receiver_->setError(string(ex.what()) + " error: " + strerror(errno));
2085 } catch (...) {
2086 std::lock_guard<std::mutex> lk(receiver_mutex_);
2087 dhcp_receiver_->setError("receive failed");
2088 }
2089 }
2090}
2091
2092void
2093IfaceMgr::receiveDHCP4Packet(Iface& iface, const SocketInfo& socket_info) {
2094 int len;
2095
2096 int result = ioctl(socket_info.sockfd_, FIONREAD, &len);
2097 if (result < 0) {
2098 std::lock_guard<std::mutex> lk(receiver_mutex_);
2099 // Signal the error to receive4.
2100 dhcp_receiver_->setError(strerror(errno));
2101 return;
2102 }
2103 if (len == 0) {
2104 // Nothing to read.
2105 return;
2106 }
2107
2108 Pkt4Ptr pkt;
2109
2110 try {
2111 pkt = packet_filter_->receive(iface, socket_info);
2112 } catch (const std::exception& ex) {
2113 std::lock_guard<std::mutex> lk(receiver_mutex_);
2114 dhcp_receiver_->setError(ex.what());
2115 } catch (...) {
2116 std::lock_guard<std::mutex> lk(receiver_mutex_);
2117 dhcp_receiver_->setError("packet filter receive() failed");
2118 }
2119
2120 if (pkt) {
2121 std::lock_guard<std::mutex> lk(receiver_mutex_);
2122 getPacketQueue4()->enqueuePacket(pkt, socket_info);
2123 dhcp_receiver_->markReady(WatchedThread::READY);
2124 }
2125}
2126
2127void
2128IfaceMgr::receiveDHCP6Packet(const SocketInfo& socket_info) {
2129 int len;
2130
2131 int result = ioctl(socket_info.sockfd_, FIONREAD, &len);
2132 if (result < 0) {
2133 std::lock_guard<std::mutex> lk(receiver_mutex_);
2134 // Signal the error to receive6.
2135 dhcp_receiver_->setError(strerror(errno));
2136 return;
2137 }
2138 if (len == 0) {
2139 // Nothing to read.
2140 return;
2141 }
2142
2143 Pkt6Ptr pkt;
2144
2145 try {
2146 pkt = packet_filter6_->receive(socket_info);
2147 } catch (const std::exception& ex) {
2148 std::lock_guard<std::mutex> lk(receiver_mutex_);
2149 dhcp_receiver_->setError(ex.what());
2150 } catch (...) {
2151 std::lock_guard<std::mutex> lk(receiver_mutex_);
2152 dhcp_receiver_->setError("packet filter receive() failed");
2153 }
2154
2155 if (pkt) {
2156 std::lock_guard<std::mutex> lk(receiver_mutex_);
2157 getPacketQueue6()->enqueuePacket(pkt, socket_info);
2158 dhcp_receiver_->markReady(WatchedThread::READY);
2159 }
2160}
2161
2162uint16_t
2164 IfacePtr iface = getIface(pkt);
2165 if (!iface) {
2166 isc_throw(IfaceNotFound, "Tried to find socket for non-existent interface");
2167 }
2168
2169 const Iface::SocketCollection& socket_collection = iface->getSockets();
2170
2171 Iface::SocketCollection::const_iterator candidate = socket_collection.end();
2172
2173 Iface::SocketCollection::const_iterator s;
2174 for (s = socket_collection.begin(); s != socket_collection.end(); ++s) {
2175
2176 // We should not merge those conditions for debugging reasons.
2177
2178 // V4 sockets are useless for sending v6 packets.
2179 if (s->family_ != AF_INET6) {
2180 continue;
2181 }
2182
2183 // Sockets bound to multicast address are useless for sending anything.
2184 if (s->addr_.isV6Multicast()) {
2185 continue;
2186 }
2187
2188 if (s->addr_ == pkt->getLocalAddr()) {
2189 // This socket is bound to the source address. This is perfect
2190 // match, no need to look any further.
2191 return (s->sockfd_);
2192 }
2193
2194 // If we don't have any other candidate, this one will do
2195 if (candidate == socket_collection.end()) {
2196 candidate = s;
2197 } else {
2198 // If we want to send something to link-local and the socket is
2199 // bound to link-local or we want to send to global and the socket
2200 // is bound to global, then use it as candidate
2201 if ((pkt->getRemoteAddr().isV6LinkLocal() &&
2202 s->addr_.isV6LinkLocal()) ||
2203 (!pkt->getRemoteAddr().isV6LinkLocal() &&
2204 !s->addr_.isV6LinkLocal())) {
2205 candidate = s;
2206 }
2207 }
2208 }
2209
2210 if (candidate != socket_collection.end()) {
2211 return (candidate->sockfd_);
2212 }
2213
2214 isc_throw(SocketNotFound, "Interface " << iface->getFullName()
2215 << " does not have any suitable IPv6 sockets open.");
2216}
2217
2220 IfacePtr iface = getIface(pkt);
2221 if (!iface) {
2222 isc_throw(IfaceNotFound, "Tried to find socket for non-existent interface");
2223 }
2224
2225 const Iface::SocketCollection& socket_collection = iface->getSockets();
2226 // A candidate being an end of the iterator marks that it is a beginning of
2227 // the socket search and that the candidate needs to be set to the first
2228 // socket found.
2229 Iface::SocketCollection::const_iterator candidate = socket_collection.end();
2230 Iface::SocketCollection::const_iterator s;
2231 for (s = socket_collection.begin(); s != socket_collection.end(); ++s) {
2232 if (s->family_ == AF_INET) {
2233 if (s->addr_ == pkt->getLocalAddr()) {
2234 return (*s);
2235 }
2236
2237 if (candidate == socket_collection.end()) {
2238 candidate = s;
2239 }
2240 }
2241 }
2242
2243 if (candidate == socket_collection.end()) {
2244 isc_throw(SocketNotFound, "Interface " << iface->getFullName()
2245 << " does not have any suitable IPv4 sockets open.");
2246 }
2247
2248 return (*candidate);
2249}
2250
2251bool
2253 if (isDHCPReceiverRunning()) {
2254 isc_throw(InvalidOperation, "Cannot reconfigure queueing"
2255 " while DHCP receiver thread is running");
2256 }
2257
2258 bool enable_queue = false;
2259 if (queue_control) {
2260 try {
2261 enable_queue = data::SimpleParser::getBoolean(queue_control, "enable-queue");
2262 } catch (...) {
2263 // @todo - for now swallow not found errors.
2264 // if not present we assume default
2265 }
2266 }
2267
2268 if (enable_queue) {
2269 // Try to create the queue as configured.
2270 if (family == AF_INET) {
2271 packet_queue_mgr4_->createPacketQueue(queue_control);
2272 } else {
2273 packet_queue_mgr6_->createPacketQueue(queue_control);
2274 }
2275 } else {
2276 // Destroy the current queue (if one), this inherently disables threading.
2277 if (family == AF_INET) {
2278 packet_queue_mgr4_->destroyPacketQueue();
2279 } else {
2280 packet_queue_mgr6_->destroyPacketQueue();
2281 }
2282 }
2283
2284 return (enable_queue);
2285}
2286
2287void
2288Iface::addError(std::string const& message) {
2289 errors_.push_back(message);
2290}
2291
2292void
2294 errors_.clear();
2295}
2296
2297Iface::ErrorBuffer const&
2299 return errors_;
2300}
2301
2302bool
2304 if (test_mode_ && update_only) {
2305 return (false);
2306 }
2307 return (true);
2308}
2309
2310} // end of namespace isc::dhcp
2311} // 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:300
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:355
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:350
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
bool isMainThread() const
Check if called from the main thread.
Definition iface_mgr.h:875
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:128
@ error
Definition db_log.h:126
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:1005
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