1
0

getifaddrs.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. #define _GNU_SOURCE
  2. #include <errno.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include <unistd.h>
  6. #include <ifaddrs.h>
  7. #include <syscall.h>
  8. #include <net/if.h>
  9. #include <netinet/in.h>
  10. #include "netlink.h"
  11. #define IFADDRS_HASH_SIZE 64
  12. /* getifaddrs() reports hardware addresses with PF_PACKET that implies
  13. * struct sockaddr_ll. But e.g. Infiniband socket address length is
  14. * longer than sockaddr_ll.ssl_addr[8] can hold. Use this hack struct
  15. * to extend ssl_addr - callers should be able to still use it. */
  16. struct sockaddr_ll_hack {
  17. unsigned short sll_family, sll_protocol;
  18. int sll_ifindex;
  19. unsigned short sll_hatype;
  20. unsigned char sll_pkttype, sll_halen;
  21. unsigned char sll_addr[24];
  22. };
  23. union sockany {
  24. struct sockaddr sa;
  25. struct sockaddr_ll_hack ll;
  26. struct sockaddr_in v4;
  27. struct sockaddr_in6 v6;
  28. };
  29. struct ifaddrs_storage {
  30. struct ifaddrs ifa;
  31. struct ifaddrs_storage *hash_next;
  32. union sockany addr, netmask, ifu;
  33. unsigned int index;
  34. char name[IFNAMSIZ+1];
  35. };
  36. struct ifaddrs_ctx {
  37. struct ifaddrs_storage *first;
  38. struct ifaddrs_storage *last;
  39. struct ifaddrs_storage *hash[IFADDRS_HASH_SIZE];
  40. };
  41. void freeifaddrs(struct ifaddrs *ifp)
  42. {
  43. struct ifaddrs *n;
  44. while (ifp) {
  45. n = ifp->ifa_next;
  46. free(ifp);
  47. ifp = n;
  48. }
  49. }
  50. static void copy_addr(struct sockaddr **r, int af, union sockany *sa, void *addr, size_t addrlen, int ifindex)
  51. {
  52. uint8_t *dst;
  53. int len;
  54. switch (af) {
  55. case AF_INET:
  56. dst = (uint8_t*) &sa->v4.sin_addr;
  57. len = 4;
  58. break;
  59. case AF_INET6:
  60. dst = (uint8_t*) &sa->v6.sin6_addr;
  61. len = 16;
  62. if (IN6_IS_ADDR_LINKLOCAL(addr) || IN6_IS_ADDR_MC_LINKLOCAL(addr))
  63. sa->v6.sin6_scope_id = ifindex;
  64. break;
  65. default:
  66. return;
  67. }
  68. if (addrlen < len) return;
  69. sa->sa.sa_family = af;
  70. memcpy(dst, addr, len);
  71. *r = &sa->sa;
  72. }
  73. static void gen_netmask(struct sockaddr **r, int af, union sockany *sa, int prefixlen)
  74. {
  75. uint8_t addr[16] = {0};
  76. int i;
  77. if (prefixlen > 8*sizeof(addr)) prefixlen = 8*sizeof(addr);
  78. i = prefixlen / 8;
  79. memset(addr, 0xff, i);
  80. if (i < sizeof(addr)) addr[i++] = 0xff << (8 - (prefixlen % 8));
  81. copy_addr(r, af, sa, addr, sizeof(addr), 0);
  82. }
  83. static void copy_lladdr(struct sockaddr **r, union sockany *sa, void *addr, size_t addrlen, int ifindex, unsigned short hatype)
  84. {
  85. if (addrlen > sizeof(sa->ll.sll_addr)) return;
  86. sa->ll.sll_family = AF_PACKET;
  87. sa->ll.sll_ifindex = ifindex;
  88. sa->ll.sll_hatype = hatype;
  89. sa->ll.sll_halen = addrlen;
  90. memcpy(sa->ll.sll_addr, addr, addrlen);
  91. *r = &sa->sa;
  92. }
  93. static int netlink_msg_to_ifaddr(void *pctx, struct nlmsghdr *h)
  94. {
  95. struct ifaddrs_ctx *ctx = pctx;
  96. struct ifaddrs_storage *ifs, *ifs0;
  97. struct ifinfomsg *ifi = NLMSG_DATA(h);
  98. struct ifaddrmsg *ifa = NLMSG_DATA(h);
  99. struct rtattr *rta;
  100. int stats_len = 0;
  101. if (h->nlmsg_type == RTM_NEWLINK) {
  102. for (rta = NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) {
  103. if (rta->rta_type != IFLA_STATS) continue;
  104. stats_len = RTA_DATALEN(rta);
  105. break;
  106. }
  107. } else {
  108. for (ifs0 = ctx->hash[ifa->ifa_index % IFADDRS_HASH_SIZE]; ifs0; ifs0 = ifs0->hash_next)
  109. if (ifs0->index == ifa->ifa_index)
  110. break;
  111. if (!ifs0) return 0;
  112. }
  113. ifs = calloc(1, sizeof(struct ifaddrs_storage) + stats_len);
  114. if (ifs == 0) return -1;
  115. if (h->nlmsg_type == RTM_NEWLINK) {
  116. ifs->index = ifi->ifi_index;
  117. ifs->ifa.ifa_flags = ifi->ifi_flags;
  118. for (rta = NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) {
  119. switch (rta->rta_type) {
  120. case IFLA_IFNAME:
  121. if (RTA_DATALEN(rta) < sizeof(ifs->name)) {
  122. memcpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta));
  123. ifs->ifa.ifa_name = ifs->name;
  124. }
  125. break;
  126. case IFLA_ADDRESS:
  127. copy_lladdr(&ifs->ifa.ifa_addr, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifi->ifi_index, ifi->ifi_type);
  128. break;
  129. case IFLA_BROADCAST:
  130. copy_lladdr(&ifs->ifa.ifa_broadaddr, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifi->ifi_index, ifi->ifi_type);
  131. break;
  132. case IFLA_STATS:
  133. ifs->ifa.ifa_data = (void*)(ifs+1);
  134. memcpy(ifs->ifa.ifa_data, RTA_DATA(rta), RTA_DATALEN(rta));
  135. break;
  136. }
  137. }
  138. if (ifs->ifa.ifa_name) {
  139. unsigned int bucket = ifs->index % IFADDRS_HASH_SIZE;
  140. ifs->hash_next = ctx->hash[bucket];
  141. ctx->hash[bucket] = ifs;
  142. }
  143. } else {
  144. ifs->ifa.ifa_name = ifs0->ifa.ifa_name;
  145. ifs->ifa.ifa_flags = ifs0->ifa.ifa_flags;
  146. for (rta = NLMSG_RTA(h, sizeof(*ifa)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) {
  147. switch (rta->rta_type) {
  148. case IFA_ADDRESS:
  149. copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index);
  150. break;
  151. case IFA_BROADCAST:
  152. /* For point-to-point links this is peer, but ifa_broadaddr
  153. * and ifa_dstaddr are union, so this works for both. */
  154. copy_addr(&ifs->ifa.ifa_broadaddr, ifa->ifa_family, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index);
  155. break;
  156. case IFA_LABEL:
  157. if (RTA_DATALEN(rta) < sizeof(ifs->name)) {
  158. memcpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta));
  159. ifs->ifa.ifa_name = ifs->name;
  160. }
  161. break;
  162. }
  163. }
  164. if (ifs->ifa.ifa_addr)
  165. gen_netmask(&ifs->ifa.ifa_netmask, ifa->ifa_family, &ifs->netmask, ifa->ifa_prefixlen);
  166. }
  167. if (ifs->ifa.ifa_name) {
  168. if (!ctx->first) ctx->first = ifs;
  169. if (ctx->last) ctx->last->ifa.ifa_next = &ifs->ifa;
  170. ctx->last = ifs;
  171. } else {
  172. free(ifs);
  173. }
  174. return 0;
  175. }
  176. int getifaddrs(struct ifaddrs **ifap)
  177. {
  178. struct ifaddrs_ctx _ctx, *ctx = &_ctx;
  179. int r;
  180. memset(ctx, 0, sizeof *ctx);
  181. r = __rtnetlink_enumerate(AF_UNSPEC, AF_UNSPEC, netlink_msg_to_ifaddr, ctx);
  182. if (r == 0) *ifap = &ctx->first->ifa;
  183. else freeifaddrs(&ctx->first->ifa);
  184. return r;
  185. }