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