20 #include <boost/foreach.hpp>
21 #include <boost/scoped_ptr.hpp>
22 #include <boost/bind.hpp>
29 #include <arpa/inet.h>
30 #include <netinet/in.h>
32 #include <sys/ioctl.h>
33 #include <sys/select.h>
36 #define FD_COPY(orig, copy) \
38 memmove(copy, orig, sizeof(fd_set)); \
53 IfaceMgr::instance() {
54 return (*instancePtr());
58 IfaceMgr::instancePtr() {
63 Iface::Iface(
const std::string& name,
int ifindex)
64 :
name_(name), ifindex_(ifindex), mac_len_(0), hardware_type_(0),
65 flag_loopback_(false), flag_up_(false), flag_running_(false),
66 flag_multicast_(false), flag_broadcast_(false), flags_(0),
67 inactive4_(false), inactive6_(false)
91 if ((family != AF_INET) && (family != AF_INET6)) {
93 <<
" specified when requested to close all sockets"
94 <<
" which belong to this family");
98 SocketCollection::iterator sock =
sockets_.begin();
100 if (sock->family_ == family) {
103 close(sock->sockfd_);
105 if (sock->fallbackfd_ >= 0) {
106 close(sock->fallbackfd_);
131 for (
int 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();
157 if (a->get() == addr) {
166 list<SocketInfo>::iterator sock =
sockets_.begin();
168 if (sock->sockfd_ == sockfd) {
171 if (sock->fallbackfd_ >= 0) {
172 close(sock->fallbackfd_);
186 allow_loopback_(false) {
193 }
catch (
const std::exception& ex) {
204 }
catch (
const std::exception& ex) {
211 if (a.
get() == addr) {
213 <<
" already defined on the " <<
name_ <<
" interface.");
226 if (addr.
get().isV4()) {
227 address = addr.
get();
238 if (address == addr.
get()) {
252 for (AddressCollection::iterator addr_it =
addrs_.begin();
253 addr_it !=
addrs_.end(); ++addr_it) {
254 if (address == addr_it->get()) {
260 " found on the interface " <<
getName());
265 for (AddressCollection::iterator addr_it =
addrs_.begin();
266 addr_it !=
addrs_.end(); ++addr_it) {
287 iface->closeSockets();
293 dhcp_receiver_->stop();
296 dhcp_receiver_.reset();
313 return (packet_filter_->isDirectResponseSupported());
335 callbacks_.push_back(x);
340 for (SocketCallbackInfoContainer::iterator s = callbacks_.begin();
341 s != callbacks_.end(); ++s) {
342 if (s->socket_ == socketfd) {
357 if (!packet_filter) {
370 "it is not allowed to set new packet"
371 <<
" filter when there are open IPv4 sockets - need"
372 <<
" to close them first");
375 packet_filter_ = packet_filter;
380 if (!packet_filter) {
388 "it is not allowed to set new packet"
389 <<
" filter when there are open IPv6 sockets - need"
390 <<
" to close them first");
393 packet_filter6_ = packet_filter;
400 BOOST_FOREACH(
SocketInfo sock, iface->getSockets()) {
416 BOOST_FOREACH(
SocketInfo sock, iface->getSockets()) {
419 if (sock.
addr_ == addr) {
427 if (addr == a.
get()) {
440 const string v4addr(
"127.0.0.1"), v6addr(
"::1");
446 if (if_nametoindex(
"lo") > 0) {
449 }
else if (if_nametoindex(
"lo0") > 0) {
455 "Interface detection on this OS is not supported.");
458 IfacePtr iface(
new Iface(ifaceName, if_nametoindex(ifaceName.c_str())));
459 iface->flag_up_ =
true;
460 iface->flag_running_ =
true;
466 iface->flag_loopback_ =
false;
467 iface->flag_multicast_ =
true;
468 iface->flag_broadcast_ =
true;
469 iface->setHWType(HWTYPE_ETHERNET);
485 if (iface->inactive4_) {
496 if (iface->flag_loopback_ && !allow_loopback_) {
498 "must not open socket on the loopback"
499 " interface " << iface->getName());
504 if (!iface->flag_up_) {
506 "the interface " << iface->getName()
511 if (!iface->flag_running_) {
513 "the interface " << iface->getName()
514 <<
" is not running");
519 if (!iface->getAddress4(out_address)) {
521 "the interface " << iface->getName()
522 <<
" has no usable IPv4 addresses configured");
536 if (iface->flag_broadcast_ && use_bcast) {
552 "Binding socket to an interface is not"
553 " supported on this OS; therefore only"
554 " one socket listening to broadcast traffic"
555 " can be opened. Sockets will not be opened"
556 " on remaining interfaces");
566 "failed to open socket on interface "
567 << iface->getName() <<
", reason: "
581 openSocket(iface->getName(), addr.
get(), port,
false,
false);
584 "failed to open socket on interface "
585 << iface->getName() <<
", reason: "
611 if (iface->inactive6_) {
622 if (iface->flag_loopback_ && !allow_loopback_) {
624 "must not open socket on the loopback"
625 " interface " << iface->getName());
628 }
else if (!iface->flag_up_) {
630 "the interface " << iface->getName()
633 }
else if (!iface->flag_running_) {
635 "the interface " << iface->getName()
636 <<
" is not running");
649 "Failed to open unicast socket on interface "
650 << iface->getName() <<
", reason: "
662 if (!addr.
get().isV6()) {
671 if (!addr.
get().isV6LinkLocal()){
678 if (openMulticastSocket(*iface, addr, port, error_handler)) {
708 dhcp_receiver_->start(boost::bind(&IfaceMgr::receiveDHCP4Packets,
this));
719 dhcp_receiver_->start(boost::bind(&IfaceMgr::receiveDHCP6Packets,
this));
732 out <<
"Detected interface " << iface->getFullName()
733 <<
", hwtype=" << iface->getHWType()
734 <<
", mac=" << iface->getPlainMac();
735 out <<
", flags=" << hex << iface->flags_ << dec <<
"("
736 << (iface->flag_loopback_?
"LOOPBACK ":
"")
737 << (iface->flag_up_?
"UP ":
"")
738 << (iface->flag_running_?
"RUNNING ":
"")
739 << (iface->flag_multicast_?
"MULTICAST ":
"")
740 << (iface->flag_broadcast_?
"BROADCAST ":
"")
742 out <<
" " << addrs.size() <<
" addr(s):";
745 out <<
" " << addr.
get().toText();
754 if (iface->getIndex() == ifindex)
764 if (iface->getName() == ifname)
779 iface->clearUnicasts();
784 const uint16_t port,
const bool receive_bcast,
785 const bool send_bcast) {
791 return openSocket4(*iface, addr, port, receive_bcast, send_bcast);
793 }
else if (addr.
isV6()) {
794 return openSocket6(*iface, addr, port, receive_bcast);
804 const uint8_t family) {
807 if ((iface->getFullName() != ifname) &&
808 (iface->getName() != ifname)) {
815 Iface::AddressCollection::iterator addr_it = addrs.begin();
816 while (addr_it != addrs.end()) {
817 if (addr_it->get().getFamily() == family) {
820 return (
openSocket(iface->getName(), *addr_it, port,
false));
826 if (addr_it == addrs.end()) {
828 std::string family_name(
"AF_INET");
829 if (family == AF_INET6) {
830 family_name =
"AF_INET6";
834 << ifname <<
", port: " << port <<
", address "
835 " family: " << family_name);
844 const uint16_t port) {
854 if (a.
get() == addr) {
857 return (
openSocket(iface->getName(), a, port,
false));
867 const uint16_t port) {
870 IOAddress local_address(getLocalAddress(remote_addr, port));
878 IfaceMgr::getLocalAddress(
const IOAddress& remote_addr,
const uint16_t port) {
880 boost::scoped_ptr<const UDPEndpoint>
883 if (!remote_endpoint) {
888 boost::asio::io_service io_service;
889 boost::asio::ip::udp::socket sock(io_service);
891 boost::system::error_code err_code;
894 if (remote_addr.
isV4() &&
907 sock.open(boost::asio::ip::udp::v4(), err_code);
909 const char* errstr = strerror(errno);
913 sock.set_option(boost::asio::socket_base::broadcast(
true), err_code);
916 isc_throw(Unexpected,
"failed to enable broadcast on the socket");
921 sock.connect(remote_endpoint->getASIOEndpoint(), err_code);
924 isc_throw(Unexpected,
"failed to connect to remote endpoint.");
928 boost::asio::ip::udp::socket::endpoint_type local_endpoint =
929 sock.local_endpoint();
930 boost::asio::ip::address local_address(local_endpoint.address());
941 const uint16_t port,
const bool receive_bcast,
942 const bool send_bcast) {
945 SocketInfo info = packet_filter_->openSocket(iface, addr, port,
946 receive_bcast, send_bcast);
957 << pkt->getIface() <<
") specified.");
961 return (packet_filter6_->send(*iface,
getSocket(*pkt), pkt));
970 << pkt->getIface() <<
") specified.");
974 return (packet_filter_->send(*iface,
getSocket(*pkt).sockfd_, pkt));
987 if (timeout_usec >= 1000000) {
989 " one million microseconds");
998 if (!callbacks_.empty()) {
1005 addFDtoSet(dhcp_receiver_->getWatchFd(WatchedThread::READY), maxfd, &sockets);
1016 struct timeval select_timeout;
1018 select_timeout.tv_sec = timeout_sec;
1019 select_timeout.tv_usec = timeout_usec;
1021 select_timeout.tv_sec = 0;
1022 select_timeout.tv_usec = 0;
1028 int result = select(maxfd + 1, &sockets, NULL, NULL, &select_timeout);
1033 }
else if (result < 0) {
1041 if (errno == EINTR) {
1052 string msg = dhcp_receiver_->getLastError();
1059 if (!FD_ISSET(s.
socket_, &sockets)) {
1079 dhcp_receiver_->clearReady(WatchedThread::READY);
1087 if (timeout_usec >= 1000000) {
1089 " one million microseconds");
1091 boost::scoped_ptr<SocketInfo> candidate;
1101 BOOST_FOREACH(iface,
ifaces_) {
1102 BOOST_FOREACH(
SocketInfo s, iface->getSockets()) {
1112 if (!callbacks_.empty()) {
1119 struct timeval select_timeout;
1120 select_timeout.tv_sec = timeout_sec;
1121 select_timeout.tv_usec = timeout_usec;
1126 int result = select(maxfd + 1, &sockets, NULL, NULL, &select_timeout);
1132 }
else if (result < 0) {
1140 if (errno == EINTR) {
1149 if (!FD_ISSET(s.
socket_, &sockets)) {
1166 BOOST_FOREACH(iface,
ifaces_) {
1167 BOOST_FOREACH(
SocketInfo s, iface->getSockets()) {
1168 if (FD_ISSET(s.
sockfd_, &sockets)) {
1184 return (packet_filter_->receive(*iface, *candidate));
1202 FD_SET(fd, sockets);
1211 if (timeout_usec >= 1000000) {
1213 " one million microseconds");
1216 boost::scoped_ptr<SocketInfo> candidate;
1226 BOOST_FOREACH(
SocketInfo s, iface->getSockets()) {
1236 if (!callbacks_.empty()) {
1243 struct timeval select_timeout;
1244 select_timeout.tv_sec = timeout_sec;
1245 select_timeout.tv_usec = timeout_usec;
1250 int result = select(maxfd + 1, &sockets, NULL, NULL, &select_timeout);
1256 }
else if (result < 0) {
1264 if (errno == EINTR) {
1273 if (!FD_ISSET(s.
socket_, &sockets)) {
1291 BOOST_FOREACH(
SocketInfo s, iface->getSockets()) {
1292 if (FD_ISSET(s.
sockfd_, &sockets)) {
1306 return (packet_filter6_->receive(*candidate));
1312 if (timeout_usec >= 1000000) {
1314 " one million microseconds");
1323 if (!callbacks_.empty()) {
1331 addFDtoSet(dhcp_receiver_->getWatchFd(WatchedThread::READY), maxfd, &sockets);
1342 struct timeval select_timeout;
1344 select_timeout.tv_sec = timeout_sec;
1345 select_timeout.tv_usec = timeout_usec;
1347 select_timeout.tv_sec = 0;
1348 select_timeout.tv_usec = 0;
1354 int result = select(maxfd + 1, &sockets, NULL, NULL, &select_timeout);
1359 }
else if (result < 0) {
1367 if (errno == EINTR) {
1378 string msg = dhcp_receiver_->getLastError();
1385 if (!FD_ISSET(s.
socket_, &sockets)) {
1405 dhcp_receiver_->clearReady(WatchedThread::READY);
1412 IfaceMgr::receiveDHCP4Packets() {
1420 addFDtoSet(dhcp_receiver_->getWatchFd(WatchedThread::TERMINATE), maxfd, &sockets);
1423 BOOST_FOREACH(iface,
ifaces_) {
1424 BOOST_FOREACH(
SocketInfo s, iface->getSockets()) {
1435 if (dhcp_receiver_->shouldTerminate()) {
1446 int result = select(maxfd + 1, &rd_set, 0, 0, 0);
1449 if (dhcp_receiver_->shouldTerminate()) {
1457 }
else if (result < 0) {
1459 if (errno != EINTR) {
1461 dhcp_receiver_->setError(strerror(errno));
1471 BOOST_FOREACH(iface,
ifaces_) {
1472 BOOST_FOREACH(SocketInfo s, iface->getSockets()) {
1473 if (FD_ISSET(s.sockfd_, &sockets)) {
1474 receiveDHCP4Packet(*iface, s);
1476 if (dhcp_receiver_->shouldTerminate()) {
1487 IfaceMgr::receiveDHCP6Packets() {
1495 addFDtoSet(dhcp_receiver_->getWatchFd(WatchedThread::TERMINATE), maxfd, &sockets);
1498 BOOST_FOREACH(iface,
ifaces_) {
1499 BOOST_FOREACH(SocketInfo s, iface->getSockets()) {
1501 if (s.addr_.isV6()) {
1510 if (dhcp_receiver_->shouldTerminate()) {
1521 int result = select(maxfd + 1, &rd_set, 0, 0, 0);
1524 if (dhcp_receiver_->shouldTerminate()) {
1531 }
else if (result < 0) {
1533 if (errno != EINTR) {
1535 dhcp_receiver_->setError(strerror(errno));
1545 BOOST_FOREACH(iface,
ifaces_) {
1546 BOOST_FOREACH(SocketInfo s, iface->getSockets()) {
1547 if (FD_ISSET(s.sockfd_, &sockets)) {
1548 receiveDHCP6Packet(s);
1550 if (dhcp_receiver_->shouldTerminate()) {
1560 IfaceMgr::receiveDHCP4Packet(Iface& iface,
const SocketInfo& socket_info) {
1563 int result = ioctl(socket_info.sockfd_, FIONREAD, &len);
1566 dhcp_receiver_->setError(strerror(errno));
1577 pkt = packet_filter_->receive(iface, socket_info);
1578 }
catch (
const std::exception& ex) {
1579 dhcp_receiver_->setError(strerror(errno));
1581 dhcp_receiver_->setError(
"packet filter receive() failed");
1586 dhcp_receiver_->markReady(WatchedThread::READY);
1591 IfaceMgr::receiveDHCP6Packet(
const SocketInfo& socket_info) {
1594 int result = ioctl(socket_info.sockfd_, FIONREAD, &len);
1597 dhcp_receiver_->setError(strerror(errno));
1608 pkt = packet_filter6_->receive(socket_info);
1609 }
catch (
const std::exception& ex) {
1610 dhcp_receiver_->setError(ex.what());
1612 dhcp_receiver_->setError(
"packet filter receive() failed");
1617 dhcp_receiver_->markReady(WatchedThread::READY);
1631 Iface::SocketCollection::const_iterator candidate = socket_collection.end();
1633 Iface::SocketCollection::const_iterator s;
1634 for (s = socket_collection.begin(); s != socket_collection.end(); ++s) {
1639 if (s->family_ != AF_INET6) {
1644 if (s->addr_.isV6Multicast()) {
1651 return (s->sockfd_);
1655 if (candidate == socket_collection.end()) {
1662 s->addr_.isV6LinkLocal()) ||
1664 !s->addr_.isV6LinkLocal()) ) {
1670 if (candidate != socket_collection.end()) {
1671 return (candidate->sockfd_);
1675 <<
" does not have any suitable IPv6 sockets open.");
1681 if (iface == NULL) {
1689 Iface::SocketCollection::const_iterator candidate = socket_collection.end();
1690 Iface::SocketCollection::const_iterator s;
1691 for (s = socket_collection.begin(); s != socket_collection.end(); ++s) {
1692 if (s->family_ == AF_INET) {
1697 if (candidate == socket_collection.end()) {
1703 if (candidate == socket_collection.end()) {
1705 <<
" does not have any suitable IPv4 sockets open.");
1708 return (*candidate);
1715 " while DHCP receiver thread is running");
1718 bool enable_queue =
false;
1719 if (queue_control) {
1730 if (family == AF_INET) {
1731 packet_queue_mgr4_->createPacketQueue(queue_control);
1733 packet_queue_mgr6_->createPacketQueue(queue_control);
1737 if (family == AF_INET) {
1738 packet_queue_mgr4_->destroyPacketQueue();
1740 packet_queue_mgr6_->destroyPacketQueue();
1744 return(enable_queue);