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