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