iface_mgr_linux.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. // Copyright (C) 2011-2012 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. /// @file
  15. /// Access to interface information on Linux is via netlink, a socket-based
  16. /// method for transferring information between the kernel and user processes.
  17. ///
  18. /// For detailed information about netlink interface, please refer to
  19. /// http://en.wikipedia.org/wiki/Netlink and RFC3549. Comments in the
  20. /// detectIfaces() method (towards the end of this file) provide an overview
  21. /// on how the netlink interface is used here.
  22. ///
  23. /// Note that this interface is very robust and allows many operations:
  24. /// add/get/set/delete links, addresses, routes, queuing, manipulation of
  25. /// traffic classes, manipulation of neighbourhood tables and even the ability
  26. /// to do something with address labels. Getting a list of interfaces with
  27. /// addresses configured on it is just a small subset of all possible actions.
  28. #include <config.h>
  29. #if defined(OS_LINUX)
  30. #include <dhcp/iface_mgr.h>
  31. #include <exceptions/exceptions.h>
  32. #include <stdint.h>
  33. #include <net/if.h>
  34. #include <linux/rtnetlink.h>
  35. #include <boost/array.hpp>
  36. #include <boost/static_assert.hpp>
  37. #include <dhcp/iface_mgr.h>
  38. #include <exceptions/exceptions.h>
  39. #include <asiolink/io_address.h>
  40. #include <util/io/sockaddr_util.h>
  41. using namespace std;
  42. using namespace isc;
  43. using namespace isc::asiolink;
  44. using namespace isc::dhcp;
  45. using namespace isc::util::io::internal;
  46. BOOST_STATIC_ASSERT(IFLA_MAX>=IFA_MAX);
  47. namespace {
  48. /// @brief This class offers utility methods for netlink connection.
  49. ///
  50. /// See IfaceMgr::detectIfaces() (Linux implementation, towards the end of this
  51. /// file) for example usage.
  52. class Netlink
  53. {
  54. public:
  55. /// @brief Holds pointers to netlink messages.
  56. ///
  57. /// netlink (a Linux interface for getting information about network
  58. /// interfaces) uses memory aliasing. Linux kernel returns a memory
  59. /// blob that should be interpreted as series of nlmessages. There
  60. /// are different nlmsg structures defined with varying size. They
  61. /// have one thing common - inital fields are laid out in the same
  62. /// way as nlmsghdr. Therefore different messages can be represented
  63. /// as nlmsghdr with followed variable number of bytes that are
  64. /// message-specific. The only reasonable way to represent this in
  65. /// C++ is to use vector of pointers to nlmsghdr (the common structure).
  66. typedef vector<nlmsghdr*> NetlinkMessages;
  67. /// @brief Holds pointers to interface or address attributes.
  68. ///
  69. /// Note that to get address info, a shorter (IFA_MAX rather than IFLA_MAX)
  70. /// table could be used, but we will use the bigger one anyway to
  71. /// make the code reusable.
  72. ///
  73. /// rtattr is a generic structure, similar to sockaddr. It is defined
  74. /// in linux/rtnetlink.h and shown here for documentation purposes only:
  75. ///
  76. /// struct rtattr {
  77. /// unsigned short<>rta_len;
  78. /// unsigned short<>rta_type;
  79. /// };
  80. typedef boost::array<struct rtattr*, IFLA_MAX + 1> RTattribPtrs;
  81. Netlink() : fd_(-1), seq_(0), dump_(0) {
  82. memset(&local_, 0, sizeof(struct sockaddr_nl));
  83. memset(&peer_, 0, sizeof(struct sockaddr_nl));
  84. }
  85. ~Netlink() {
  86. rtnl_close_socket();
  87. }
  88. void rtnl_open_socket();
  89. void rtnl_send_request(int family, int type);
  90. void rtnl_store_reply(NetlinkMessages& storage, const nlmsghdr* msg);
  91. void parse_rtattr(RTattribPtrs& table, rtattr* rta, int len);
  92. void ipaddrs_get(IfaceMgr::Iface& iface, NetlinkMessages& addr_info);
  93. void rtnl_process_reply(NetlinkMessages& info);
  94. void release_list(NetlinkMessages& messages);
  95. void rtnl_close_socket();
  96. private:
  97. int fd_; // Netlink file descriptor
  98. sockaddr_nl local_; // Local addresses
  99. sockaddr_nl peer_; // Remote address
  100. uint32_t seq_; // Counter used for generating unique sequence numbers
  101. uint32_t dump_; // Number of expected message response
  102. };
  103. /// @brief defines a size of a sent netlink buffer
  104. const static size_t SNDBUF_SIZE = 32768;
  105. /// @brief defines a size of a received netlink buffer
  106. const static size_t RCVBUF_SIZE = 32768;
  107. /// @brief Opens netlink socket and initializes handle structure.
  108. ///
  109. /// @exception Unexpected Thrown if socket configuration fails.
  110. void Netlink::rtnl_open_socket() {
  111. fd_ = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  112. if (fd_ < 0) {
  113. isc_throw(Unexpected, "Failed to create NETLINK socket.");
  114. }
  115. if (setsockopt(fd_, SOL_SOCKET, SO_SNDBUF, &SNDBUF_SIZE, sizeof(SNDBUF_SIZE)) < 0) {
  116. isc_throw(Unexpected, "Failed to set send buffer in NETLINK socket.");
  117. }
  118. if (setsockopt(fd_, SOL_SOCKET, SO_RCVBUF, &RCVBUF_SIZE, sizeof(RCVBUF_SIZE)) < 0) {
  119. isc_throw(Unexpected, "Failed to set receive buffer in NETLINK socket.");
  120. }
  121. local_.nl_family = AF_NETLINK;
  122. local_.nl_groups = 0;
  123. if (bind(fd_, convertSockAddr(&local_), sizeof(local_)) < 0) {
  124. isc_throw(Unexpected, "Failed to bind netlink socket.");
  125. }
  126. socklen_t addr_len = sizeof(local_);
  127. if (getsockname(fd_, convertSockAddr(&local_), &addr_len) < 0) {
  128. isc_throw(Unexpected, "Getsockname for netlink socket failed.");
  129. }
  130. // just 2 sanity checks and we are done
  131. if ( (addr_len != sizeof(local_)) ||
  132. (local_.nl_family != AF_NETLINK) ) {
  133. isc_throw(Unexpected, "getsockname() returned unexpected data for netlink socket.");
  134. }
  135. }
  136. /// @brief Closes netlink communication socket
  137. void Netlink::rtnl_close_socket() {
  138. if (fd_ != -1) {
  139. close(fd_);
  140. }
  141. fd_ = -1;
  142. }
  143. /// @brief Sends request over NETLINK socket.
  144. ///
  145. /// @param family requested information family.
  146. /// @param type request type (RTM_GETLINK or RTM_GETADDR).
  147. void Netlink::rtnl_send_request(int family, int type) {
  148. struct Req {
  149. nlmsghdr netlink_header;
  150. rtgenmsg generic;
  151. };
  152. Req req; // we need this type named for offsetof() used in assert
  153. struct sockaddr_nl nladdr;
  154. // do a sanity check. Verify that Req structure is aligned properly
  155. BOOST_STATIC_ASSERT(sizeof(nlmsghdr) == offsetof(Req, generic));
  156. memset(&nladdr, 0, sizeof(nladdr));
  157. nladdr.nl_family = AF_NETLINK;
  158. // According to netlink(7) manpage, mlmsg_seq must be set to a sequence
  159. // number and is used to track messages. That is just a value that is
  160. // opaque to kernel, and user-space code is supposed to use it to match
  161. // incoming responses to sent requests. That is not really useful as we
  162. // send a single request and get a single response at a time. However, we
  163. // obey the man page suggestion and just set this to monotonically
  164. // increasing numbers.
  165. seq_++;
  166. // This will be used to finding correct response (responses
  167. // sent by kernel are supposed to have the same sequence number
  168. // as the request we sent).
  169. dump_ = seq_;
  170. memset(&req, 0, sizeof(req));
  171. req.netlink_header.nlmsg_len = sizeof(req);
  172. req.netlink_header.nlmsg_type = type;
  173. req.netlink_header.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
  174. req.netlink_header.nlmsg_pid = 0;
  175. req.netlink_header.nlmsg_seq = seq_;
  176. req.generic.rtgen_family = family;
  177. int status = sendto(fd_, static_cast<void*>(&req), sizeof(req), 0,
  178. static_cast<struct sockaddr*>(static_cast<void*>(&nladdr)),
  179. sizeof(nladdr));
  180. if (status<0) {
  181. isc_throw(Unexpected, "Failed to send " << sizeof(nladdr)
  182. << " bytes over netlink socket.");
  183. }
  184. }
  185. /// @brief Appends nlmsg to a storage.
  186. ///
  187. /// This method copies pointed nlmsg to a newly allocated memory
  188. /// and adds it to storage.
  189. ///
  190. /// @param storage A vector that holds pointers to netlink messages. The caller
  191. /// is responsible for freeing the pointed-to messages.
  192. /// @param msg A netlink message to be added.
  193. void Netlink::rtnl_store_reply(NetlinkMessages& storage, const struct nlmsghdr *msg)
  194. {
  195. // we need to make a copy of this message. We really can't allocate
  196. // nlmsghdr directly as it is only part of the structure. There are
  197. // many message types with varying lengths and a common header.
  198. struct nlmsghdr* copy = reinterpret_cast<struct nlmsghdr*>(new char[msg->nlmsg_len]);
  199. memcpy(copy, msg, msg->nlmsg_len);
  200. // push_back copies only pointer content, not the pointed-to object.
  201. storage.push_back(copy);
  202. }
  203. /// @brief Parses rtattr message.
  204. ///
  205. /// Some netlink messages represent address information. Such messages
  206. /// are concatenated collection of rtaddr structures. This function
  207. /// iterates over that list and stores pointers to those messages in
  208. /// flat array (table).
  209. ///
  210. /// @param table rtattr Messages will be stored here
  211. /// @param rta Pointer to first rtattr object
  212. /// @param len Length (in bytes) of concatenated rtattr list.
  213. void Netlink::parse_rtattr(RTattribPtrs& table, struct rtattr* rta, int len)
  214. {
  215. std::fill(table.begin(), table.end(), static_cast<struct rtattr*>(NULL));
  216. // RTA_OK and RTA_NEXT() are macros defined in linux/rtnetlink.h
  217. // they are used to handle rtattributes. RTA_OK checks if the structure
  218. // pointed by rta is reasonable and passes all sanity checks.
  219. // RTA_NEXT() returns pointer to the next rtattr structure that
  220. // immediately follows pointed rta structure. See aforementioned
  221. // header for details.
  222. while (RTA_OK(rta, len)) {
  223. if (rta->rta_type < table.size()) {
  224. table[rta->rta_type] = rta;
  225. }
  226. rta = RTA_NEXT(rta,len);
  227. }
  228. if (len) {
  229. isc_throw(Unexpected, "Failed to parse RTATTR in netlink message.");
  230. }
  231. }
  232. /// @brief Parses addr_info and appends appropriate addresses to Iface object.
  233. ///
  234. /// Netlink is a fine, but convoluted interface. It returns a concatenated
  235. /// collection of netlink messages. Some of those messages convey information
  236. /// about addresses. Those messages are in fact appropriate header followed
  237. /// by concatenated lists of rtattr structures that define various pieces
  238. /// of address information.
  239. ///
  240. /// @param iface interface representation (addresses will be added here)
  241. /// @param addr_info collection of parsed netlink messages
  242. void Netlink::ipaddrs_get(IfaceMgr::Iface& iface, NetlinkMessages& addr_info) {
  243. uint8_t addr[V6ADDRESS_LEN];
  244. RTattribPtrs rta_tb;
  245. for (NetlinkMessages::const_iterator msg = addr_info.begin();
  246. msg != addr_info.end(); ++msg) {
  247. ifaddrmsg* ifa = static_cast<ifaddrmsg*>(NLMSG_DATA(*msg));
  248. // These are not the addresses you are looking for
  249. if (ifa->ifa_index != iface.getIndex()) {
  250. continue;
  251. }
  252. if ((ifa->ifa_family == AF_INET6) || (ifa->ifa_family == AF_INET)) {
  253. std::fill(rta_tb.begin(), rta_tb.end(), static_cast<rtattr*>(NULL));
  254. parse_rtattr(rta_tb, IFA_RTA(ifa), (*msg)->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
  255. if (!rta_tb[IFA_LOCAL]) {
  256. rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
  257. }
  258. if (!rta_tb[IFA_ADDRESS]) {
  259. rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
  260. }
  261. memcpy(addr, RTA_DATA(rta_tb[IFLA_ADDRESS]),
  262. ifa->ifa_family==AF_INET?V4ADDRESS_LEN:V6ADDRESS_LEN);
  263. IOAddress a = IOAddress::from_bytes(ifa->ifa_family, addr);
  264. iface.addAddress(a);
  265. /// TODO: Read lifetimes of configured IPv6 addresses
  266. }
  267. }
  268. }
  269. /// @brief Processes reply received over netlink socket.
  270. ///
  271. /// This method parses the received buffer (a collection of concatenated
  272. /// netlink messages), copies each received message to newly allocated
  273. /// memory and stores pointers to it in the "info" container.
  274. ///
  275. /// @param info received netlink messages will be stored here. It is the
  276. /// caller's responsibility to release the memory associated with the
  277. /// messages by calling the release_list() method.
  278. void Netlink::rtnl_process_reply(NetlinkMessages& info) {
  279. sockaddr_nl nladdr;
  280. iovec iov;
  281. msghdr msg;
  282. memset(&msg, 0, sizeof(msghdr));
  283. msg.msg_name = &nladdr;
  284. msg.msg_namelen = sizeof(nladdr);
  285. msg.msg_iov = &iov;
  286. msg.msg_iovlen = 1;
  287. char buf[RCVBUF_SIZE];
  288. iov.iov_base = buf;
  289. iov.iov_len = sizeof(buf);
  290. while (true) {
  291. int status = recvmsg(fd_, &msg, 0);
  292. if (status < 0) {
  293. if (errno == EINTR) {
  294. continue;
  295. }
  296. isc_throw(Unexpected, "Error " << errno
  297. << " while processing reply from netlink socket.");
  298. }
  299. if (status == 0) {
  300. isc_throw(Unexpected, "EOF while reading netlink socket.");
  301. }
  302. nlmsghdr* header = static_cast<nlmsghdr*>(static_cast<void*>(buf));
  303. while (NLMSG_OK(header, status)) {
  304. // Received a message not addressed to our process, or not
  305. // with a sequence number we are expecting. Ignore, and
  306. // look at the next one.
  307. if (nladdr.nl_pid != 0 ||
  308. header->nlmsg_pid != local_.nl_pid ||
  309. header->nlmsg_seq != dump_) {
  310. header = NLMSG_NEXT(header, status);
  311. continue;
  312. }
  313. if (header->nlmsg_type == NLMSG_DONE) {
  314. // End of message.
  315. return;
  316. }
  317. if (header->nlmsg_type == NLMSG_ERROR) {
  318. nlmsgerr* err = static_cast<nlmsgerr*>(NLMSG_DATA(header));
  319. if (header->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
  320. // We are really out of luck here. We can't even say what is
  321. // wrong as error message is truncated. D'oh.
  322. isc_throw(Unexpected, "Netlink reply read failed.");
  323. } else {
  324. isc_throw(Unexpected, "Netlink reply read error " << -err->error);
  325. }
  326. // Never happens we throw before we reach here
  327. return;
  328. }
  329. // store the data
  330. rtnl_store_reply(info, header);
  331. header = NLMSG_NEXT(header, status);
  332. }
  333. if (msg.msg_flags & MSG_TRUNC) {
  334. isc_throw(Unexpected, "Message received over netlink truncated.");
  335. }
  336. if (status) {
  337. isc_throw(Unexpected, "Trailing garbage of " << status << " bytes received over netlink.");
  338. }
  339. }
  340. }
  341. /// @brief releases nlmsg structure
  342. ///
  343. /// @param messages Set of messages to be freed.
  344. void Netlink::release_list(NetlinkMessages& messages) {
  345. // let's free local copies of stored messages
  346. for (NetlinkMessages::iterator msg = messages.begin(); msg != messages.end(); ++msg) {
  347. delete (*msg);
  348. }
  349. // ang get rid of the message pointers as well
  350. messages.clear();
  351. }
  352. } // end of anonymous namespace
  353. namespace isc {
  354. namespace dhcp {
  355. /// @brief Detect available interfaces on Linux systems.
  356. ///
  357. /// Uses the socket-based netlink protocol to retrieve the list of interfaces
  358. /// from the Linux kernel.
  359. void IfaceMgr::detectIfaces() {
  360. cout << "Linux: detecting interfaces." << endl;
  361. // Copies of netlink messages about links will be stored here.
  362. Netlink::NetlinkMessages link_info;
  363. // Copies of netlink messages about addresses will be stored here.
  364. Netlink::NetlinkMessages addr_info;
  365. // Socket descriptors and other rtnl-related parameters.
  366. Netlink nl;
  367. // Table with pointers to address attributes.
  368. Netlink::RTattribPtrs attribs_table;
  369. std::fill(attribs_table.begin(), attribs_table.end(),
  370. static_cast<struct rtattr*>(NULL));
  371. // Open socket
  372. nl.rtnl_open_socket();
  373. // Now we have open functional socket, let's use it!
  374. // Ask for list of network interfaces...
  375. nl.rtnl_send_request(AF_PACKET, RTM_GETLINK);
  376. // Get reply and store it in link_info list:
  377. // response is received as with any other socket - just a series
  378. // of bytes. They are representing collection of netlink messages
  379. // concatenated together. rtnl_process_reply will parse this
  380. // buffer, copy each message to a newly allocated memory and
  381. // store pointers to it in link_info. This allocated memory will
  382. // be released later. See release_info(link_info) below.
  383. nl.rtnl_process_reply(link_info);
  384. // Now ask for list of addresses (AF_UNSPEC = of any family)
  385. // Let's repeat, but this time ask for any addresses.
  386. // That includes IPv4, IPv6 and any other address families that
  387. // are happen to be supported by this system.
  388. nl.rtnl_send_request(AF_UNSPEC, RTM_GETADDR);
  389. // Get reply and store it in addr_info list.
  390. // Again, we will allocate new memory and store messages in
  391. // addr_info. It will be released later using release_info(addr_info).
  392. nl.rtnl_process_reply(addr_info);
  393. // Now build list with interface names
  394. for (Netlink::NetlinkMessages::iterator msg = link_info.begin();
  395. msg != link_info.end(); ++msg) {
  396. // Required to display information about interface
  397. struct ifinfomsg* interface_info = static_cast<ifinfomsg*>(NLMSG_DATA(*msg));
  398. int len = (*msg)->nlmsg_len;
  399. len -= NLMSG_LENGTH(sizeof(*interface_info));
  400. nl.parse_rtattr(attribs_table, IFLA_RTA(interface_info), len);
  401. // valgrind reports *possible* memory leak in the line below, but it is
  402. // bogus. Nevertheless, the whole interface definition has been split
  403. // into three separate steps for easier debugging.
  404. const char* tmp = static_cast<const char*>(RTA_DATA(attribs_table[IFLA_IFNAME]));
  405. string iface_name(tmp); // <--- bogus valgrind warning here
  406. Iface iface = Iface(iface_name, interface_info->ifi_index);
  407. iface.setHWType(interface_info->ifi_type);
  408. iface.setFlags(interface_info->ifi_flags);
  409. // Does inetface have LL_ADDR?
  410. if (attribs_table[IFLA_ADDRESS]) {
  411. iface.setMac(static_cast<const uint8_t*>(RTA_DATA(attribs_table[IFLA_ADDRESS])),
  412. RTA_PAYLOAD(attribs_table[IFLA_ADDRESS]));
  413. }
  414. else {
  415. // Tunnels can have no LL_ADDR. RTA_PAYLOAD doesn't check it and
  416. // try to dereference it in this manner
  417. }
  418. nl.ipaddrs_get(iface, addr_info);
  419. ifaces_.push_back(iface);
  420. }
  421. nl.release_list(link_info);
  422. nl.release_list(addr_info);
  423. printIfaces();
  424. }
  425. /// @brief sets flag_*_ fields.
  426. ///
  427. /// This implementation is OS-specific as bits have different meaning
  428. /// on different OSes.
  429. ///
  430. /// @param flags flags bitfield read from OS
  431. void IfaceMgr::Iface::setFlags(uint32_t flags) {
  432. flags_ = flags;
  433. flag_loopback_ = flags & IFF_LOOPBACK;
  434. flag_up_ = flags & IFF_UP;
  435. flag_running_ = flags & IFF_RUNNING;
  436. flag_multicast_ = flags & IFF_MULTICAST;
  437. flag_broadcast_ = flags & IFF_BROADCAST;
  438. }
  439. void IfaceMgr::os_send4(struct msghdr& m, boost::scoped_array<char>& control_buf,
  440. size_t control_buf_len, const Pkt4Ptr& pkt) {
  441. // Setting the interface is a bit more involved.
  442. //
  443. // We have to create a "control message", and set that to
  444. // define the IPv4 packet information. We could set the
  445. // source address if we wanted, but we can safely let the
  446. // kernel decide what that should be.
  447. m.msg_control = &control_buf[0];
  448. m.msg_controllen = control_buf_len;
  449. struct cmsghdr* cmsg = CMSG_FIRSTHDR(&m);
  450. cmsg->cmsg_level = IPPROTO_IP;
  451. cmsg->cmsg_type = IP_PKTINFO;
  452. cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
  453. struct in_pktinfo* pktinfo =(struct in_pktinfo *)CMSG_DATA(cmsg);
  454. memset(pktinfo, 0, sizeof(struct in_pktinfo));
  455. pktinfo->ipi_ifindex = pkt->getIndex();
  456. m.msg_controllen = cmsg->cmsg_len;
  457. }
  458. bool IfaceMgr::os_receive4(struct msghdr& m, Pkt4Ptr& pkt) {
  459. struct cmsghdr* cmsg;
  460. struct in_pktinfo* pktinfo;
  461. struct in_addr to_addr;
  462. memset(&to_addr, 0, sizeof(to_addr));
  463. cmsg = CMSG_FIRSTHDR(&m);
  464. while (cmsg != NULL) {
  465. if ((cmsg->cmsg_level == IPPROTO_IP) &&
  466. (cmsg->cmsg_type == IP_PKTINFO)) {
  467. pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
  468. pkt->setIndex(pktinfo->ipi_ifindex);
  469. pkt->setLocalAddr(IOAddress(htonl(pktinfo->ipi_addr.s_addr)));
  470. return (true);
  471. // This field is useful, when we are bound to unicast
  472. // address e.g. 192.0.2.1 and the packet was sent to
  473. // broadcast. This will return broadcast address, not
  474. // the address we are bound to.
  475. // IOAddress tmp(htonl(pktinfo->ipi_spec_dst.s_addr));
  476. // cout << "The other addr is: " << tmp.toText() << endl;
  477. // Perhaps we should uncomment this:
  478. // to_addr = pktinfo->ipi_spec_dst;
  479. }
  480. cmsg = CMSG_NXTHDR(&m, cmsg);
  481. }
  482. return (false);
  483. }
  484. } // end of isc::dhcp namespace
  485. } // end of isc namespace
  486. #endif // if defined(LINUX)