2 * Copyright (c) 1995, 1999
3 * Berkeley Software Design, Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
12 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14 * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
15 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
16 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
17 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
18 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
19 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
20 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
26 Copyright (c) 2013, Kenneth MacKay
29 Redistribution and use in source and binary forms, with or without modification,
30 are permitted provided that the following conditions are met:
31 * Redistributions of source code must retain the above copyright notice, this
32 list of conditions and the following disclaimer.
33 * Redistributions in binary form must reproduce the above copyright notice,
34 this list of conditions and the following disclaimer in the documentation
35 and/or other materials provided with the distribution.
37 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
38 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
39 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
41 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
42 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
44 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
45 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
46 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53 struct ifaddrs *ifa_next;
55 unsigned int ifa_flags;
56 struct sockaddr *ifa_addr;
57 struct sockaddr *ifa_netmask;
58 struct sockaddr *ifa_dstaddr;
63 * This may have been defined in <net/if.h>. Note that if <net/if.h> is
64 * to be included it must be included before this header file.
67 #define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
70 #include <sys/cdefs.h>
73 extern int getifaddrs(struct ifaddrs **ifap);
74 extern void freeifaddrs(struct ifaddrs *ifa);
85 #include <sys/socket.h>
86 #include <netpacket/packet.h>
87 #include <net/if_arp.h>
88 #include <netinet/in.h>
89 #include <linux/netlink.h>
90 #include <linux/rtnetlink.h>
92 typedef struct NetlinkList {
93 struct NetlinkList *m_next;
94 struct nlmsghdr *m_data;
98 static int netlink_socket(void)
100 int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
101 if (l_socket < 0) return -1;
103 struct sockaddr_nl l_addr;
104 memset(&l_addr, 0, sizeof(l_addr));
105 l_addr.nl_family = AF_NETLINK;
106 if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0) {
114 static int netlink_send(int p_socket, int p_request)
117 struct nlmsghdr m_hdr;
118 struct rtgenmsg m_msg;
121 memset(&l_data, 0, sizeof(l_data));
123 l_data.m_hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
124 l_data.m_hdr.nlmsg_type = p_request;
125 l_data.m_hdr.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
126 l_data.m_hdr.nlmsg_pid = 0;
127 l_data.m_hdr.nlmsg_seq = p_socket;
128 l_data.m_msg.rtgen_family = AF_UNSPEC;
130 struct sockaddr_nl l_addr;
131 memset(&l_addr, 0, sizeof(l_addr));
132 l_addr.nl_family = AF_NETLINK;
133 return (sendto(p_socket, &l_data.m_hdr, l_data.m_hdr.nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
136 static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
139 struct iovec l_iov = { p_buffer, p_len };
140 struct sockaddr_nl l_addr;
143 l_msg.msg_name = (void *)&l_addr;
144 l_msg.msg_namelen = sizeof(l_addr);
145 l_msg.msg_iov = &l_iov;
146 l_msg.msg_iovlen = 1;
147 l_msg.msg_control = NULL;
148 l_msg.msg_controllen = 0;
150 int l_result = recvmsg(p_socket, &l_msg, 0);
153 if (errno == EINTR) {
159 if (l_msg.msg_flags & MSG_TRUNC) {
160 /* Buffer was too small. */
167 static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
169 size_t l_size = 4096;
170 void *l_buffer = NULL;
174 l_buffer = malloc(l_size);
175 if (l_buffer == NULL) return NULL;
177 int l_read = netlink_recv(p_socket, l_buffer, l_size);
184 pid_t l_pid = getpid();
185 struct nlmsghdr *l_hdr;
186 for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read)) {
187 if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) continue;
189 if(l_hdr->nlmsg_type == NLMSG_DONE) {
194 if(l_hdr->nlmsg_type == NLMSG_ERROR) {
199 return (struct nlmsghdr*)l_buffer;
206 static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
208 NetlinkList *l_item = (NetlinkList*)malloc(sizeof(NetlinkList));
209 if (l_item == NULL) return NULL;
211 l_item->m_next = NULL;
212 l_item->m_data = p_data;
213 l_item->m_size = p_size;
217 static void freeResultList(NetlinkList *p_list)
222 p_list = p_list->m_next;
228 static NetlinkList *getResultList(int p_socket, int p_request)
230 if (netlink_send(p_socket, p_request) < 0) return NULL;
232 NetlinkList *l_list = NULL;
233 NetlinkList *l_end = NULL;
237 struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
239 freeResultList(l_list);
243 NetlinkList *l_item = newListItem(l_hdr, l_size);
245 freeResultList(l_list);
251 l_end->m_next = l_item;
258 static size_t maxSize(size_t a, size_t b)
260 return (a > b ? a : b);
263 static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
267 return sizeof(struct sockaddr_in);
269 return sizeof(struct sockaddr_in6);
271 return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
273 return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
277 static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
281 memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
284 memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
287 memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
288 ((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
291 memcpy(p_dest->sa_data, p_data, p_size);
294 p_dest->sa_family = p_family;
297 static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
299 if (!*p_resultList) {
300 *p_resultList = p_entry;
302 struct ifaddrs *l_cur = *p_resultList;
303 while(l_cur->ifa_next) {
304 l_cur = l_cur->ifa_next;
306 l_cur->ifa_next = p_entry;
310 static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
312 struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
314 size_t l_nameSize = 0;
315 size_t l_addrSize = 0;
316 size_t l_dataSize = 0;
318 size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
319 struct rtattr *l_rta;
320 for (l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) {
321 void *l_rtaData = RTA_DATA(l_rta);
322 size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
323 switch (l_rta->rta_type) {
326 l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
329 l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
332 l_dataSize += NLMSG_ALIGN(l_rtaSize);
339 struct ifaddrs *l_entry = (struct ifaddrs*)malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
340 if (l_entry == NULL) return -1;
341 memset(l_entry, 0, sizeof(struct ifaddrs));
342 l_entry->ifa_name = (char*)"";
344 char *l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
345 char *l_name = l_index + sizeof(int);
346 char *l_addr = l_name + l_nameSize;
347 char *l_data = l_addr + l_addrSize;
349 /* Save the interface index so we can look it up when handling the addresses. */
350 memcpy(l_index, &l_info->ifi_index, sizeof(int));
352 l_entry->ifa_flags = l_info->ifi_flags;
354 l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
355 for (l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) {
356 void *l_rtaData = RTA_DATA(l_rta);
357 size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
358 switch (l_rta->rta_type) {
362 size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
363 makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
364 ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
365 ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
366 if (l_rta->rta_type == IFLA_ADDRESS) {
367 l_entry->ifa_addr = (struct sockaddr *)l_addr;
369 l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
371 l_addr += NLMSG_ALIGN(l_addrLen);
375 strncpy(l_name, (char*)l_rtaData, l_rtaDataSize);
376 l_name[l_rtaDataSize] = '\0';
377 l_entry->ifa_name = l_name;
380 memcpy(l_data, l_rtaData, l_rtaDataSize);
381 l_entry->ifa_data = l_data;
388 addToEnd(p_resultList, l_entry);
392 static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
395 struct ifaddrs *l_cur = *p_links;
396 while (l_cur && l_num < p_numLinks) {
397 char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
399 memcpy(&l_index, l_indexPtr, sizeof(int));
400 if(l_index == p_index) return l_cur;
402 l_cur = l_cur->ifa_next;
408 static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
410 struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
411 struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
413 if (l_info->ifa_family == AF_PACKET) return 0;
415 size_t l_nameSize = 0;
416 size_t l_addrSize = 0;
417 int l_addedNetmask = 0;
419 size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
420 struct rtattr *l_rta;
421 for (l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) {
422 void *l_rtaData = RTA_DATA(l_rta);
423 size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
425 switch (l_rta->rta_type) {
428 if ((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask) {
429 /* Make room for netmask. */
430 l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
434 l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
437 l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
444 struct ifaddrs *l_entry = (struct ifaddrs*)malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
445 if (l_entry == NULL) return -1;
446 memset(l_entry, 0, sizeof(struct ifaddrs));
447 l_entry->ifa_name = (l_interface ? l_interface->ifa_name : (char*)"");
449 char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
450 char *l_addr = l_name + l_nameSize;
452 l_entry->ifa_flags = l_info->ifa_flags;
454 l_entry->ifa_flags |= l_interface->ifa_flags;
457 l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
458 for (l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) {
459 void *l_rtaData = RTA_DATA(l_rta);
460 size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
461 switch (l_rta->rta_type) {
466 size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
467 makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
468 if (l_info->ifa_family == AF_INET6) {
469 if (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData)) {
470 ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
474 if (l_rta->rta_type == IFA_ADDRESS) {
475 /* Apparently in a point-to-point network IFA_ADDRESS contains
476 the dest address and IFA_LOCAL contains the local address. */
477 if(l_entry->ifa_addr) {
478 l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
480 l_entry->ifa_addr = (struct sockaddr *)l_addr;
482 } else if (l_rta->rta_type == IFA_LOCAL) {
483 if(l_entry->ifa_addr) {
484 l_entry->ifa_dstaddr = l_entry->ifa_addr;
486 l_entry->ifa_addr = (struct sockaddr *)l_addr;
488 l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
490 l_addr += NLMSG_ALIGN(l_addrLen);
494 strncpy(l_name, (char*)l_rtaData, l_rtaDataSize);
495 l_name[l_rtaDataSize] = '\0';
496 l_entry->ifa_name = l_name;
503 if (l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6)) {
504 unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
505 unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
506 char l_mask[16] = {0};
508 for (i=0; i<(l_prefix/8); ++i) {
512 l_mask[i] = 0xff << (8 - (l_prefix % 8));
515 makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
516 l_entry->ifa_netmask = (struct sockaddr *)l_addr;
519 addToEnd(p_resultList, l_entry);
523 static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
526 pid_t l_pid = getpid();
527 for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) {
528 unsigned int l_nlsize = p_netlinkList->m_size;
529 struct nlmsghdr *l_hdr;
530 for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
532 if ((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) continue;
534 if (l_hdr->nlmsg_type == NLMSG_DONE) break;
536 if (l_hdr->nlmsg_type == RTM_NEWLINK) {
537 if(interpretLink(l_hdr, p_resultList) == -1) return -1;
545 static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
547 pid_t l_pid = getpid();
548 for (; p_netlinkList; p_netlinkList = p_netlinkList->m_next) {
549 unsigned int l_nlsize = p_netlinkList->m_size;
550 struct nlmsghdr *l_hdr;
551 for (l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) {
552 if ((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) continue;
554 if (l_hdr->nlmsg_type == NLMSG_DONE) break;
556 if (l_hdr->nlmsg_type == RTM_NEWADDR) {
557 if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1) return -1;
564 int getifaddrs(struct ifaddrs **ifap)
566 if (!ifap) return -1;
569 int l_socket = netlink_socket();
574 NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK);
575 if (!l_linkResults) {
580 NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR);
581 if (!l_addrResults) {
583 freeResultList(l_linkResults);
588 int l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);
589 if (l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1) {
593 freeResultList(l_linkResults);
594 freeResultList(l_addrResults);
599 void freeifaddrs(struct ifaddrs *ifa)
601 struct ifaddrs *l_cur;