freebsd_getifmaddrs.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. this BSD licensed code is from https://github.com/freebsd/freebsd/blob/386ddae58459341ec567604707805814a2128a57/lib/libc/net/getifmaddrs.c
  3. as in older OS X there is no getifmaddrs() and related functions is NetBSD
  4. */
  5. #define NET_RT_IFMALIST 4 /* return multicast address list */
  6. #define RTM_NEWMADDR 0xf /* mcast group membership being added to if */
  7. /*
  8. * Copyright (c) 2003 Bruce M. Simpson.
  9. * All rights reserved
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions
  13. * are met:
  14. * 1. Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. * 2. Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in the
  18. * documentation and/or other materials provided with the distribution.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30. * SUCH DAMAGE.
  31. */
  32. #include <sys/cdefs.h>
  33. /*
  34. __FBSDID("$FreeBSD$");
  35. #include "namespace.h"*/
  36. #include <sys/param.h>
  37. #include <sys/sysctl.h>
  38. #include <sys/ioctl.h>
  39. #include <sys/socket.h>
  40. #include <net/if.h>
  41. #include <net/if_dl.h>
  42. #include <net/route.h>
  43. #include <errno.h>
  44. #include <ifaddrs.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. //#include "un-namespace.h"
  48. #define SALIGN (sizeof(long) - 1)
  49. #define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \
  50. (SALIGN + 1))
  51. #define MAX_SYSCTL_TRY 5
  52. #define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA)
  53. int
  54. getifmaddrs(struct ifmaddrs **pif)
  55. {
  56. int icnt = 1;
  57. int dcnt = 0;
  58. int ntry = 0;
  59. size_t len;
  60. size_t needed;
  61. int mib[6];
  62. int i;
  63. char *buf;
  64. char *data;
  65. char *next;
  66. char *p;
  67. struct ifma_msghdr *ifmam;
  68. struct ifmaddrs *ifa, *ift;
  69. struct rt_msghdr *rtm;
  70. struct sockaddr *sa;
  71. mib[0] = CTL_NET;
  72. mib[1] = PF_ROUTE;
  73. mib[2] = 0; /* protocol */
  74. mib[3] = 0; /* wildcard address family */
  75. mib[4] = NET_RT_IFMALIST;
  76. mib[5] = 0; /* no flags */
  77. do {
  78. if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
  79. return (-1);
  80. if ((buf = malloc(needed)) == NULL)
  81. return (-1);
  82. if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
  83. if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
  84. free(buf);
  85. return (-1);
  86. }
  87. free(buf);
  88. buf = NULL;
  89. }
  90. } while (buf == NULL);
  91. for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
  92. rtm = (struct rt_msghdr *)(void *)next;
  93. if (rtm->rtm_version != RTM_VERSION)
  94. continue;
  95. switch (rtm->rtm_type) {
  96. case RTM_NEWMADDR:
  97. ifmam = (struct ifma_msghdr *)(void *)rtm;
  98. if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
  99. break;
  100. icnt++;
  101. p = (char *)(ifmam + 1);
  102. for (i = 0; i < RTAX_MAX; i++) {
  103. if ((RTA_MASKS & ifmam->ifmam_addrs &
  104. (1 << i)) == 0)
  105. continue;
  106. sa = (struct sockaddr *)(void *)p;
  107. len = SA_RLEN(sa);
  108. dcnt += len;
  109. p += len;
  110. }
  111. break;
  112. }
  113. }
  114. data = malloc(sizeof(struct ifmaddrs) * icnt + dcnt);
  115. if (data == NULL) {
  116. free(buf);
  117. return (-1);
  118. }
  119. ifa = (struct ifmaddrs *)(void *)data;
  120. data += sizeof(struct ifmaddrs) * icnt;
  121. memset(ifa, 0, sizeof(struct ifmaddrs) * icnt);
  122. ift = ifa;
  123. for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
  124. rtm = (struct rt_msghdr *)(void *)next;
  125. if (rtm->rtm_version != RTM_VERSION)
  126. continue;
  127. switch (rtm->rtm_type) {
  128. case RTM_NEWMADDR:
  129. ifmam = (struct ifma_msghdr *)(void *)rtm;
  130. if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
  131. break;
  132. p = (char *)(ifmam + 1);
  133. for (i = 0; i < RTAX_MAX; i++) {
  134. if ((RTA_MASKS & ifmam->ifmam_addrs &
  135. (1 << i)) == 0)
  136. continue;
  137. sa = (struct sockaddr *)(void *)p;
  138. len = SA_RLEN(sa);
  139. switch (i) {
  140. case RTAX_GATEWAY:
  141. ift->ifma_lladdr =
  142. (struct sockaddr *)(void *)data;
  143. memcpy(data, p, len);
  144. data += len;
  145. break;
  146. case RTAX_IFP:
  147. ift->ifma_name =
  148. (struct sockaddr *)(void *)data;
  149. memcpy(data, p, len);
  150. data += len;
  151. break;
  152. case RTAX_IFA:
  153. ift->ifma_addr =
  154. (struct sockaddr *)(void *)data;
  155. memcpy(data, p, len);
  156. data += len;
  157. break;
  158. default:
  159. data += len;
  160. break;
  161. }
  162. p += len;
  163. }
  164. ift->ifma_next = ift + 1;
  165. ift = ift->ifma_next;
  166. break;
  167. }
  168. }
  169. free(buf);
  170. if (ift > ifa) {
  171. ift--;
  172. ift->ifma_next = NULL;
  173. *pif = ifa;
  174. } else {
  175. *pif = NULL;
  176. free(ifa);
  177. }
  178. return (0);
  179. }
  180. void
  181. freeifmaddrs(struct ifmaddrs *ifmp)
  182. {
  183. free(ifmp);
  184. }