2 Copyright (c) 2013, Kenneth MacKay
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright notice, this
8 list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright notice,
10 this list of conditions and the following disclaimer in the documentation
11 and/or other materials provided with the distribution.
13 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
17 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/socket.h>
34 #include <netpacket/packet.h>
35 #include <net/if_arp.h>
36 #include <netinet/in.h>
37 #include <linux/netlink.h>
38 #include <linux/rtnetlink.h>
39 #include <sys/ioctl.h>
41 typedef struct NetlinkList
43 struct NetlinkList *m_next;
44 struct nlmsghdr *m_data;
48 static int netlink_socket(void)
50 int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
56 struct sockaddr_nl l_addr;
57 memset(&l_addr, 0, sizeof(l_addr));
58 l_addr.nl_family = AF_NETLINK;
59 if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
68 static int netlink_send(int p_socket, int p_request)
72 struct nlmsghdr m_hdr;
73 struct rtgenmsg m_msg;
76 memset(&l_data, 0, sizeof(l_data));
78 l_data.m_hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
79 l_data.m_hdr.nlmsg_type = p_request;
80 l_data.m_hdr.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
81 l_data.m_hdr.nlmsg_pid = 0;
82 l_data.m_hdr.nlmsg_seq = p_socket;
83 l_data.m_msg.rtgen_family = AF_UNSPEC;
85 struct sockaddr_nl l_addr;
86 memset(&l_addr, 0, sizeof(l_addr));
87 l_addr.nl_family = AF_NETLINK;
88 return (sendto(p_socket, &l_data.m_hdr, l_data.m_hdr.nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
91 static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
94 struct iovec l_iov = { p_buffer, p_len };
95 struct sockaddr_nl l_addr;
99 l_msg.msg_name = (void *)&l_addr;
100 l_msg.msg_namelen = sizeof(l_addr);
101 l_msg.msg_iov = &l_iov;
102 l_msg.msg_iovlen = 1;
103 l_msg.msg_control = NULL;
104 l_msg.msg_controllen = 0;
106 int l_result = recvmsg(p_socket, &l_msg, 0);
117 if(l_msg.msg_flags & MSG_TRUNC)
118 { // buffer was too small
125 static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
127 size_t l_size = 4096;
128 void *l_buffer = NULL;
133 l_buffer = malloc(l_size);
134 if (l_buffer == NULL)
139 int l_read = netlink_recv(p_socket, l_buffer, l_size);
148 pid_t l_pid = getpid();
149 struct nlmsghdr *l_hdr;
150 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))
152 if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
157 if(l_hdr->nlmsg_type == NLMSG_DONE)
163 if(l_hdr->nlmsg_type == NLMSG_ERROR)
176 static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
178 NetlinkList *l_item = malloc(sizeof(NetlinkList));
184 l_item->m_next = NULL;
185 l_item->m_data = p_data;
186 l_item->m_size = p_size;
190 static void freeResultList(NetlinkList *p_list)
196 p_list = p_list->m_next;
202 static NetlinkList *getResultList(int p_socket, int p_request)
204 if(netlink_send(p_socket, p_request) < 0)
209 NetlinkList *l_list = NULL;
210 NetlinkList *l_end = NULL;
215 struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
218 freeResultList(l_list);
222 NetlinkList *l_item = newListItem(l_hdr, l_size);
225 freeResultList(l_list);
234 l_end->m_next = l_item;
241 static size_t maxSize(size_t a, size_t b)
243 return (a > b ? a : b);
246 static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
251 return sizeof(struct sockaddr_in);
253 return sizeof(struct sockaddr_in6);
255 return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
257 return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
261 static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
266 memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
269 memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
272 memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
273 ((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
276 memcpy(p_dest->sa_data, p_data, p_size);
279 p_dest->sa_family = p_family;
282 static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
286 *p_resultList = p_entry;
290 struct ifaddrs *l_cur = *p_resultList;
291 while(l_cur->ifa_next)
293 l_cur = l_cur->ifa_next;
295 l_cur->ifa_next = p_entry;
299 static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
301 struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
303 size_t l_nameSize = 0;
304 size_t l_addrSize = 0;
305 size_t l_dataSize = 0;
307 size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
308 struct rtattr *l_rta;
309 for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
311 //void *l_rtaData = RTA_DATA(l_rta);
312 size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
313 switch(l_rta->rta_type)
317 l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
320 l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
323 l_dataSize += NLMSG_ALIGN(l_rtaSize);
330 struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
335 memset(l_entry, 0, sizeof(struct ifaddrs));
336 l_entry->ifa_name = "";
338 char *l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
339 char *l_name = l_index + sizeof(int);
340 char *l_addr = l_name + l_nameSize;
341 char *l_data = l_addr + l_addrSize;
343 // save the interface index so we can look it up when handling the addresses.
344 memcpy(l_index, &l_info->ifi_index, sizeof(int));
346 l_entry->ifa_flags = l_info->ifi_flags;
348 l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
349 for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
351 void *l_rtaData = RTA_DATA(l_rta);
352 size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
353 switch(l_rta->rta_type)
358 size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
359 makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
360 ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
361 ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
362 if(l_rta->rta_type == IFLA_ADDRESS)
364 l_entry->ifa_addr = (struct sockaddr *)l_addr;
368 l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
370 l_addr += NLMSG_ALIGN(l_addrLen);
374 strncpy(l_name, l_rtaData, l_rtaDataSize);
375 l_name[l_rtaDataSize] = '\0';
376 l_entry->ifa_name = l_name;
379 memcpy(l_data, l_rtaData, l_rtaDataSize);
380 l_entry->ifa_data = l_data;
387 addToEnd(p_resultList, l_entry);
391 static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
394 struct ifaddrs *l_cur = *p_links;
395 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)
405 l_cur = l_cur->ifa_next;
411 static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
413 struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
414 struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
416 if(l_info->ifa_family == AF_PACKET)
421 size_t l_nameSize = 0;
422 size_t l_addrSize = 0;
424 int l_addedNetmask = 0;
426 size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
427 struct rtattr *l_rta;
428 for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
430 //void *l_rtaData = RTA_DATA(l_rta);
431 size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
433 switch(l_rta->rta_type)
437 if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
438 { // make room for netmask
439 l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
443 l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
446 l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
453 struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
458 memset(l_entry, 0, sizeof(struct ifaddrs));
459 l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");
461 char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
462 char *l_addr = l_name + l_nameSize;
464 l_entry->ifa_flags = l_info->ifa_flags;
467 l_entry->ifa_flags |= l_interface->ifa_flags;
470 l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
471 for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
473 void *l_rtaData = RTA_DATA(l_rta);
474 size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
475 switch(l_rta->rta_type)
481 size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
482 makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
483 if(l_info->ifa_family == AF_INET6)
485 if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
487 ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
491 if(l_rta->rta_type == IFA_ADDRESS)
492 { // apparently in a point-to-point network IFA_ADDRESS contains the dest address and IFA_LOCAL contains the local address
493 if(l_entry->ifa_addr)
495 l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
499 l_entry->ifa_addr = (struct sockaddr *)l_addr;
502 else if(l_rta->rta_type == IFA_LOCAL)
504 if(l_entry->ifa_addr)
506 l_entry->ifa_dstaddr = l_entry->ifa_addr;
508 l_entry->ifa_addr = (struct sockaddr *)l_addr;
512 l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
514 l_addr += NLMSG_ALIGN(l_addrLen);
518 strncpy(l_name, l_rtaData, l_rtaDataSize);
519 l_name[l_rtaDataSize] = '\0';
520 l_entry->ifa_name = l_name;
527 if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
529 unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
530 unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
531 char l_mask[16] = {0};
533 for(i=0; i<(l_prefix/8); ++i)
539 l_mask[i] = 0xff << (8 - (l_prefix % 8));
542 makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
543 l_entry->ifa_netmask = (struct sockaddr *)l_addr;
546 addToEnd(p_resultList, l_entry);
550 static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
553 pid_t l_pid = getpid();
554 for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
556 unsigned int l_nlsize = p_netlinkList->m_size;
557 struct nlmsghdr *l_hdr;
558 for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
560 if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
565 if(l_hdr->nlmsg_type == NLMSG_DONE)
570 if(l_hdr->nlmsg_type == RTM_NEWLINK)
572 if(interpretLink(l_hdr, p_resultList) == -1)
583 static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
585 pid_t l_pid = getpid();
586 for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
588 unsigned int l_nlsize = p_netlinkList->m_size;
589 struct nlmsghdr *l_hdr;
590 for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
592 if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
597 if(l_hdr->nlmsg_type == NLMSG_DONE)
602 if(l_hdr->nlmsg_type == RTM_NEWADDR)
604 if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
614 int getifaddrs(struct ifaddrs **ifap)
622 int l_socket = netlink_socket();
628 NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK);
635 NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR);
639 freeResultList(l_linkResults);
644 int l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);
645 if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1)
650 freeResultList(l_linkResults);
651 freeResultList(l_addrResults);
656 void freeifaddrs(struct ifaddrs *ifa)
658 struct ifaddrs *l_cur;
669 * Copyright (C) 2008 The Android Open Source Project
670 * All rights reserved.
672 * Redistribution and use in source and binary forms, with or without
673 * modification, are permitted provided that the following conditions
675 * * Redistributions of source code must retain the above copyright
676 * notice, this list of conditions and the following disclaimer.
677 * * Redistributions in binary form must reproduce the above copyright
678 * notice, this list of conditions and the following disclaimer in
679 * the documentation and/or other materials provided with the
682 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
683 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
684 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
685 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
686 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
687 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
688 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
689 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
690 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
691 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
692 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
696 //#include <string.h>
697 //#include <unistd.h>
698 //#include <linux/sockios.h>
699 //#include <net/if.h>
700 //#include <sys/socket.h>
701 //#include <sys/ioctl.h>
704 * Map an interface name into its corresponding index.
705 * Returns 0 on error, as 0 is not a valid index.
707 unsigned int if_nametoindex(const char *ifname)
713 memset(&ifr, 0, sizeof(struct ifreq));
714 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
715 ifr.ifr_name[IFNAMSIZ - 1] = 0;
718 if ((ctl_sock = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) {
719 if (ioctl(ctl_sock, SIOCGIFINDEX, &ifr) >= 0) {
720 index = ifr.ifr_ifindex;