Portable build framework for OpenNTPD
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

222 lines
5.6 KiB

  1. /* The following code was found on the OpenSolaris networking-discuss
  2. * mailing list (http://markmail.org/message/t74kvl63savhzrzp) in a post
  3. * by James Carlson.
  4. */
  5. /*
  6. * Copyright (c) 2006 WIDE Project. All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3. Neither the name of the project nor the names of its contributors
  17. * may be used to endorse or promote products derived from this software
  18. * without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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 <unistd.h>
  33. #include <stdlib.h>
  34. #include <errno.h>
  35. #include <string.h>
  36. #include <sys/sockio.h>
  37. #include <sys/socket.h>
  38. #include <net/if.h>
  39. #include "ifaddrs.h"
  40. static int
  41. get_lifreq(int fd, struct lifreq **ifr_ret)
  42. {
  43. struct lifnum lifn;
  44. struct lifconf lifc;
  45. struct lifreq *lifrp;
  46. lifn.lifn_family = AF_UNSPEC;
  47. lifn.lifn_flags = 0;
  48. if (ioctl(fd, SIOCGLIFNUM, &lifn) == -1)
  49. lifn.lifn_count = 16;
  50. else
  51. lifn.lifn_count += 16;
  52. for (;;) {
  53. lifc.lifc_len = lifn.lifn_count * sizeof (*lifrp);
  54. lifrp = malloc(lifc.lifc_len);
  55. if (lifrp == NULL)
  56. return (-1);
  57. lifc.lifc_family = AF_UNSPEC;
  58. lifc.lifc_flags = 0;
  59. lifc.lifc_buf = (char *)lifrp;
  60. if (ioctl(fd, SIOCGLIFCONF, &lifc) == -1) {
  61. free(lifrp);
  62. if (errno == EINVAL) {
  63. lifn.lifn_count <<= 1;
  64. continue;
  65. }
  66. (void) close(fd);
  67. return (-1);
  68. }
  69. if (lifc.lifc_len < (lifn.lifn_count - 1) * sizeof (*lifrp))
  70. break;
  71. free(lifrp);
  72. lifn.lifn_count <<= 1;
  73. }
  74. (void) close(fd);
  75. *ifr_ret = lifrp;
  76. return (lifc.lifc_len / sizeof (*lifrp));
  77. }
  78. static size_t
  79. nbytes(const struct lifreq *lifrp, int nlif, size_t socklen)
  80. {
  81. size_t len = 0;
  82. size_t slen;
  83. while (nlif > 0) {
  84. slen = strlen(lifrp->lifr_name) + 1;
  85. len += sizeof (struct ifaddrs) + ((slen + 3) & ~3);
  86. len += 3 * socklen;
  87. lifrp++;
  88. nlif--;
  89. }
  90. return (len);
  91. }
  92. static struct sockaddr *
  93. addrcpy(struct sockaddr_storage *addr, char **bufp)
  94. {
  95. char *buf = *bufp;
  96. size_t len;
  97. len = addr->ss_family == AF_INET ? sizeof (struct sockaddr_in) :
  98. sizeof (struct sockaddr_in6);
  99. (void) memcpy(buf, addr, len);
  100. *bufp = buf + len;
  101. return ((struct sockaddr *)buf);
  102. }
  103. static int
  104. populate(struct ifaddrs *ifa, int fd, struct lifreq *lifrp, int nlif, int af,
  105. char **bufp)
  106. {
  107. char *buf = *bufp;
  108. size_t slen;
  109. while (nlif > 0) {
  110. ifa->ifa_next = (nlif > 1) ? ifa + 1 : NULL;
  111. (void) strcpy(ifa->ifa_name = buf, lifrp->lifr_name);
  112. slen = strlen(lifrp->lifr_name) + 1;
  113. buf += (slen + 3) & ~3;
  114. if (ioctl(fd, SIOCGLIFFLAGS, lifrp) == -1)
  115. ifa->ifa_flags = 0;
  116. else
  117. ifa->ifa_flags = lifrp->lifr_flags;
  118. if (ioctl(fd, SIOCGLIFADDR, lifrp) == -1)
  119. ifa->ifa_addr = NULL;
  120. else
  121. ifa->ifa_addr = addrcpy(&lifrp->lifr_addr, &buf);
  122. if (ioctl(fd, SIOCGLIFNETMASK, lifrp) == -1)
  123. ifa->ifa_netmask = NULL;
  124. else
  125. ifa->ifa_netmask = addrcpy(&lifrp->lifr_addr, &buf);
  126. if (ifa->ifa_flags & IFF_POINTOPOINT) {
  127. if (ioctl(fd, SIOCGLIFDSTADDR, lifrp) == -1)
  128. ifa->ifa_dstaddr = NULL;
  129. else
  130. ifa->ifa_dstaddr =
  131. addrcpy(&lifrp->lifr_dstaddr, &buf);
  132. } else if (ifa->ifa_flags & IFF_BROADCAST) {
  133. if (ioctl(fd, SIOCGLIFBRDADDR, lifrp) == -1)
  134. ifa->ifa_broadaddr = NULL;
  135. else
  136. ifa->ifa_broadaddr =
  137. addrcpy(&lifrp->lifr_broadaddr, &buf);
  138. } else {
  139. ifa->ifa_dstaddr = NULL;
  140. }
  141. ifa++;
  142. nlif--;
  143. lifrp++;
  144. }
  145. *bufp = buf;
  146. return (0);
  147. }
  148. int
  149. getifaddrs(struct ifaddrs **ifap)
  150. {
  151. int fd4, fd6;
  152. int nif4, nif6 = 0;
  153. struct lifreq *ifr4 = NULL;
  154. struct lifreq *ifr6 = NULL;
  155. struct ifaddrs *ifa = NULL;
  156. char *buf;
  157. if ((fd4 = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
  158. return (-1);
  159. if ((fd6 = socket(AF_INET6, SOCK_DGRAM, 0)) == -1 &&
  160. errno != EAFNOSUPPORT) {
  161. (void) close(fd4);
  162. return (-1);
  163. }
  164. if ((nif4 = get_lifreq(fd4, &ifr4)) == -1 ||
  165. (fd6 != -1 && (nif6 = get_lifreq(fd6, &ifr6)) == -1))
  166. goto failure;
  167. if (nif4 == 0 && nif6 == 0) {
  168. *ifap = NULL;
  169. return (0);
  170. }
  171. ifa = malloc(nbytes(ifr4, nif4, sizeof (struct sockaddr_in)) +
  172. nbytes(ifr6, nif6, sizeof (struct sockaddr_in6)));
  173. if (ifa == NULL)
  174. goto failure;
  175. buf = (char *)(ifa + nif4 + nif6);
  176. if (populate(ifa, fd4, ifr4, nif4, AF_INET, &buf) == -1)
  177. goto failure;
  178. if (nif4 > 0 && nif6 > 0)
  179. ifa[nif4 - 1].ifa_next = ifa + nif4;
  180. if (populate(ifa + nif4, fd6, ifr6, nif6, AF_INET6, &buf) == -1)
  181. goto failure;
  182. return (0);
  183. failure:
  184. free(ifa);
  185. (void) close(fd4);
  186. if (fd6 != -1)
  187. (void) close(fd6);
  188. free(ifr4);
  189. free(ifr6);
  190. return (-1);
  191. }
  192. void
  193. freeifaddrs(struct ifaddrs *ifa)
  194. {
  195. free(ifa);
  196. }