Kea  1.9.9-git
iface_mgr.cc
Go to the documentation of this file.
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>
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>
15 #include <dhcp/pkt_filter_inet.h>
16 #include <dhcp/pkt_filter_inet6.h>
17 #include <exceptions/exceptions.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&
53 IfaceMgr::instance() {
54  return (*instancePtr());
55 }
56 
57 const IfaceMgrPtr&
58 IfaceMgr::instancePtr() {
59  static IfaceMgrPtr iface_mgr(new IfaceMgr());
60  return (iface_mgr);
61 }
62 
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
78  // Close IPv4 sockets.
79  closeSockets(AF_INET);
80  // Close IPv6 sockets.
81  closeSockets(AF_INET6);
82 }
83 
84 void
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
125  ostringstream tmp;
126  tmp << name_ << "/" << ifindex_;
127  return (tmp.str());
128 }
129 
130 std::string
132  ostringstream tmp;
133  tmp.fill('0');
134  tmp << hex;
135  for (int i = 0; i < mac_len_; i++) {
136  tmp.width(2);
137  tmp << static_cast<int>(mac_[i]);
138  if (i < mac_len_-1) {
139  tmp << ":";
140  }
141  }
142  return (tmp.str());
143 }
144 
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 
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 
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 
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) {
210  }
211 }
212 
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
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
241  for (Address addr : getAddresses()) {
242  if (address == addr.get()) {
243  return (true);
244  }
245  }
246  return (false);
247 }
248 
249 void
251  addrs_.push_back(Address(addr));
252 }
253 
254 void
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
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
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 
287  // Clears bound addresses.
289 
290  // Stops the receiver thread if there is one.
292 
293  for (IfacePtr iface : ifaces_) {
294  iface->closeSockets();
295  }
296 }
297 
299  if (isDHCPReceiverRunning()) {
300  dhcp_receiver_->stop();
301  }
302 
303  dhcp_receiver_.reset();
304 
305  if (getPacketQueue4()) {
306  getPacketQueue4()->clear();
307  }
308 
309  if (getPacketQueue6()) {
310  getPacketQueue6()->clear();
311  }
312 }
313 
315  closeSockets();
316 }
317 
318 bool
320  return (packet_filter_->isDirectResponseSupported());
321 }
322 
323 void
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
341  x.socket_ = socketfd;
342  x.callback_ = callback;
343  callbacks_.push_back(x);
344 }
345 
346 void
348  std::lock_guard<std::mutex> lock(callbacks_mutex_);
349  deleteExternalSocketInternal(socketfd);
350 }
351 
352 void
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
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
383  std::lock_guard<std::mutex> lock(callbacks_mutex_);
384  callbacks_.clear();
385 }
386 
387 void
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.
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
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.
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
430 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
446 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 
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?
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
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.
641 
642  // Starts the receiver thread (if queueing is enabled).
643  startDHCPReceiver(AF_INET);
644  }
645 
646  return (count > 0);
647 }
648 
649 bool
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
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
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
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
808 IfaceCollection::getIface(uint32_t ifindex) {
809  return (getIfaceInternal(ifindex, MultiThreadingMgr::instance().getMode()));
810 }
811 
812 
813 IfacePtr
814 IfaceCollection::getIface(const std::string& ifname) {
815  return (getIfaceInternal(ifname, MultiThreadingMgr::instance().getMode()));
816 }
817 
818 IfacePtr
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
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
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
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
892  if (pkt->indexSet()) {
893  return (getIface(pkt->getIndex()));
894  } else {
895  return (getIface(pkt->getIface()));
896  }
897 }
898 
899 void
901  ifaces_.clear();
902 }
903 
904 void
906  bound_address_.clear();
907 }
908 
909 void
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
926  for (IfacePtr iface : ifaces_) {
927  iface->clearUnicasts();
928  }
929 }
930 
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 
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 
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 
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) {
1022  }
1023 }
1024 
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
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
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
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 
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 
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();
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 
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 
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();
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
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
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
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 
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();
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
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();
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
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
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
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
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
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
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
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
SocketCallback callback_
A callback that will be called when data arrives over socket_.
Definition: iface_mgr.h:644
void clearIfaces()
Removes detected interfaces.
Definition: iface_mgr.cc:900
IfacePtr getIface(int ifindex)
Returns interface specified interface index.
Definition: iface_mgr.cc:875
Provides a thread and controls for monitoring its activities.
static bool getBoolean(isc::data::ConstElementPtr scope, const std::string &name)
Returns a boolean parameter from a scope.
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:1014
Pkt4Ptr receive4Direct(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets directly or data from external sockets.
Definition: iface_mgr.cc:1256
void collectBoundAddresses()
Collect the addresses all sockets are bound to.
Definition: iface_mgr.cc:910
IfaceMgr exception thrown thrown when socket opening or configuration failed.
Definition: iface_mgr.h:63
A generic exception that is thrown when a function is not implemented.
Packet Queue Manager for DHPCv6 servers.
void addSocket(const SocketInfo &sock)
Adds socket descriptor to an interface.
Definition: iface_mgr.h:318
IfaceMgr exception thrown when there is no suitable socket found.
Definition: iface_mgr.h:93
void setPacketFilter(const PktFilterPtr &packet_filter)
Set packet filter object to handle sending and receiving DHCPv4 messages.
Definition: iface_mgr.cc:388
bool isDHCPReceiverRunning() const
Returns true if there is a receiver exists and its thread is currently running.
Definition: iface_mgr.h:1251
static const unsigned int MAX_MAC_LEN
Maximum MAC address length (Infiniband uses 20 bytes)
Definition: iface_mgr.h:122
size_t mac_len_
Length of link-layer address (usually 6).
Definition: iface_mgr.h:415
Pkt6Ptr receive6Indirect(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv6 packets indirectly or data from external sockets.
Definition: iface_mgr.cc:1524
void addExternalSocket(int socketfd, SocketCallback callback)
Adds external socket and a callback.
Definition: iface_mgr.cc:324
bool delSocket(uint16_t sockfd)
Closes socket.
Definition: iface_mgr.cc:169
IfaceMgr exception thrown thrown when interface detection fails.
Definition: iface_mgr.h:41
void addUnicast(const isc::asiolink::IOAddress &addr)
Adds unicast the server should listen on.
Definition: iface_mgr.cc:213
boost::shared_ptr< Iface > IfacePtr
Type definition for the pointer to an Iface object.
Definition: iface_mgr.h:463
std::string getPlainMac() const
Returns link-layer address a plain text.
Definition: iface_mgr.cc:131
#define FD_COPY(orig, copy)
Definition: iface_mgr.cc:37
void startDHCPReceiver(const uint16_t family)
Starts DHCP packet receiver.
Definition: iface_mgr.cc:738
#define DHCP_IPV4_BROADCAST_ADDRESS
Definition: dhcp4.h:42
int ifindex_
Interface index (a value that uniquely identifies an interface).
Definition: iface_mgr.h:403
void setActive(const isc::asiolink::IOAddress &address, const bool active)
Activates or deactivates address for the interface.
Definition: iface_mgr.cc:255
std::list< SocketInfo > SocketCollection
Type that holds a list of socket information.
Definition: iface_mgr.h:139
unsigned int countActive4() const
Returns a number of activated IPv4 addresses on the interface.
Definition: iface_mgr.cc:276
STL namespace.
AddressCollection unicasts_
List of unicast addresses the server should listen on.
Definition: iface_mgr.h:409
int purgeBadSockets()
Scans registered socket set and removes any that are invalid.
Definition: iface_mgr.cc:364
bool openSockets6(const uint16_t port=DHCP6_SERVER_PORT, IfaceMgrErrorMsgCallback error_handler=0)
Opens IPv6 sockets on detected interfaces.
Definition: iface_mgr.cc:650
std::function< void(const std::string &errmsg)> IfaceMgrErrorMsgCallback
This type describes the callback function invoked when error occurs in the IfaceMgr.
Definition: iface_mgr.h:624
PacketQueue6Ptr getPacketQueue6()
Fetches the DHCPv6 receiver packet queue.
Definition: iface_mgr.h:1227
bool hasAddress(const isc::asiolink::IOAddress &address) const
Check if the interface has the specified address assigned.
Definition: iface_mgr.cc:240
Handles network interfaces, transmission and reception.
Definition: iface_mgr.h:632
Packet handling class using AF_INET socket family.
Represents a single network interface.
Definition: iface_mgr.h:118
int openSocketFromAddress(const isc::asiolink::IOAddress &addr, const uint16_t port)
Opens UDP/IP socket and binds to address specified.
Definition: iface_mgr.cc:991
boost::shared_ptr< PktFilter > PktFilterPtr
Pointer to a PktFilter object.
Definition: pkt_filter.h:134
int sockfd_
IPv4 or IPv6.
Definition: socket_info.h:26
bool send(const Pkt6Ptr &pkt)
Sends an IPv6 packet.
Definition: iface_mgr.cc:1101
void closeSockets()
Closes all open sockets on interface.
Definition: iface_mgr.cc:77
Keeps callback information for external sockets.
Definition: iface_mgr.h:639
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition: pkt6.h:28
Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets or data from external sockets.
Definition: iface_mgr.cc:1126
Definition: edns.h:19
IfaceMgr exception thrown when there is no suitable interface.
Definition: iface_mgr.h:86
void deleteExternalSocket(int socketfd)
Deletes external socket.
Definition: iface_mgr.cc:347
BoundAddresses bound_address_
Unordered set of IPv4 bound addresses.
Definition: iface_mgr.h:1424
A generic exception that is thrown when an unexpected error condition occurs.
Exception thrown when invalid packet filter object specified.
Definition: pkt_filter.h:18
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition: pkt4.h:544
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:23
void clearUnicasts()
Clears unicast addresses on all interfaces.
Definition: iface_mgr.cc:925
Packet Queue Manager for DHPCv4 servers.
IfacePtr getIface(uint32_t ifindex)
Lookup by interface index.
Definition: iface_mgr.cc:808
void clearBoundAddresses()
Clears the addresses all sockets are bound to.
Definition: iface_mgr.cc:905
IfaceMgr exception thrown thrown when error occurred during reading data from socket.
Definition: iface_mgr.h:71
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
Definition: pkt.h:797
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
void deleteAllExternalSockets()
Deletes all external sockets.
Definition: iface_mgr.cc:382
bool getAddress4(isc::asiolink::IOAddress &address) const
Returns IPv4 address assigned to the interface.
Definition: iface_mgr.cc:224
void addInterface(const IfacePtr &iface)
Adds an interface to list of known interfaces.
Definition: iface_mgr.cc:771
std::string getName() const
Returns interface name.
Definition: iface_mgr.h:221
std::function< void(int fd)> SocketCallback
Defines callback used when data is received over external sockets.
Definition: iface_mgr.h:636
This is a base class for exceptions thrown from the DNS library module.
Defines the logger used by the top-level component of kea-dhcp-ddns.
AddressCollection addrs_
List of assigned addresses.
Definition: iface_mgr.h:406
std::list< Address > AddressCollection
Type that defines list of addresses.
Definition: iface_mgr.h:128
bool hasOpenSocket(const uint16_t family) const
Checks if there is at least one socket of the specified family open.
Definition: iface_mgr.cc:430
boost::shared_ptr< PktFilter6 > PktFilter6Ptr
Pointer to a PktFilter object.
Definition: pkt_filter6.h:136
std::string getFullName() const
Returns full interface name as "ifname/ifindex" string.
Definition: iface_mgr.cc:124
util::Optional< asiolink::IOAddress > Address
Address type.
Definition: iface_mgr.h:125
Exception thrown when a call to select is interrupted by a signal.
Definition: iface_mgr.h:55
#define IFACEMGR_ERROR(ex_type, handler, stream)
A macro which handles an error in IfaceMgr.
const Name & name_
Definition: dns/message.cc:693
void closeSockets()
Closes all open sockets.
Definition: iface_mgr.cc:286
A generic exception that is thrown if a function is called in a prohibited way.
SocketCollection sockets_
Socket used to send data.
Definition: iface_mgr.h:397
bool delAddress(const isc::asiolink::IOAddress &addr)
Deletes an address from an interface.
Definition: iface_mgr.cc:158
uint8_t mac_[MAX_MAC_LEN]
Link-layer address.
Definition: iface_mgr.h:412
A DHCPv6 packet handling class using datagram sockets.
uint16_t getSocket(const isc::dhcp::Pkt6Ptr &pkt)
Return most suitable socket for transmitting specified IPv6 packet.
Definition: iface_mgr.cc:1855
void detectIfaces()
Detects network interfaces.
void addAddress(const isc::asiolink::IOAddress &addr)
Adds an address to an interface.
Definition: iface_mgr.cc:250
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:931
virtual ~IfaceMgr()
Destructor.
Definition: iface_mgr.cc:314
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
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:950
static void addFDtoSet(int fd, int &maxfd, fd_set *sockets)
Convenience method for adding an descriptor to a set.
Definition: iface_mgr.cc:1390
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:1088
PacketQueue4Ptr getPacketQueue4()
Fetches the DHCPv4 receiver packet queue.
Definition: iface_mgr.h:1210
IfaceMgr()
Protected constructor.
Definition: iface_mgr.cc:186
Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets or data from external sockets.
Definition: iface_mgr.cc:1381
bool isDirectResponseSupported() const
Check if packet be sent directly to the client having no address.
Definition: iface_mgr.cc:319
int openSocket6(Iface &iface, const isc::asiolink::IOAddress &addr, uint16_t port, const bool join_multicast)
Opens IPv6 socket.
int socket_
Socket descriptor of the external socket.
Definition: iface_mgr.h:641
void printIfaces(std::ostream &out=std::cout)
Debugging method that prints out all available interfaces.
Definition: iface_mgr.cc:784
Pkt6Ptr receive6Direct(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv6 packets directly or data from external sockets.
Definition: iface_mgr.cc:1402
std::string name_
Network interface name.
Definition: iface_mgr.h:400
A template representing an optional value.
Definition: optional.h:36
void stopDHCPReceiver()
Stops the DHCP packet receiver.
Definition: iface_mgr.cc:298
Pkt4Ptr receive4Indirect(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets indirectly or data from external sockets.
Definition: iface_mgr.cc:1134
boost::shared_ptr< IfaceMgr > IfaceMgrPtr
Type definition for the pointer to the IfaceMgr.
Definition: iface_mgr.h:614
const AddressCollection & getAddresses() const
Returns all addresses available on an interface.
Definition: iface_mgr.h:251
void stubDetectIfaces()
Stub implementation of network interface detection.
Definition: iface_mgr.cc:479
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:518
Holds information about socket.
Definition: socket_info.h:19
Exception thrown when it is not allowed to set new Packet Filter.
Definition: iface_mgr.h:48
IfaceCollection ifaces_
List of available interfaces.
Definition: iface_mgr.h:1421
bool configureDHCPPacketQueue(const uint16_t family, data::ConstElementPtr queue_control)
Configures DHCP packet queue.
Definition: iface_mgr.cc:1945
void clear()
Clear the collection.
Definition: iface_mgr.h:532
void setMac(const uint8_t *mac, size_t macLen)
Sets MAC address of the interface.
Definition: iface_mgr.cc:145