iface_mgr_bsd.cc 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. // Copyright (C) 2011, 2013-2014 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #if defined(OS_BSD)
  16. #include <dhcp/iface_mgr.h>
  17. #include <dhcp/iface_mgr_error_handler.h>
  18. #include <dhcp/pkt_filter_bpf.h>
  19. #include <dhcp/pkt_filter_inet.h>
  20. #include <exceptions/exceptions.h>
  21. #include <sys/types.h>
  22. #include <sys/socket.h>
  23. #include <net/if_dl.h>
  24. #include <net/if.h>
  25. #include <ifaddrs.h>
  26. using namespace std;
  27. using namespace isc;
  28. using namespace isc::asiolink;
  29. using namespace isc::dhcp;
  30. namespace isc {
  31. namespace dhcp {
  32. /// This is a BSD specific interface detection method.
  33. void
  34. IfaceMgr::detectIfaces() {
  35. struct ifaddrs* iflist = 0;// The whole interface list
  36. struct ifaddrs* ifptr = 0; // The interface we're processing now
  37. // Gets list of ifaddrs struct
  38. if(getifaddrs(&iflist) != 0) {
  39. isc_throw(Unexpected, "Network interfaces detection failed.");
  40. }
  41. typedef map<string, IfacePtr> IfaceLst;
  42. IfaceLst::iterator iface_iter;
  43. IfaceLst ifaces;
  44. // First lookup for getting interfaces ...
  45. for (ifptr = iflist; ifptr != 0; ifptr = ifptr->ifa_next) {
  46. const char * ifname = ifptr->ifa_name;
  47. uint ifindex = 0;
  48. if (!(ifindex = if_nametoindex(ifname))) {
  49. // Interface name does not have corresponding index ...
  50. freeifaddrs(iflist);
  51. isc_throw(Unexpected, "Interface " << ifname << " has no index");
  52. }
  53. if ((iface_iter = ifaces.find(ifname)) != ifaces.end()) {
  54. continue;
  55. }
  56. IfacePtr iface(new Iface(ifname, ifindex));
  57. iface->setFlags(ifptr->ifa_flags);
  58. ifaces.insert(pair<string, IfacePtr>(ifname, iface));
  59. }
  60. // Second lookup to get MAC and IP addresses
  61. for (ifptr = iflist; ifptr != 0; ifptr = ifptr->ifa_next) {
  62. if ((iface_iter = ifaces.find(ifptr->ifa_name)) == ifaces.end()) {
  63. continue;
  64. }
  65. // Common byte pointer for following data
  66. const uint8_t * ptr = 0;
  67. if(ifptr->ifa_addr->sa_family == AF_LINK) {
  68. // HWAddr
  69. struct sockaddr_dl * ldata =
  70. reinterpret_cast<struct sockaddr_dl *>(ifptr->ifa_addr);
  71. ptr = reinterpret_cast<uint8_t *>(LLADDR(ldata));
  72. iface_iter->second->setHWType(ldata->sdl_type);
  73. iface_iter->second->setMac(ptr, ldata->sdl_alen);
  74. } else if(ifptr->ifa_addr->sa_family == AF_INET6) {
  75. // IPv6 Addr
  76. struct sockaddr_in6 * adata =
  77. reinterpret_cast<struct sockaddr_in6 *>(ifptr->ifa_addr);
  78. ptr = reinterpret_cast<uint8_t *>(&adata->sin6_addr);
  79. IOAddress a = IOAddress::fromBytes(AF_INET6, ptr);
  80. iface_iter->second->addAddress(a);
  81. } else {
  82. // IPv4 Addr
  83. struct sockaddr_in * adata =
  84. reinterpret_cast<struct sockaddr_in *>(ifptr->ifa_addr);
  85. ptr = reinterpret_cast<uint8_t *>(&adata->sin_addr);
  86. IOAddress a = IOAddress::fromBytes(AF_INET, ptr);
  87. iface_iter->second->addAddress(a);
  88. }
  89. }
  90. freeifaddrs(iflist);
  91. // Interfaces registering
  92. for(IfaceLst::const_iterator iface_iter = ifaces.begin();
  93. iface_iter != ifaces.end(); ++iface_iter) {
  94. addInterface(iface_iter->second);
  95. }
  96. }
  97. /// @brief sets flag_*_ fields
  98. ///
  99. /// Like Linux version, os specific flags
  100. ///
  101. /// @params flags
  102. void Iface::setFlags(uint64_t flags) {
  103. flags_ = flags;
  104. flag_loopback_ = flags & IFF_LOOPBACK;
  105. flag_up_ = flags & IFF_UP;
  106. flag_running_ = flags & IFF_RUNNING;
  107. flag_multicast_ = flags & IFF_MULTICAST;
  108. flag_broadcast_ = flags & IFF_BROADCAST;
  109. }
  110. void IfaceMgr::os_send4(struct msghdr& /*m*/,
  111. boost::scoped_array<char>& /*control_buf*/,
  112. size_t /*control_buf_len*/,
  113. const Pkt4Ptr& /*pkt*/) {
  114. // @todo: Are there any specific actions required before sending IPv4 packet
  115. // on BSDs? See iface_mgr_linux.cc for working Linux implementation.
  116. }
  117. bool IfaceMgr::os_receive4(struct msghdr& /*m*/, Pkt4Ptr& /*pkt*/) {
  118. // @todo: Are there any specific actions required before receiving IPv4 packet
  119. // on BSDs? See iface_mgr_linux.cc for working Linux implementation.
  120. return (true); // pretend that we have everything set up for reception.
  121. }
  122. void
  123. IfaceMgr::setMatchingPacketFilter(const bool direct_response_desired) {
  124. // If direct response is desired we have to use BPF. If the direct
  125. // response is not desired we use datagram socket supported by the
  126. // PktFilterInet class. Note however that on BSD systems binding the
  127. // datagram socket to the device is not supported and the server would
  128. // have no means to determine on which interface the packet has been
  129. // received. Hence, it is discouraged to use PktFilterInet for the
  130. // server.
  131. if (direct_response_desired) {
  132. setPacketFilter(PktFilterPtr(new PktFilterBPF()));
  133. } else {
  134. setPacketFilter(PktFilterPtr(new PktFilterInet()));
  135. }
  136. }
  137. bool
  138. IfaceMgr::openMulticastSocket(Iface& iface,
  139. const isc::asiolink::IOAddress& addr,
  140. const uint16_t port,
  141. IfaceMgrErrorMsgCallback error_handler) {
  142. try {
  143. // This should open a socket, bind it to link-local address
  144. // and join multicast group.
  145. openSocket(iface.getName(), addr, port, iface.flag_multicast_);
  146. } catch (const Exception& ex) {
  147. IFACEMGR_ERROR(SocketConfigError, error_handler,
  148. "Failed to open link-local socket on "
  149. " interface " << iface.getName() << ": "
  150. << ex.what());
  151. return (false);
  152. }
  153. return (true);
  154. }
  155. int
  156. IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port,
  157. const bool join_multicast) {
  158. // On BSD, we bind the socket to in6addr_any and join multicast group
  159. // to receive multicast traffic. So, if the multicast is requested,
  160. // replace the address specified by the caller with the "unspecified"
  161. // address.
  162. IOAddress actual_address = join_multicast ? IOAddress("::") : addr;
  163. SocketInfo info = packet_filter6_->openSocket(iface, actual_address, port,
  164. join_multicast);
  165. iface.addSocket(info);
  166. return (info.sockfd_);
  167. }
  168. } // end of isc::dhcp namespace
  169. } // end of dhcp namespace
  170. #endif