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