if_index.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /* Copyright (C) 1997-2019 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. The GNU C Library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 2.1 of the License, or (at your option) any later version.
  7. The GNU C Library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public
  12. License along with the GNU C Library; if not, see
  13. <http://www.gnu.org/licenses/>. */
  14. #include <alloca.h>
  15. #include <errno.h>
  16. #include <string.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <unistd.h>
  20. #include <net/if.h>
  21. #include <sys/socket.h>
  22. #include <sys/ioctl.h>
  23. #include <libc-lock.h>
  24. #include <not-cancel.h>
  25. #include "netlinkaccess.h"
  26. unsigned int
  27. __if_nametoindex (const char *ifname)
  28. {
  29. #ifndef SIOCGIFINDEX
  30. __set_errno (ENOSYS);
  31. return 0;
  32. #else
  33. struct ifreq ifr;
  34. if (strlen (ifname) >= IFNAMSIZ)
  35. {
  36. __set_errno (ENODEV);
  37. return 0;
  38. }
  39. strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
  40. int fd = __opensock ();
  41. if (fd < 0)
  42. return 0;
  43. if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
  44. {
  45. int saved_errno = errno;
  46. __close_nocancel_nostatus (fd);
  47. if (saved_errno == EINVAL)
  48. __set_errno (ENOSYS);
  49. return 0;
  50. }
  51. __close_nocancel_nostatus (fd);
  52. return ifr.ifr_ifindex;
  53. #endif
  54. }
  55. libc_hidden_def (__if_nametoindex)
  56. weak_alias (__if_nametoindex, if_nametoindex)
  57. libc_hidden_weak (if_nametoindex)
  58. void
  59. __if_freenameindex (struct if_nameindex *ifn)
  60. {
  61. struct if_nameindex *ptr = ifn;
  62. while (ptr->if_name || ptr->if_index)
  63. {
  64. free (ptr->if_name);
  65. ++ptr;
  66. }
  67. free (ifn);
  68. }
  69. libc_hidden_def (__if_freenameindex)
  70. weak_alias (__if_freenameindex, if_freenameindex)
  71. libc_hidden_weak (if_freenameindex)
  72. static struct if_nameindex *
  73. if_nameindex_netlink (void)
  74. {
  75. struct netlink_handle nh = { 0, 0, 0, NULL, NULL };
  76. struct if_nameindex *idx = NULL;
  77. if (__netlink_open (&nh) < 0)
  78. return NULL;
  79. /* Tell the kernel that we wish to get a list of all
  80. active interfaces. Collect all data for every interface. */
  81. if (__netlink_request (&nh, RTM_GETLINK) < 0)
  82. goto exit_free;
  83. /* Count the interfaces. */
  84. unsigned int nifs = 0;
  85. for (struct netlink_res *nlp = nh.nlm_list; nlp; nlp = nlp->next)
  86. {
  87. struct nlmsghdr *nlh;
  88. size_t size = nlp->size;
  89. if (nlp->nlh == NULL)
  90. continue;
  91. /* Walk through all entries we got from the kernel and look, which
  92. message type they contain. */
  93. for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
  94. {
  95. /* Check if the message is what we want. */
  96. if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
  97. continue;
  98. if (nlh->nlmsg_type == NLMSG_DONE)
  99. break; /* ok */
  100. if (nlh->nlmsg_type == RTM_NEWLINK)
  101. ++nifs;
  102. }
  103. }
  104. idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
  105. if (idx == NULL)
  106. {
  107. nomem:
  108. __set_errno (ENOBUFS);
  109. goto exit_free;
  110. }
  111. /* Add the interfaces. */
  112. nifs = 0;
  113. for (struct netlink_res *nlp = nh.nlm_list; nlp; nlp = nlp->next)
  114. {
  115. struct nlmsghdr *nlh;
  116. size_t size = nlp->size;
  117. if (nlp->nlh == NULL)
  118. continue;
  119. /* Walk through all entries we got from the kernel and look, which
  120. message type they contain. */
  121. for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
  122. {
  123. /* Check if the message is what we want. */
  124. if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
  125. continue;
  126. if (nlh->nlmsg_type == NLMSG_DONE)
  127. break; /* ok */
  128. if (nlh->nlmsg_type == RTM_NEWLINK)
  129. {
  130. struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
  131. struct rtattr *rta = IFLA_RTA (ifim);
  132. size_t rtasize = IFLA_PAYLOAD (nlh);
  133. idx[nifs].if_index = ifim->ifi_index;
  134. while (RTA_OK (rta, rtasize))
  135. {
  136. char *rta_data = RTA_DATA (rta);
  137. size_t rta_payload = RTA_PAYLOAD (rta);
  138. if (rta->rta_type == IFLA_IFNAME)
  139. {
  140. idx[nifs].if_name = __strndup (rta_data, rta_payload);
  141. if (idx[nifs].if_name == NULL)
  142. {
  143. idx[nifs].if_index = 0;
  144. __if_freenameindex (idx);
  145. idx = NULL;
  146. goto nomem;
  147. }
  148. break;
  149. }
  150. rta = RTA_NEXT (rta, rtasize);
  151. }
  152. ++nifs;
  153. }
  154. }
  155. }
  156. idx[nifs].if_index = 0;
  157. idx[nifs].if_name = NULL;
  158. exit_free:
  159. __netlink_free_handle (&nh);
  160. __netlink_close (&nh);
  161. return idx;
  162. }
  163. struct if_nameindex *
  164. __if_nameindex (void)
  165. {
  166. #ifndef SIOCGIFINDEX
  167. __set_errno (ENOSYS);
  168. return NULL;
  169. #else
  170. struct if_nameindex *result = if_nameindex_netlink ();
  171. return result;
  172. #endif
  173. }
  174. weak_alias (__if_nameindex, if_nameindex)
  175. libc_hidden_weak (if_nameindex)
  176. char *
  177. __if_indextoname (unsigned int ifindex, char *ifname)
  178. {
  179. /* We may be able to do the conversion directly, rather than searching a
  180. list. This ioctl is not present in kernels before version 2.1.50. */
  181. struct ifreq ifr;
  182. int fd;
  183. int status;
  184. fd = __opensock ();
  185. if (fd < 0)
  186. return NULL;
  187. ifr.ifr_ifindex = ifindex;
  188. status = __ioctl (fd, SIOCGIFNAME, &ifr);
  189. __close_nocancel_nostatus (fd);
  190. if (status < 0)
  191. {
  192. if (errno == ENODEV)
  193. /* POSIX requires ENXIO. */
  194. __set_errno (ENXIO);
  195. return NULL;
  196. }
  197. else
  198. return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
  199. }
  200. weak_alias (__if_indextoname, if_indextoname)
  201. libc_hidden_weak (if_indextoname)