26#include <boost/scoped_ptr.hpp>
36#include <netinet/in.h>
46namespace ph = std::placeholders;
69 isc_throw(BadValue,
"Interface name must not be empty");
93 if ((family != AF_INET) && (family != AF_INET6)) {
95 <<
" specified when requested to close all sockets"
96 <<
" which belong to this family");
100 SocketCollection::iterator sock =
sockets_.begin();
102 if (sock->family_ == family) {
105 close(sock->sockfd_);
107 if (sock->fallbackfd_ >= 0) {
108 close(sock->fallbackfd_);
131 for (
unsigned i = 0; i <
mac_len_; i++) {
133 tmp << static_cast<int>(
mac_[i]);
144 <<
" was detected to have link address of length "
145 << len <<
", but maximum supported length is "
150 memcpy(
mac_, mac, len);
155 for (AddressCollection::iterator a =
addrs_.begin(); a !=
addrs_.end(); ++a) {
156 if (a->get() == addr) {
165 SocketCollection::iterator sock =
sockets_.begin();
167 if (sock->sockfd_ == sockfd) {
170 if (sock->fallbackfd_ >= 0) {
171 close(sock->fallbackfd_);
184 test_mode_(false), check_thread_id_(true),
185 allow_loopback_(false), family_(AF_INET) {
186 id_ = std::this_thread::get_id();
193 }
catch (
const std::exception& ex) {
206 }
catch (
const std::exception& ex) {
220 if (a.get() == addr) {
222 <<
" already defined on the " <<
name_ <<
" interface.");
235 if (addr.get().isV4()) {
236 address = addr.get();
247 if (address == addr.get()) {
263 for (
auto& addr :
addrs_) {
264 if (address == addr.get()) {
265 addr.unspecified(!active);
270 " found on the interface " <<
getName());
275 for (
auto& addr :
addrs_) {
276 addr.unspecified(!active);
284 if (!addr.unspecified() && addr.get().isV4()) {
306 for (
auto const& addr :
addrs_) {
309 result->set(
"addresses", addrs);
321 iface->closeSockets();
327 dhcp_receiver_->stop();
330 dhcp_receiver_.reset();
350 for (
auto const& iface:
ifaces_) {
351 result->add(iface->toElement());
358 return (packet_filter_->isDirectResponseSupported());
363 return (packet_filter_->isSocketReceivedTimeSupported());
375 .arg(std::this_thread::get_id())
381 std::lock_guard<std::mutex> lock(callbacks_mutex_);
382 auto& idx = callbacks_.get<1>();
383 auto it = idx.find(socketfd);
384 if (it != idx.end()) {
394 callbacks_.push_back(x);
399 std::lock_guard<std::mutex> lock(callbacks_mutex_);
400 deleteExternalSocketInternal(socketfd);
404IfaceMgr::deleteExternalSocketInternal(
int socketfd) {
408 .arg(std::this_thread::get_id())
411 auto& idx = callbacks_.get<1>();
412 auto it = idx.find(socketfd);
413 if (it == idx.end()) {
423 std::lock_guard<std::mutex> lock(callbacks_mutex_);
424 auto const& idx = callbacks_.get<1>();
425 auto const it = idx.find(fd);
426 return (it != idx.end());
431 std::lock_guard<std::mutex> lock(callbacks_mutex_);
432 auto const& idx = callbacks_.get<1>();
433 auto const it = idx.find(fd);
434 if (it != idx.end()) {
435 return (it->unusable_);
445 .arg(std::this_thread::get_id())
448 std::lock_guard<std::mutex> lock(callbacks_mutex_);
454 std::list<int> result;
455 std::lock_guard<std::mutex> lock(callbacks_mutex_);
457 result.push_back(s.socket_);
465 if (!packet_filter) {
478 "it is not allowed to set new packet"
479 <<
" filter when there are open IPv4 sockets - need"
480 <<
" to close them first");
483 packet_filter_ = packet_filter;
488 if (!packet_filter) {
496 "it is not allowed to set new packet"
497 <<
" filter when there are open IPv6 sockets - need"
498 <<
" to close them first");
501 packet_filter6_ = packet_filter;
508 for (
const SocketInfo& sock : iface->getSockets()) {
510 if (sock.family_ == family) {
528 for (
const SocketInfo& sock : iface->getSockets()) {
531 if (sock.addr_ == addr) {
533 }
else if (sock.addr_.isV6Zero() && !unicast) {
540 if (addr == a.get()) {
557 const bool skip_opened) {
563 iface->clearErrors();
567 if (iface->inactive4_) {
578 if (iface->flag_loopback_ && !allow_loopback_) {
580 "must not open socket on the loopback"
581 " interface " << iface->getName());
585 if (!iface->flag_up_) {
587 "the interface " << iface->getName()
592 if (!iface->flag_running_) {
594 "the interface " << iface->getName()
595 <<
" is not running");
600 if (!iface->getAddress4(out_address)) {
602 "the interface " << iface->getName()
603 <<
" has no usable IPv4 addresses configured");
609 if (addr.unspecified() || !addr.get().isV4()) {
616 bool is_open_as_broadcast = iface->flag_broadcast_ && use_bcast;
633 "Binding socket to an interface is not"
634 " supported on this OS; therefore only"
635 " one socket listening to broadcast traffic"
636 " can be opened. Sockets will not be opened"
637 " on remaining interfaces");
649 is_open_as_broadcast,
650 is_open_as_broadcast);
653 "Failed to open socket on interface "
661 if (is_open_as_broadcast) {
687 const bool skip_opened) {
692 iface->clearErrors();
696 if (iface->inactive6_) {
707 if (iface->flag_loopback_ && !allow_loopback_) {
709 "must not open socket on the loopback"
710 " interface " << iface->getName());
712 }
else if (!iface->flag_up_) {
714 "the interface " << iface->getName()
717 }
else if (!iface->flag_running_) {
719 "the interface " << iface->getName()
720 <<
" is not running");
733 !iface->getSockets().size()) {
738 "Failed to open unicast socket on interface "
740 <<
", reason: " << ex.
what());
750 if (!addr.get().isV6()) {
759 if (!addr.get().isV6LinkLocal()) {
774 iface->getSockets().size() <= iface->getUnicasts().size()) {
778 IfaceMgr::openMulticastSocket(*iface, addr, port);
781 "Failed to open multicast socket on interface "
782 << iface->getName() <<
", reason: " << ex.
what());
814 dhcp_receiver_->start(std::bind(&IfaceMgr::receiveDHCP4Packets,
this));
824 dhcp_receiver_->start(std::bind(&IfaceMgr::receiveDHCP6Packets,
this));
835 if ((existing->getName() == iface->getName()) ||
836 (existing->getIndex() == iface->getIndex())) {
838 " when " << existing->getFullName() <<
850 out <<
"Detected interface " << iface->getFullName()
851 <<
", hwtype=" << iface->getHWType()
852 <<
", mac=" << iface->getPlainMac();
853 out <<
", flags=" << hex << iface->flags_ << dec <<
"("
854 << (iface->flag_loopback_?
"LOOPBACK ":
"")
855 << (iface->flag_up_?
"UP ":
"")
856 << (iface->flag_running_?
"RUNNING ":
"")
857 << (iface->flag_multicast_?
"MULTICAST ":
"")
858 << (iface->flag_broadcast_?
"BROADCAST ":
"")
860 out <<
" " << addrs.size() <<
" addr(s):";
863 out <<
" " << addr.get().toText();
880IfaceCollection::getIfaceInternal(
const unsigned int ifindex,
const bool need_lock) {
885 lock_guard<mutex> lock(mutex_);
886 if (cache_ && (cache_->getIndex() == ifindex)) {
890 if (cache_ && (cache_->getIndex() == ifindex)) {
894 auto const& idx = ifaces_container_.get<1>();
895 auto it = idx.find(ifindex);
896 if (it == idx.end()) {
900 lock_guard<mutex> lock(mutex_);
910IfaceCollection::getIfaceInternal(
const std::string& ifname,
const bool need_lock) {
912 lock_guard<mutex> lock(mutex_);
913 if (cache_ && (cache_->getName() == ifname)) {
917 if (cache_ && (cache_->getName() == ifname)) {
921 auto const& idx = ifaces_container_.get<2>();
922 auto it = idx.find(ifname);
923 if (it == idx.end()) {
927 lock_guard<mutex> lock(mutex_);
938 return (
ifaces_.getIface(ifindex));
943 if (ifname.empty()) {
946 return (
ifaces_.getIface(ifname));
951 if (pkt->indexSet()) {
969IfaceMgr::handleClosedExternalSocket(SocketCallbackInfoIterator it) {
971 if (fcntl(it->socket_, F_GETFD) < 0 && (errno == EBADF)) {
972 SocketCallbackInfo x(*it);
974 callbacks_.replace(it, x);
980IfaceMgr::handleClosedExternalSockets() {
981 std::lock_guard<std::mutex> lock(callbacks_mutex_);
982 for (
auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
986 handleClosedExternalSocket(it);
993 socklen_t opt_size =
sizeof(
error);
995 if (getsockopt(s.sockfd_, SOL_SOCKET, SO_ERROR,
996 reinterpret_cast<char*
>(&
error), &opt_size) < 0) {
997 if ((errno == ENOTSOCK) || (errno == ENOPROTOOPT)) {
1001 isc_throw(BadValue,
"Can't get socket error fd: "
1002 << s.sockfd_ <<
" - error: " << strerror(errno));
1007 .arg(iface->getFullName())
1008 .arg(strerror(
error));
1015 for (
const SocketInfo& sock : iface->getSockets()) {
1030 iface->clearUnicasts();
1035 const uint16_t port,
const bool receive_bcast,
1036 const bool send_bcast) {
1043 status =
openSocket4(*iface, addr, port, receive_bcast, send_bcast);
1045 }
else if (addr.
isV6()) {
1046 status =
openSocket6(*iface, addr, port, receive_bcast);
1060 const uint16_t port,
1061 const uint8_t family) {
1064 if ((iface->getFullName() != ifname) &&
1065 (iface->getName() != ifname)) {
1072 Iface::AddressCollection::iterator addr_it = addrs.begin();
1073 while (addr_it != addrs.end()) {
1074 if (addr_it->get().getFamily() == family) {
1077 return (
openSocket(iface->getName(), *addr_it, port,
false));
1083 if (addr_it == addrs.end()) {
1085 std::string family_name(
"AF_INET");
1086 if (family == AF_INET6) {
1087 family_name =
"AF_INET6";
1091 << ifname <<
", port: " << port <<
", address "
1092 " family: " << family_name);
1101 const uint16_t port) {
1111 if (a.get() == addr) {
1114 return (
openSocket(iface->getName(), a, port,
false));
1124 const uint16_t port) {
1127 IOAddress local_address(getLocalAddress(remote_addr, port));
1135IfaceMgr::getLocalAddress(
const IOAddress& remote_addr,
const uint16_t port) {
1137 boost::scoped_ptr<const UDPEndpoint>
1140 if (!remote_endpoint) {
1145 boost::asio::io_context io_service;
1146 boost::asio::ip::udp::socket sock(io_service);
1148 boost::system::error_code err_code;
1151 if (remote_addr.
isV4() &&
1164 sock.open(boost::asio::ip::udp::v4(), err_code);
1166 const char* errstr = strerror(errno);
1170 sock.set_option(boost::asio::socket_base::broadcast(
true), err_code);
1178 sock.connect(remote_endpoint->getASIOEndpoint(), err_code);
1181 isc_throw(Unexpected,
"failed to connect to remote endpoint.");
1185 boost::asio::ip::udp::socket::endpoint_type local_endpoint =
1186 sock.local_endpoint();
1187 boost::asio::ip::address local_address(local_endpoint.address());
1193 return IOAddress(local_address);
1198 const bool receive_bcast,
const bool send_bcast) {
1201 receive_bcast, send_bcast);
1204 return (
info.sockfd_);
1212 << pkt->getIface() <<
") specified.");
1217 return (packet_filter6_->send(*iface,
getSocket(pkt), pkt) == 0);
1225 << pkt->getIface() <<
") specified.");
1230 return (packet_filter_->send(*iface,
getSocket(pkt).sockfd_, pkt) == 0);
1243 if (timeout_usec >= 1000000) {
1245 " one million microseconds");
1248 fd_event_handler_->clear();
1252 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1253 if (!callbacks_.empty()) {
1254 for (
auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1255 if (it->unusable_) {
1258 handleClosedExternalSocket(it);
1260 fd_event_handler_->add(it->socket_);
1285 int result = fd_event_handler_->waitEvent(timeout_sec, timeout_usec);
1290 }
else if (result < 0) {
1298 if (errno == EINTR) {
1300 }
else if (errno == EBADF) {
1301 handleClosedExternalSockets();
1310 std::lock_guard<std::mutex> lk(receiver_mutex_);
1313 string msg = dhcp_receiver_->getLastError();
1320 boost::scoped_ptr<SocketCallbackInfo> ex_sock;
1323 std::list<SocketCallbackInfoIterator> to_reloc;
1324 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1325 for (
auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1326 if (it->unusable_) {
1329 handleClosedExternalSocket(it);
1330 if (fd_event_handler_->readReady(it->socket_) ||
1331 fd_event_handler_->hasError(it->socket_)) {
1333 to_reloc.push_back(it);
1336 if (it->callback_) {
1345 for (
auto it : to_reloc) {
1346 callbacks_.relocate(callbacks_.end(), it);
1351 if (ex_sock && ex_sock->callback_) {
1355 ex_sock->callback_(ex_sock->socket_);
1360 std::lock_guard<std::mutex> lk(receiver_mutex_);
1371 if (timeout_usec >= 1000000) {
1373 " one million microseconds");
1376 fd_event_handler_->clear();
1384 for (
const SocketInfo& s : iface->getSockets()) {
1386 if (s.addr_.isV4()) {
1388 fd_event_handler_->add(s.sockfd_);
1395 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1396 if (!callbacks_.empty()) {
1397 for (
auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1398 if (it->unusable_) {
1401 handleClosedExternalSocket(it);
1403 fd_event_handler_->add(it->socket_);
1411 int result = fd_event_handler_->waitEvent(timeout_sec, timeout_usec);
1416 }
else if (result < 0) {
1424 if (errno == EINTR) {
1426 }
else if (errno == EBADF) {
1427 handleClosedExternalSockets();
1434 boost::scoped_ptr<SocketCallbackInfo> ex_sock;
1437 std::list<SocketCallbackInfoIterator> to_reloc;
1438 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1439 for (
auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1440 if (it->unusable_) {
1443 handleClosedExternalSocket(it);
1444 if (fd_event_handler_->readReady(it->socket_) ||
1445 fd_event_handler_->hasError(it->socket_)) {
1447 to_reloc.push_back(it);
1450 if (it->callback_) {
1459 for (
auto it : to_reloc) {
1460 callbacks_.relocate(callbacks_.end(), it);
1465 if (ex_sock && ex_sock->callback_) {
1469 ex_sock->callback_(ex_sock->socket_);
1473 boost::scoped_ptr<SocketInfo> candidate;
1475 std::list<IfaceCollection::LruIterator> ifaces_to_reloc;
1477 for (
auto iit = iidx.begin(); iit != iidx.end(); ++iit) {
1478 std::list<Iface::SocketLruIterator> sockets_to_reloc;
1481 for (
auto sit = sidx.begin(); sit != sidx.end(); ++sit) {
1482 if (!fd_event_handler_->readReady(sit->sockfd_) &&
1483 !fd_event_handler_->hasError(sit->sockfd_)) {
1486 ifaces_to_reloc.push_back(iit);
1487 sockets_to_reloc.push_back(sit);
1488 if (fd_event_handler_->hasError(sit->sockfd_)) {
1489 handleIfaceSocketError(*iit, *sit);
1494 if (!sockets_to_reloc.empty()) {
1495 for (
auto it : sockets_to_reloc) {
1496 sidx.relocate(sidx.end(), it);
1504 if (!ifaces_to_reloc.empty()) {
1505 for (
auto it : ifaces_to_reloc) {
1506 iidx.relocate(iidx.end(), it);
1510 if (!candidate || !recv_if) {
1519 if (ioctl(candidate->sockfd_, FIONREAD, &len) < 0) {
1528 return (packet_filter_->receive(*recv_if, *candidate));
1543 if (timeout_usec >= 1000000) {
1545 " one million microseconds");
1548 fd_event_handler_->clear();
1556 for (
const SocketInfo& s : iface->getSockets()) {
1558 if (s.addr_.isV6()) {
1560 fd_event_handler_->add(s.sockfd_);
1567 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1568 if (!callbacks_.empty()) {
1569 for (
auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1570 if (it->unusable_) {
1573 handleClosedExternalSocket(it);
1575 fd_event_handler_->add(it->socket_);
1583 int result = fd_event_handler_->waitEvent(timeout_sec, timeout_usec);
1588 }
else if (result < 0) {
1596 if (errno == EINTR) {
1598 }
else if (errno == EBADF) {
1599 handleClosedExternalSockets();
1606 boost::scoped_ptr<SocketCallbackInfo> ex_sock;
1609 std::list<SocketCallbackInfoIterator> to_reloc;
1610 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1611 for (
auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1612 if (it->unusable_) {
1615 handleClosedExternalSocket(it);
1616 if (fd_event_handler_->readReady(it->socket_) ||
1617 fd_event_handler_->hasError(it->socket_)) {
1619 to_reloc.push_back(it);
1622 if (it->callback_) {
1631 for (
auto it : to_reloc) {
1632 callbacks_.relocate(callbacks_.end(), it);
1637 if (ex_sock && ex_sock->callback_) {
1641 ex_sock->callback_(ex_sock->socket_);
1645 boost::scoped_ptr<SocketInfo> candidate;
1647 std::list<IfaceCollection::LruIterator> ifaces_to_reloc;
1649 for (
auto iit = iidx.begin(); iit != iidx.end(); ++iit) {
1650 std::list<Iface::SocketLruIterator> sockets_to_reloc;
1653 for (
auto sit = sidx.begin(); sit != sidx.end(); ++sit) {
1654 if (!fd_event_handler_->readReady(sit->sockfd_) &&
1655 !fd_event_handler_->hasError(sit->sockfd_)) {
1658 ifaces_to_reloc.push_back(iit);
1659 sockets_to_reloc.push_back(sit);
1660 if (fd_event_handler_->hasError(sit->sockfd_)) {
1661 handleIfaceSocketError(*iit, *sit);
1666 if (!sockets_to_reloc.empty()) {
1667 for (
auto it : sockets_to_reloc) {
1668 sidx.relocate(sidx.end(), it);
1676 if (!ifaces_to_reloc.empty()) {
1677 for (
auto it : ifaces_to_reloc) {
1678 iidx.relocate(iidx.end(), it);
1691 if (ioctl(candidate->sockfd_, FIONREAD, &len) < 0) {
1700 return (packet_filter6_->receive(*candidate));
1706 if (timeout_usec >= 1000000) {
1708 " one million microseconds");
1711 fd_event_handler_->clear();
1715 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1716 if (!callbacks_.empty()) {
1717 for (
auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1718 if (it->unusable_) {
1721 handleClosedExternalSocket(it);
1723 fd_event_handler_->add(it->socket_);
1748 int result = fd_event_handler_->waitEvent(timeout_sec, timeout_usec);
1753 }
else if (result < 0) {
1761 if (errno == EINTR) {
1763 }
else if (errno == EBADF) {
1764 handleClosedExternalSockets();
1773 std::lock_guard<std::mutex> lk(receiver_mutex_);
1776 string msg = dhcp_receiver_->getLastError();
1783 boost::scoped_ptr<SocketCallbackInfo> ex_sock;
1786 std::list<SocketCallbackInfoIterator> to_reloc;
1787 std::lock_guard<std::mutex> lock(callbacks_mutex_);
1788 for (
auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
1789 if (it->unusable_) {
1792 handleClosedExternalSocket(it);
1793 if (fd_event_handler_->readReady(it->socket_) ||
1794 fd_event_handler_->hasError(it->socket_)) {
1796 to_reloc.push_back(it);
1799 if (it->callback_) {
1808 for (
auto it : to_reloc) {
1809 callbacks_.relocate(callbacks_.end(), it);
1814 if (ex_sock && ex_sock->callback_) {
1818 ex_sock->callback_(ex_sock->socket_);
1823 std::lock_guard<std::mutex> lk(receiver_mutex_);
1833IfaceMgr::scanReceiveDHCP4Packets() {
1835 std::list<IfaceCollection::LruIterator> ifaces_to_reloc;
1838 for (
auto iit = iidx.begin(); iit != iidx.end(); ++iit) {
1839 std::list<Iface::SocketLruIterator> sockets_to_reloc;
1842 bool to_reloc =
false;
1844 for (
auto sit = sidx.begin(); sit != sidx.end(); ++sit) {
1845 if (!receiver_fd_event_handler_->readReady(sit->sockfd_) &&
1846 !receiver_fd_event_handler_->hasError(sit->sockfd_)) {
1850 ifaces_to_reloc.push_back(iit);
1853 sockets_to_reloc.push_back(sit);
1854 if (receiver_fd_event_handler_->hasError(sit->sockfd_)) {
1855 handleIfaceSocketError(*iit, *sit);
1857 receiveDHCP4Packet(**iit, *sit);
1859 if (dhcp_receiver_->shouldTerminate()) {
1860 isc_throw(ReceiveTerminate,
"receiveDHCP4Packet");
1863 if (!sockets_to_reloc.empty()) {
1864 for (
auto it : sockets_to_reloc) {
1865 sidx.relocate(sidx.end(), it);
1869 if (!sockets_to_reloc.empty()) {
1870 for (
auto it : sockets_to_reloc) {
1871 sidx.relocate(sidx.end(), it);
1877 if (!ifaces_to_reloc.empty()) {
1878 for (
auto it : ifaces_to_reloc) {
1879 iidx.relocate(iidx.end(), it);
1883 if (!ifaces_to_reloc.empty()) {
1884 for (
auto it : ifaces_to_reloc) {
1885 iidx.relocate(iidx.end(), it);
1893IfaceMgr::receiveDHCP4Packets() {
1894 receiver_fd_event_handler_->clear();
1901 for (
const SocketInfo& s : iface->getSockets()) {
1903 if (s.addr_.isV4()) {
1905 receiver_fd_event_handler_->add(s.sockfd_);
1913 if (dhcp_receiver_->shouldTerminate()) {
1921 int result = receiver_fd_event_handler_->waitEvent(0, 0,
false);
1924 if (dhcp_receiver_->shouldTerminate()) {
1925 isc_throw(ReceiveTerminate,
"waitEvent");
1931 }
else if (result < 0) {
1933 if (errno != EINTR) {
1935 std::lock_guard<std::mutex> lk(receiver_mutex_);
1937 dhcp_receiver_->setError(strerror(errno));
1948 scanReceiveDHCP4Packets();
1950 }
catch (
const ReceiveTerminate&) {
1952 }
catch (
const std::exception& ex) {
1953 std::lock_guard<std::mutex> lk(receiver_mutex_);
1954 dhcp_receiver_->setError(
string(ex.what()) +
" error: " + strerror(errno));
1956 std::lock_guard<std::mutex> lk(receiver_mutex_);
1957 dhcp_receiver_->setError(
"receive failed");
1963IfaceMgr::scanReceiveDHCP6Packets() {
1965 std::list<IfaceCollection::LruIterator> ifaces_to_reloc;
1968 for (
auto iit = iidx.begin(); iit != iidx.end(); ++iit) {
1969 std::list<Iface::SocketLruIterator> sockets_to_reloc;
1972 bool to_reloc =
false;
1974 for (
auto sit = sidx.begin(); sit != sidx.end(); ++sit) {
1975 if (!receiver_fd_event_handler_->readReady(sit->sockfd_) &&
1976 !receiver_fd_event_handler_->hasError(sit->sockfd_)) {
1980 ifaces_to_reloc.push_back(iit);
1983 sockets_to_reloc.push_back(sit);
1984 if (receiver_fd_event_handler_->hasError(sit->sockfd_)) {
1985 handleIfaceSocketError(*iit, *sit);
1987 receiveDHCP6Packet(*sit);
1989 if (dhcp_receiver_->shouldTerminate()) {
1990 isc_throw(ReceiveTerminate,
"receiveDHCP6Packet");
1993 if (!sockets_to_reloc.empty()) {
1994 for (
auto it : sockets_to_reloc) {
1995 sidx.relocate(sidx.end(), it);
1999 if (!sockets_to_reloc.empty()) {
2000 for (
auto it : sockets_to_reloc) {
2001 sidx.relocate(sidx.end(), it);
2007 if (!ifaces_to_reloc.empty()) {
2008 for (
auto it : ifaces_to_reloc) {
2009 iidx.relocate(iidx.end(), it);
2013 if (!ifaces_to_reloc.empty()) {
2014 for (
auto it : ifaces_to_reloc) {
2015 iidx.relocate(iidx.end(), it);
2023IfaceMgr::receiveDHCP6Packets() {
2024 receiver_fd_event_handler_->clear();
2031 for (
const SocketInfo& s : iface->getSockets()) {
2033 if (s.addr_.isV6()) {
2035 receiver_fd_event_handler_->add(s.sockfd_);
2043 if (dhcp_receiver_->shouldTerminate()) {
2051 int result = receiver_fd_event_handler_->waitEvent(0, 0,
false);
2054 if (dhcp_receiver_->shouldTerminate()) {
2055 isc_throw(ReceiveTerminate,
"waitEvent");
2061 }
else if (result < 0) {
2063 if (errno != EINTR) {
2065 std::lock_guard<std::mutex> lk(receiver_mutex_);
2067 dhcp_receiver_->setError(strerror(errno));
2078 scanReceiveDHCP6Packets();
2080 }
catch (
const ReceiveTerminate&) {
2082 }
catch (
const std::exception& ex) {
2083 std::lock_guard<std::mutex> lk(receiver_mutex_);
2084 dhcp_receiver_->setError(
string(ex.what()) +
" error: " + strerror(errno));
2086 std::lock_guard<std::mutex> lk(receiver_mutex_);
2087 dhcp_receiver_->setError(
"receive failed");
2093IfaceMgr::receiveDHCP4Packet(
Iface& iface,
const SocketInfo& socket_info) {
2096 int result = ioctl(socket_info.sockfd_, FIONREAD, &len);
2098 std::lock_guard<std::mutex> lk(receiver_mutex_);
2100 dhcp_receiver_->setError(strerror(errno));
2111 pkt = packet_filter_->receive(iface, socket_info);
2112 }
catch (
const std::exception& ex) {
2113 std::lock_guard<std::mutex> lk(receiver_mutex_);
2114 dhcp_receiver_->setError(ex.what());
2116 std::lock_guard<std::mutex> lk(receiver_mutex_);
2117 dhcp_receiver_->setError(
"packet filter receive() failed");
2121 std::lock_guard<std::mutex> lk(receiver_mutex_);
2128IfaceMgr::receiveDHCP6Packet(
const SocketInfo& socket_info) {
2131 int result = ioctl(socket_info.sockfd_, FIONREAD, &len);
2133 std::lock_guard<std::mutex> lk(receiver_mutex_);
2135 dhcp_receiver_->setError(strerror(errno));
2146 pkt = packet_filter6_->receive(socket_info);
2147 }
catch (
const std::exception& ex) {
2148 std::lock_guard<std::mutex> lk(receiver_mutex_);
2149 dhcp_receiver_->setError(ex.what());
2151 std::lock_guard<std::mutex> lk(receiver_mutex_);
2152 dhcp_receiver_->setError(
"packet filter receive() failed");
2156 std::lock_guard<std::mutex> lk(receiver_mutex_);
2171 Iface::SocketCollection::const_iterator candidate = socket_collection.end();
2173 Iface::SocketCollection::const_iterator s;
2174 for (s = socket_collection.begin(); s != socket_collection.end(); ++s) {
2179 if (s->family_ != AF_INET6) {
2184 if (s->addr_.isV6Multicast()) {
2188 if (s->addr_ == pkt->getLocalAddr()) {
2191 return (s->sockfd_);
2195 if (candidate == socket_collection.end()) {
2201 if ((pkt->getRemoteAddr().isV6LinkLocal() &&
2202 s->addr_.isV6LinkLocal()) ||
2203 (!pkt->getRemoteAddr().isV6LinkLocal() &&
2204 !s->addr_.isV6LinkLocal())) {
2210 if (candidate != socket_collection.end()) {
2211 return (candidate->sockfd_);
2215 <<
" does not have any suitable IPv6 sockets open.");
2229 Iface::SocketCollection::const_iterator candidate = socket_collection.end();
2230 Iface::SocketCollection::const_iterator s;
2231 for (s = socket_collection.begin(); s != socket_collection.end(); ++s) {
2232 if (s->family_ == AF_INET) {
2233 if (s->addr_ == pkt->getLocalAddr()) {
2237 if (candidate == socket_collection.end()) {
2243 if (candidate == socket_collection.end()) {
2245 <<
" does not have any suitable IPv4 sockets open.");
2248 return (*candidate);
2255 " while DHCP receiver thread is running");
2258 bool enable_queue =
false;
2259 if (queue_control) {
2270 if (family == AF_INET) {
2271 packet_queue_mgr4_->createPacketQueue(queue_control);
2273 packet_queue_mgr6_->createPacketQueue(queue_control);
2277 if (family == AF_INET) {
2278 packet_queue_mgr4_->destroyPacketQueue();
2280 packet_queue_mgr6_->destroyPacketQueue();
2284 return (enable_queue);
2289 errors_.push_back(message);
2304 if (test_mode_ && update_only) {
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a function is called in a prohibited way.
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
A generic exception that is thrown when an unexpected error condition occurs.
The IOAddress class represents an IP addresses (version agnostic).
std::string toText() const
Convert the address to a string.
uint32_t toUint32() const
Converts IPv4 address to uint32_t.
bool isV6() const
Convenience function to check for an IPv6 address.
bool isV4() const
Convenience function to check for an IPv4 address.
static const IOEndpoint * create(const int protocol, const IOAddress &address, const unsigned short port)
A polymorphic factory of endpoint from address and port.
The UDPEndpoint class is a concrete derived class of IOEndpoint that represents an endpoint of a UDP ...
static ElementPtr create(const Position &pos=ZERO_POSITION())
Create a NullElement.
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
static bool getBoolean(isc::data::ConstElementPtr scope, const std::string &name)
Returns a boolean parameter from a scope.
IfacePtr getIface(const unsigned int ifindex)
Lookup by interface index.
LruIndex & getLru()
LRU index.
IfaceContainer::nth_index< 3 >::type LruIndex
Type of LRU index.
IfaceMgr exception thrown thrown when interface detection fails.
Handles network interfaces, transmission and reception.
void clearIfaces()
Removes detected interfaces.
bool isExternalSocket(int fd)
Checks if socket's file description is registered.
void deleteExternalSocket(int socketfd)
Deletes external socket.
Pkt6Ptr receive6Indirect(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv6 packets indirectly or data from external sockets.
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.
void stopDHCPReceiver(bool clear_queue=true)
Stops the DHCP packet receiver.
std::function< void(int fd)> SocketCallback
Defines callback used when data is received over external sockets.
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.
int openSocketFromAddress(const isc::asiolink::IOAddress &addr, const uint16_t port)
Opens UDP/IP socket and binds to address specified.
void printIfaces(std::ostream &out=std::cout)
Debugging method that prints out all available interfaces.
IfacePtr getIface(const unsigned int ifindex)
Returns interface specified interface index.
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.
bool openSockets6(const uint16_t port=DHCP6_SERVER_PORT, IfaceMgrErrorMsgCallback error_handler=0, const bool skip_opened=false)
Opens IPv6 sockets on detected interfaces.
BoundAddresses bound_address_
Unordered set of IPv4 bound addresses.
void setPacketFilter(const PktFilterPtr &packet_filter)
Set packet filter object to handle sending and receiving DHCPv4 messages.
int openSocketFromIface(const std::string &ifname, const uint16_t port, const uint8_t family)
Opens UDP/IP socket and binds it to interface specified.
Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets or data from external sockets.
void detectIfaces(bool update_only=false)
Detects network interfaces.
IfaceCollection ifaces_
List of available interfaces.
void startDHCPReceiver(const uint16_t family)
Starts DHCP packet receiver.
bool isMainThread() const
Check if called from the main thread.
void clearUnicasts()
Clears unicast addresses on all interfaces.
virtual bool isSocketReceivedTimeSupported() const
Check if the socket received time is supported.
static IfaceMgr & instance()
IfaceMgr is a singleton class.
void initializeFDEventHandler()
Initialize the FD event handler;.
bool isDHCPReceiverRunning() const
Returns true if there is a receiver exists and its thread is currently running.
bool hasOpenSocket(const uint16_t family) const
Checks if there is at least one socket of the specified family open.
virtual ~IfaceMgr()
Destructor.
void collectBoundAddresses()
Collect the addresses all sockets are bound to.
isc::data::ElementPtr ifacesToElement() const
Unparses detected interface list.
int openSocket6(Iface &iface, const isc::asiolink::IOAddress &addr, uint16_t port, const bool join_multicast)
Opens IPv6 socket.
uint16_t getFamily() const
Returns address family.
bool configureDHCPPacketQueue(const uint16_t family, data::ConstElementPtr queue_control)
Configures DHCP packet queue.
int openSocketFromRemoteAddress(const isc::asiolink::IOAddress &remote_addr, const uint16_t port)
Opens UDP/IP socket to be used to connect to remote address.
std::list< int > getAllExternalSockets()
Get the list of external sockets.
Pkt6Ptr receive6Direct(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv6 packets directly or data from external sockets.
bool checkDetectIfaces(bool update_only)
Check if the specific system calls used to detect interfaces should be executed.
bool isDirectResponseSupported() const
Check if packet be sent directly to the client having no address.
void clearBoundAddresses()
Clears the addresses all sockets are bound to.
void addExternalSocket(int socketfd, SocketCallback callback)
Adds external socket and a callback.
void addInterface(const IfacePtr &iface)
Adds an interface to list of known interfaces.
IfaceMgr()
Protected constructor.
bool send(const Pkt6Ptr &pkt)
Sends an IPv6 packet.
Pkt4Ptr receive4Indirect(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets indirectly or data from external sockets.
void closeSockets()
Closes all open sockets.
PacketQueue6Ptr getPacketQueue6()
Fetches the DHCPv6 receiver packet queue.
bool isExternalSocketUnusable(int fd)
Checks if socket's file description is registered.
static const IfaceMgrPtr & instancePtr()
Returns pointer to the sole instance of the interface manager.
void deleteAllExternalSockets()
Deletes all external sockets.
std::thread::id id_
Main thread ID.
Pkt4Ptr receive4Direct(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets directly or data from external sockets.
PacketQueue4Ptr getPacketQueue4()
Fetches the DHCPv4 receiver packet queue.
uint16_t getSocket(const isc::dhcp::Pkt6Ptr &pkt)
Return most suitable socket for transmitting specified IPv6 packet.
Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec=0)
Receive IPv4 packets or data from external sockets.
IfaceMgr exception thrown when there is no suitable interface.
Represents a single network interface.
std::string getPlainMac() const
Returns link-layer address a plain text.
uint64_t flags_
Interface flags (this value is as is returned by OS, it may mean different things on different OSes).
bool inactive4_
Indicates that IPv4 sockets should (true) or should not (false) be opened on this interface.
size_t mac_len_
Length of link-layer address (usually 6).
void clearErrors()
Clears all errors.
virtual isc::data::ElementPtr toElement() const
Unparse a configuration object.
AddressCollection addrs_
List of assigned addresses.
ErrorBuffer const & getErrors() const
Get the consistent list of error messages.
std::vector< std::string > ErrorBuffer
Type definition for a list of error messages.
std::string getFullName() const
Returns full interface name as "ifname/ifindex" string.
unsigned int ifindex_
Interface index (a value that uniquely identifies an interface).
std::string name_
Network interface name.
boost::multi_index_container< SocketInfo, boost::multi_index::indexed_by< boost::multi_index::sequenced<>, boost::multi_index::sequenced<> > > SocketCollection
Type that holds a list of socket information.
uint16_t hardware_type_
Hardware type.
SocketCollection sockets_
Socket used to send data.
const AddressCollection & getAddresses() const
Returns all addresses available on an interface.
bool flag_multicast_
Flag specifies if selected interface is multicast capable.
void setActive(const isc::asiolink::IOAddress &address, const bool active)
Activates or deactivates address for the interface.
void addError(std::string const &message)
Add an error to the list of messages.
std::string getName() const
Returns interface name.
Iface(const std::string &name, unsigned int ifindex)
Iface constructor.
bool delAddress(const isc::asiolink::IOAddress &addr)
Deletes an address from an interface.
bool hasAddress(const isc::asiolink::IOAddress &address) const
Check if the interface has the specified address assigned.
SocketCollection::nth_index< 1 >::type SocketLruIndex
SocketInfo LRU index type.
void setMac(const uint8_t *mac, size_t macLen)
Sets MAC address of the interface.
bool flag_running_
Flag specifies if selected interface is running (e.g.
bool delSocket(uint16_t sockfd)
Closes socket.
std::list< Address > AddressCollection
Type that defines list of addresses.
bool inactive6_
Indicates that IPv6 sockets should (true) or should not (false) be opened on this interface.
static const unsigned int MAX_MAC_LEN
Maximum MAC address length (Infiniband uses 20 bytes).
bool flag_loopback_
Specifies if selected interface is loopback.
void addUnicast(const isc::asiolink::IOAddress &addr)
Adds unicast the server should listen on.
unsigned int countActive4() const
Returns a number of activated IPv4 addresses on the interface.
uint8_t mac_[MAX_MAC_LEN]
Link-layer address.
util::Optional< asiolink::IOAddress > Address
Address type.
void addAddress(const isc::asiolink::IOAddress &addr)
Adds an address to an interface.
void closeSockets()
Closes all open sockets on interface.
void addSocket(const SocketInfo &sock)
Adds socket descriptor to an interface.
bool flag_up_
Specifies if selected interface is up.
bool flag_broadcast_
Flag specifies if selected interface is broadcast capable.
AddressCollection unicasts_
List of unicast addresses the server should listen on.
bool getAddress4(isc::asiolink::IOAddress &address) const
Returns IPv4 address assigned to the interface.
Exception thrown when invalid packet filter object specified.
Exception thrown when it is not allowed to set new Packet Filter.
Packet Queue Manager for DHCPv4 servers.
Packet Queue Manager for DHCPv6 servers.
A DHCPv6 packet handling class using datagram sockets.
Packet handling class using AF_INET socket family.
Exception thrown when a call to select is interrupted by a signal.
IfaceMgr exception thrown thrown when socket opening or configuration failed.
IfaceMgr exception thrown when there is an error detected for the respective socket file descriptor.
IfaceMgr exception thrown when there is no suitable socket found.
IfaceMgr exception thrown thrown when error occurred during reading data from socket.
static FDEventHandlerPtr factoryFDEventHandler()
Return an FDEventhandler.
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
A template representing an optional value.
Provides a thread and controls for monitoring its activities.
#define DHCP_IPV4_BROADCAST_ADDRESS
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define IFACEMGR_ERROR(ex_type, handler, iface, stream)
A macro which handles an error in IfaceMgr.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
boost::shared_ptr< const Element > ConstElementPtr
boost::shared_ptr< Element > ElementPtr
const isc::log::MessageID DHCP_RECEIVE4_UNKNOWN
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
const isc::log::MessageID DHCP_RECEIVE6_UNKNOWN
boost::shared_ptr< IfaceMgr > IfaceMgrPtr
Type definition for the pointer to the IfaceMgr.
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
boost::shared_ptr< PktFilter > PktFilterPtr
Pointer to a PktFilter object.
boost::shared_ptr< Iface > IfacePtr
Type definition for the pointer to an Iface object.
const isc::log::MessageID DHCP_DELETE_EXTERNAL_SOCKET_NOT_FOUND
std::function< void(const std::string &errmsg)> IfaceMgrErrorMsgCallback
This type describes the callback function invoked when error occurs in the IfaceMgr.
const isc::log::MessageID DHCP_ADD_EXTERNAL_SOCKET_ALREADY_EXISTS
const isc::log::MessageID DHCP_ADD_EXTERNAL_SOCKET_BAD_THREAD
const isc::log::MessageID DHCP_IFACE_OPEN_SOCKET
constexpr unsigned int UNSET_IFINDEX
A value used to signal that the interface index was not set.
const isc::log::MessageID DHCP_DELETE_EXTERNAL_SOCKET_BAD_THREAD
const isc::log::MessageID DHCP_DELETE_ALL_EXTERNAL_SOCKETS_BAD_THREAD
isc::log::Logger dhcp_logger("dhcp")
DHCP library Logger.
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
boost::shared_ptr< PktFilter6 > PktFilter6Ptr
Pointer to a PktFilter object.
const isc::log::MessageID DHCP_IFACE_SOCKET_ERROR
const int DBGLVL_TRACE_BASIC
Trace basic operations.
Defines the logger used by the top-level component of kea-lfc.
Keeps callback information for external sockets.
SocketCallback callback_
A callback that will be called when data arrives over socket_.
Holds information about socket.