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