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