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