ifaddrs.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /* getifaddrs -- get names and addresses of all network interfaces
  2. Copyright (C) 2002-2019 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <http://www.gnu.org/licenses/>. */
  15. #include <ifaddrs.h>
  16. #include <net/if.h>
  17. #include <sys/socket.h>
  18. #include <sys/ioctl.h>
  19. #include <unistd.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <errno.h>
  23. #include <netinet/in.h>
  24. #include "ifreq.h"
  25. /* Create a linked list of `struct ifaddrs' structures, one for each
  26. network interface on the host machine. If successful, store the
  27. list in *IFAP and return 0. On errors, return -1 and set `errno'. */
  28. int
  29. __getifaddrs (struct ifaddrs **ifap)
  30. {
  31. /* This implementation handles only IPv4 interfaces.
  32. The various ioctls below will only work on an AF_INET socket.
  33. Some different mechanism entirely must be used for IPv6. */
  34. int fd = __socket (AF_INET, SOCK_DGRAM, 0);
  35. struct ifreq *ifreqs;
  36. int nifs;
  37. if (fd < 0)
  38. return -1;
  39. __ifreq (&ifreqs, &nifs, fd);
  40. if (ifreqs == NULL) /* XXX doesn't distinguish error vs none */
  41. {
  42. __close (fd);
  43. return -1;
  44. }
  45. /* Now we have the list of interfaces and each one's address.
  46. Put it into the expected format and fill in the remaining details. */
  47. if (nifs == 0)
  48. *ifap = NULL;
  49. else
  50. {
  51. struct
  52. {
  53. struct ifaddrs ia;
  54. struct sockaddr addr, netmask, broadaddr;
  55. char name[IF_NAMESIZE];
  56. } *storage;
  57. struct ifreq *ifr;
  58. int i;
  59. storage = malloc (nifs * sizeof storage[0]);
  60. if (storage == NULL)
  61. {
  62. __close (fd);
  63. __if_freereq (ifreqs, nifs);
  64. return -1;
  65. }
  66. i = 0;
  67. ifr = ifreqs;
  68. do
  69. {
  70. /* Fill in pointers to the storage we've already allocated. */
  71. storage[i].ia.ifa_next = &storage[i + 1].ia;
  72. storage[i].ia.ifa_addr = &storage[i].addr;
  73. /* Now copy the information we already have from SIOCGIFCONF. */
  74. storage[i].ia.ifa_name = strncpy (storage[i].name, ifr->ifr_name,
  75. sizeof storage[i].name);
  76. storage[i].addr = ifr->ifr_addr;
  77. /* The SIOCGIFCONF call filled in only the name and address.
  78. Now we must also ask for the other information we need. */
  79. if (__ioctl (fd, SIOCGIFFLAGS, ifr) < 0)
  80. break;
  81. storage[i].ia.ifa_flags = ifr->ifr_flags;
  82. ifr->ifr_addr = storage[i].addr;
  83. if (__ioctl (fd, SIOCGIFNETMASK, ifr) < 0)
  84. storage[i].ia.ifa_netmask = NULL;
  85. else
  86. {
  87. storage[i].ia.ifa_netmask = &storage[i].netmask;
  88. storage[i].netmask = ifr->ifr_netmask;
  89. }
  90. if (ifr->ifr_flags & IFF_BROADCAST)
  91. {
  92. ifr->ifr_addr = storage[i].addr;
  93. if (__ioctl (fd, SIOCGIFBRDADDR, ifr) < 0)
  94. storage[i].ia.ifa_broadaddr = NULL;
  95. {
  96. storage[i].ia.ifa_broadaddr = &storage[i].broadaddr;
  97. storage[i].broadaddr = ifr->ifr_broadaddr;
  98. }
  99. }
  100. else if (ifr->ifr_flags & IFF_POINTOPOINT)
  101. {
  102. ifr->ifr_addr = storage[i].addr;
  103. if (__ioctl (fd, SIOCGIFDSTADDR, ifr) < 0)
  104. storage[i].ia.ifa_broadaddr = NULL;
  105. else
  106. {
  107. storage[i].ia.ifa_broadaddr = &storage[i].broadaddr;
  108. storage[i].broadaddr = ifr->ifr_dstaddr;
  109. }
  110. }
  111. else
  112. storage[i].ia.ifa_broadaddr = NULL;
  113. storage[i].ia.ifa_data = NULL; /* Nothing here for now. */
  114. ifr = __if_nextreq (ifr);
  115. } while (++i < nifs);
  116. if (i < nifs) /* Broke out early on error. */
  117. {
  118. __close (fd);
  119. free (storage);
  120. __if_freereq (ifreqs, nifs);
  121. return -1;
  122. }
  123. storage[i - 1].ia.ifa_next = NULL;
  124. *ifap = &storage[0].ia;
  125. __close (fd);
  126. __if_freereq (ifreqs, nifs);
  127. }
  128. return 0;
  129. }
  130. weak_alias (__getifaddrs, getifaddrs)
  131. libc_hidden_def (__getifaddrs)
  132. #ifndef getifaddrs
  133. libc_hidden_weak (getifaddrs)
  134. #endif
  135. void
  136. __freeifaddrs (struct ifaddrs *ifa)
  137. {
  138. free (ifa);
  139. }
  140. weak_alias (__freeifaddrs, freeifaddrs)
  141. libc_hidden_def (__freeifaddrs)
  142. libc_hidden_weak (freeifaddrs)