get_ifi_info.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /* include get_ifi_info1 */
  2. #include "unpifi.h"
  3. struct ifi_info *
  4. get_ifi_info(int family, int doaliases)
  5. {
  6. struct ifi_info *ifi, *ifihead, **ifipnext;
  7. int sockfd, len, lastlen, flags, myflags, idx = 0, hlen = 0;
  8. char *ptr, *buf, lastname[IFNAMSIZ], *cptr, *haddr, *sdlname;
  9. struct ifconf ifc;
  10. struct ifreq *ifr, ifrcopy;
  11. struct sockaddr_in *sinptr;
  12. struct sockaddr_in6 *sin6ptr;
  13. sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
  14. lastlen = 0;
  15. len = 100 * sizeof(struct ifreq); /* initial buffer size guess */
  16. for ( ; ; ) {
  17. buf = Malloc(len);
  18. ifc.ifc_len = len;
  19. ifc.ifc_buf = buf;
  20. if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
  21. if (errno != EINVAL || lastlen != 0)
  22. err_sys("ioctl error");
  23. } else {
  24. if (ifc.ifc_len == lastlen)
  25. break; /* success, len has not changed */
  26. lastlen = ifc.ifc_len;
  27. }
  28. len += 10 * sizeof(struct ifreq); /* increment */
  29. free(buf);
  30. }
  31. ifihead = NULL;
  32. ifipnext = &ifihead;
  33. lastname[0] = 0;
  34. sdlname = NULL;
  35. /* end get_ifi_info1 */
  36. /* include get_ifi_info2 */
  37. for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
  38. ifr = (struct ifreq *) ptr;
  39. #ifdef HAVE_SOCKADDR_SA_LEN
  40. len = max(sizeof(struct sockaddr), ifr->ifr_addr.sa_len);
  41. #else
  42. switch (ifr->ifr_addr.sa_family) {
  43. #ifdef IPV6
  44. case AF_INET6:
  45. len = sizeof(struct sockaddr_in6);
  46. break;
  47. #endif
  48. case AF_INET:
  49. default:
  50. len = sizeof(struct sockaddr);
  51. break;
  52. }
  53. #endif /* HAVE_SOCKADDR_SA_LEN */
  54. ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */
  55. #ifdef HAVE_SOCKADDR_DL_STRUCT
  56. /* assumes that AF_LINK precedes AF_INET or AF_INET6 */
  57. if (ifr->ifr_addr.sa_family == AF_LINK) {
  58. struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr;
  59. sdlname = ifr->ifr_name;
  60. idx = sdl->sdl_index;
  61. haddr = sdl->sdl_data + sdl->sdl_nlen;
  62. hlen = sdl->sdl_alen;
  63. }
  64. #endif
  65. if (ifr->ifr_addr.sa_family != family)
  66. continue; /* ignore if not desired address family */
  67. myflags = 0;
  68. if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
  69. *cptr = 0; /* replace colon with null */
  70. if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
  71. if (doaliases == 0)
  72. continue; /* already processed this interface */
  73. myflags = IFI_ALIAS;
  74. }
  75. memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
  76. ifrcopy = *ifr;
  77. Ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy);
  78. flags = ifrcopy.ifr_flags;
  79. if ((flags & IFF_UP) == 0)
  80. continue; /* ignore if interface not up */
  81. /* end get_ifi_info2 */
  82. /* include get_ifi_info3 */
  83. ifi = Calloc(1, sizeof(struct ifi_info));
  84. *ifipnext = ifi; /* prev points to this new one */
  85. ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
  86. ifi->ifi_flags = flags; /* IFF_xxx values */
  87. ifi->ifi_myflags = myflags; /* IFI_xxx values */
  88. #if defined(SIOCGIFMTU) && defined(HAVE_STRUCT_IFREQ_IFR_MTU)
  89. Ioctl(sockfd, SIOCGIFMTU, &ifrcopy);
  90. ifi->ifi_mtu = ifrcopy.ifr_mtu;
  91. #else
  92. ifi->ifi_mtu = 0;
  93. #endif
  94. memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
  95. ifi->ifi_name[IFI_NAME-1] = '\0';
  96. /* If the sockaddr_dl is from a different interface, ignore it */
  97. if (sdlname == NULL || strcmp(sdlname, ifr->ifr_name) != 0)
  98. idx = hlen = 0;
  99. ifi->ifi_index = idx;
  100. ifi->ifi_hlen = hlen;
  101. if (ifi->ifi_hlen > IFI_HADDR)
  102. ifi->ifi_hlen = IFI_HADDR;
  103. if (hlen)
  104. memcpy(ifi->ifi_haddr, haddr, ifi->ifi_hlen);
  105. /* end get_ifi_info3 */
  106. /* include get_ifi_info4 */
  107. switch (ifr->ifr_addr.sa_family) {
  108. case AF_INET:
  109. sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
  110. ifi->ifi_addr = Calloc(1, sizeof(struct sockaddr_in));
  111. memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
  112. #ifdef SIOCGIFBRDADDR
  113. if (flags & IFF_BROADCAST) {
  114. Ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy);
  115. sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
  116. ifi->ifi_brdaddr = Calloc(1, sizeof(struct sockaddr_in));
  117. memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
  118. }
  119. #endif
  120. #ifdef SIOCGIFDSTADDR
  121. if (flags & IFF_POINTOPOINT) {
  122. Ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy);
  123. sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
  124. ifi->ifi_dstaddr = Calloc(1, sizeof(struct sockaddr_in));
  125. memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
  126. }
  127. #endif
  128. break;
  129. case AF_INET6:
  130. sin6ptr = (struct sockaddr_in6 *) &ifr->ifr_addr;
  131. ifi->ifi_addr = Calloc(1, sizeof(struct sockaddr_in6));
  132. memcpy(ifi->ifi_addr, sin6ptr, sizeof(struct sockaddr_in6));
  133. #ifdef SIOCGIFDSTADDR
  134. if (flags & IFF_POINTOPOINT) {
  135. Ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy);
  136. sin6ptr = (struct sockaddr_in6 *) &ifrcopy.ifr_dstaddr;
  137. ifi->ifi_dstaddr = Calloc(1, sizeof(struct sockaddr_in6));
  138. memcpy(ifi->ifi_dstaddr, sin6ptr, sizeof(struct sockaddr_in6));
  139. }
  140. #endif
  141. break;
  142. default:
  143. break;
  144. }
  145. }
  146. free(buf);
  147. return(ifihead); /* pointer to first structure in linked list */
  148. }
  149. /* end get_ifi_info4 */
  150. /* include free_ifi_info */
  151. void
  152. free_ifi_info(struct ifi_info *ifihead)
  153. {
  154. struct ifi_info *ifi, *ifinext;
  155. for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
  156. if (ifi->ifi_addr != NULL)
  157. free(ifi->ifi_addr);
  158. if (ifi->ifi_brdaddr != NULL)
  159. free(ifi->ifi_brdaddr);
  160. if (ifi->ifi_dstaddr != NULL)
  161. free(ifi->ifi_dstaddr);
  162. ifinext = ifi->ifi_next; /* can't fetch ifi_next after free() */
  163. free(ifi); /* the ifi_info{} itself */
  164. }
  165. }
  166. /* end free_ifi_info */
  167. struct ifi_info *
  168. Get_ifi_info(int family, int doaliases)
  169. {
  170. struct ifi_info *ifi;
  171. if ( (ifi = get_ifi_info(family, doaliases)) == NULL)
  172. err_quit("get_ifi_info error");
  173. return(ifi);
  174. }