[lxc-devel] [lxc/master] include: add safe getifaddrs() version

brauner on Github lxc-bot at linuxcontainers.org
Wed Aug 22 22:56:53 UTC 2018


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180822/22e6757e/attachment.bin>
-------------- next part --------------
From dae04d45f7fb931cdabc9f8cb2cb5097e376828d Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Wed, 22 Aug 2018 17:29:33 +0200
Subject: [PATCH 1/2] ifaddrs: add safe implementation of getifaddrs()

The old version was crazy. This replaces it with an internal version based on
musl.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/include/ifaddrs.c           | 881 +++++++++++---------------------
 src/include/ifaddrs.h           |  72 +--
 src/lxc/tools/include/ifaddrs.c | 599 ----------------------
 src/lxc/tools/include/ifaddrs.h |  54 --
 src/lxc/tools/lxc_device.c      |   2 +-
 5 files changed, 337 insertions(+), 1271 deletions(-)
 delete mode 100644 src/lxc/tools/include/ifaddrs.c
 delete mode 100644 src/lxc/tools/include/ifaddrs.h

diff --git a/src/include/ifaddrs.c b/src/include/ifaddrs.c
index 3fbe170d6..16af02587 100644
--- a/src/include/ifaddrs.c
+++ b/src/include/ifaddrs.c
@@ -1,608 +1,347 @@
-/*
-Copyright (c) 2013, Kenneth MacKay
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#include "ifaddrs.h"
-
-#include <string.h>
-#include <stdlib.h>
+#define _GNU_SOURCE
 #include <errno.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <net/if_arp.h>
-#include <netinet/in.h>
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <unistd.h>
 
-typedef struct NetlinkList
-{
-    struct NetlinkList *m_next;
-    struct nlmsghdr *m_data;
-    unsigned int m_size;
-} NetlinkList;
+#include "ifaddrs.h"
 
-static int netlink_socket(void)
-{
-    int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
-    if(l_socket < 0)
-    {
-        return -1;
-    }
-
-    struct sockaddr_nl l_addr;
-    memset(&l_addr, 0, sizeof(l_addr));
-    l_addr.nl_family = AF_NETLINK;
-    if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
-    {
-        close(l_socket);
-        return -1;
-    }
-
-    return l_socket;
-}
+#define IFADDRS_HASH_SIZE 64
 
-static int netlink_send(int p_socket, int p_request)
-{
-    char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
-    memset(l_buffer, 0, sizeof(l_buffer));
-    struct nlmsghdr *l_hdr = (struct nlmsghdr *)l_buffer;
-    struct rtgenmsg *l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr);
-
-    l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg));
-    l_hdr->nlmsg_type = p_request;
-    l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
-    l_hdr->nlmsg_pid = 0;
-    l_hdr->nlmsg_seq = p_socket;
-    l_msg->rtgen_family = AF_UNSPEC;
-
-    struct sockaddr_nl l_addr;
-    memset(&l_addr, 0, sizeof(l_addr));
-    l_addr.nl_family = AF_NETLINK;
-    return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
-}
+#define __NETLINK_ALIGN(len) (((len) + 3) & ~3)
 
-static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
-{
-    struct msghdr l_msg;
-    struct iovec l_iov = { p_buffer, p_len };
-    struct sockaddr_nl l_addr;
-
-    for(;;)
-    {
-        l_msg.msg_name = (void *)&l_addr;
-        l_msg.msg_namelen = sizeof(l_addr);
-        l_msg.msg_iov = &l_iov;
-        l_msg.msg_iovlen = 1;
-        l_msg.msg_control = NULL;
-        l_msg.msg_controllen = 0;
-        l_msg.msg_flags = 0;
-        int l_result = recvmsg(p_socket, &l_msg, 0);
-
-        if(l_result < 0)
-        {
-            if(errno == EINTR)
-            {
-                continue;
-            }
-            return -2;
-        }
-
-        if(l_msg.msg_flags & MSG_TRUNC)
-        { // buffer was too small
-            return -1;
-        }
-        return l_result;
-    }
-}
+#define __NLMSG_NEXT(nlh) \
+	(struct nlmsghdr *)((char *)(nlh) + __NETLINK_ALIGN((nlh)->nlmsg_len))
 
-static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
-{
-    size_t l_size = 4096;
-    void *l_buffer = NULL;
-
-    for(;;)
-    {
-        free(l_buffer);
-        l_buffer = malloc(l_size);
-
-        int l_read = netlink_recv(p_socket, l_buffer, l_size);
-        *p_size = l_read;
-        if(l_read == -2)
-        {
-            free(l_buffer);
-            return NULL;
-        }
-        if(l_read >= 0)
-        {
-            pid_t l_pid = getpid();
-            struct nlmsghdr *l_hdr;
-            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))
-            {
-                if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
-                {
-                    continue;
-                }
-
-                if(l_hdr->nlmsg_type == NLMSG_DONE)
-                {
-                    *p_done = 1;
-                    break;
-                }
-
-                if(l_hdr->nlmsg_type == NLMSG_ERROR)
-                {
-                    free(l_buffer);
-                    return NULL;
-                }
-            }
-            return l_buffer;
-        }
-
-        l_size *= 2;
-    }
-}
+#define __NLMSG_DATAEND(nlh) ((char *)(nlh) + (nlh)->nlmsg_len)
 
-static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
-{
-    NetlinkList *l_item = malloc(sizeof(NetlinkList));
-    l_item->m_next = NULL;
-    l_item->m_data = p_data;
-    l_item->m_size = p_size;
-    return l_item;
-}
+#define __NLMSG_RTA(nlh, len)                               \
+	((void *)((char *)(nlh) + sizeof(struct nlmsghdr) + \
+		  __NETLINK_ALIGN(len)))
 
-static void freeResultList(NetlinkList *p_list)
-{
-    NetlinkList *l_cur;
-    while(p_list)
-    {
-        l_cur = p_list;
-        p_list = p_list->m_next;
-        free(l_cur->m_data);
-        free(l_cur);
-    }
-}
+#define __RTA_DATALEN(rta) ((rta)->rta_len - sizeof(struct rtattr))
 
-static NetlinkList *getResultList(int p_socket, int p_request)
-{
-    if(netlink_send(p_socket, p_request) < 0)
-    {
-        return NULL;
-    }
-
-    NetlinkList *l_list = NULL;
-    NetlinkList *l_end = NULL;
-    int l_size;
-    int l_done = 0;
-    while(!l_done)
-    {
-        struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
-        if(!l_hdr)
-        { // error
-            freeResultList(l_list);
-            return NULL;
-        }
-
-        NetlinkList *l_item = newListItem(l_hdr, l_size);
-        if(!l_list)
-        {
-            l_list = l_item;
-        }
-        else
-        {
-            l_end->m_next = l_item;
-        }
-        l_end = l_item;
-    }
-    return l_list;
-}
+#define __RTA_NEXT(rta) \
+	(struct rtattr *)((char *)(rta) + __NETLINK_ALIGN((rta)->rta_len))
 
-static size_t maxSize(size_t a, size_t b)
-{
-    return (a > b ? a : b);
-}
+#define __RTA_OK(nlh, end) \
+	((char *)(end) - (char *)(rta) >= sizeof(struct rtattr))
 
-static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
-{
-    switch(p_family)
-    {
-        case AF_INET:
-            return sizeof(struct sockaddr_in);
-        case AF_INET6:
-            return sizeof(struct sockaddr_in6);
-        case AF_PACKET:
-            return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
-        default:
-            return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
-    }
-}
+#define __NLMSG_RTAOK(rta, nlh) __RTA_OK(rta, __NLMSG_DATAEND(nlh))
+
+#define __IN6_IS_ADDR_LINKLOCAL(a) \
+	((((uint8_t *)(a))[0]) == 0xfe && (((uint8_t *)(a))[1] & 0xc0) == 0x80)
+
+#define __IN6_IS_ADDR_MC_LINKLOCAL(a) \
+	(IN6_IS_ADDR_MULTICAST(a) && ((((uint8_t *)(a))[1] & 0xf) == 0x2))
+
+#define __RTA_DATA(rta) ((void *)((char *)(rta) + sizeof(struct rtattr)))
+
+/* getifaddrs() reports hardware addresses with PF_PACKET that implies
+ * struct sockaddr_ll.  But e.g. Infiniband socket address length is
+ * longer than sockaddr_ll.ssl_addr[8] can hold. Use this hack struct
+ * to extend ssl_addr - callers should be able to still use it. */
+struct sockaddr_ll_hack {
+	unsigned short sll_family, sll_protocol;
+	int sll_ifindex;
+	unsigned short sll_hatype;
+	unsigned char sll_pkttype, sll_halen;
+	unsigned char sll_addr[24];
+};
 
-static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
+union sockany {
+	struct sockaddr sa;
+	struct sockaddr_ll_hack ll;
+	struct sockaddr_in v4;
+	struct sockaddr_in6 v6;
+};
+
+struct ifaddrs_storage {
+	struct ifaddrs ifa;
+	struct ifaddrs_storage *hash_next;
+	union sockany addr, netmask, ifu;
+	unsigned int index;
+	char name[IFNAMSIZ + 1];
+};
+
+struct ifaddrs_ctx {
+	struct ifaddrs_storage *first;
+	struct ifaddrs_storage *last;
+	struct ifaddrs_storage *hash[IFADDRS_HASH_SIZE];
+};
+
+void freeifaddrs(struct ifaddrs *ifp)
 {
-    switch(p_family)
-    {
-        case AF_INET:
-            memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
-            break;
-        case AF_INET6:
-            memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
-            break;
-        case AF_PACKET:
-            memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
-            ((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
-            break;
-        default:
-            memcpy(p_dest->sa_data, p_data, p_size);
-            break;
-    }
-    p_dest->sa_family = p_family;
+	struct ifaddrs *n;
+	while (ifp) {
+		n = ifp->ifa_next;
+		free(ifp);
+		ifp = n;
+	}
 }
 
-static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
+static void copy_addr(struct sockaddr **r, int af, union sockany *sa,
+		      void *addr, size_t addrlen, int ifindex)
 {
-    if(!*p_resultList)
-    {
-        *p_resultList = p_entry;
-    }
-    else
-    {
-        struct ifaddrs *l_cur = *p_resultList;
-        while(l_cur->ifa_next)
-        {
-            l_cur = l_cur->ifa_next;
-        }
-        l_cur->ifa_next = p_entry;
-    }
+	uint8_t *dst;
+	int len;
+
+	switch (af) {
+	case AF_INET:
+		dst = (uint8_t *)&sa->v4.sin_addr;
+		len = 4;
+		break;
+	case AF_INET6:
+		dst = (uint8_t *)&sa->v6.sin6_addr;
+		len = 16;
+		if (__IN6_IS_ADDR_LINKLOCAL(addr) || __IN6_IS_ADDR_MC_LINKLOCAL(addr))
+			sa->v6.sin6_scope_id = ifindex;
+		break;
+	default:
+		return;
+	}
+	if (addrlen < len)
+		return;
+	sa->sa.sa_family = af;
+	memcpy(dst, addr, len);
+	*r = &sa->sa;
 }
 
-static void interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList)
+static void gen_netmask(struct sockaddr **r, int af, union sockany *sa,
+			int prefixlen)
 {
-    struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
-
-    size_t l_nameSize = 0;
-    size_t l_addrSize = 0;
-    size_t l_dataSize = 0;
-
-    size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
-    struct rtattr *l_rta;
-    for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
-    {
-        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
-        switch(l_rta->rta_type)
-        {
-            case IFLA_ADDRESS:
-            case IFLA_BROADCAST:
-                l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
-                break;
-            case IFLA_IFNAME:
-                l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
-                break;
-            case IFLA_STATS:
-                l_dataSize += NLMSG_ALIGN(l_rtaSize);
-                break;
-            default:
-                break;
-        }
-    }
-
-    struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize + l_dataSize);
-    memset(l_entry, 0, sizeof(struct ifaddrs));
-    l_entry->ifa_name = "";
-
-    char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
-    char *l_addr = l_name + l_nameSize;
-    char *l_data = l_addr + l_addrSize;
-
-    l_entry->ifa_flags = l_info->ifi_flags;
-
-    l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
-    for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
-    {
-        void *l_rtaData = RTA_DATA(l_rta);
-        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
-        switch(l_rta->rta_type)
-        {
-            case IFLA_ADDRESS:
-            case IFLA_BROADCAST:
-            {
-                size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
-                makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
-                ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
-                ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
-                if(l_rta->rta_type == IFLA_ADDRESS)
-                {
-                    l_entry->ifa_addr = (struct sockaddr *)l_addr;
-                }
-                else
-                {
-                    l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
-                }
-                l_addr += NLMSG_ALIGN(l_addrLen);
-                break;
-            }
-            case IFLA_IFNAME:
-                strncpy(l_name, l_rtaData, l_rtaDataSize);
-                l_name[l_rtaDataSize] = '\0';
-                l_entry->ifa_name = l_name;
-                break;
-            case IFLA_STATS:
-                memcpy(l_data, l_rtaData, l_rtaDataSize);
-                l_entry->ifa_data = l_data;
-                break;
-            default:
-                break;
-        }
-    }
-
-    addToEnd(p_resultList, l_entry);
-    p_links[l_info->ifi_index - 1] = l_entry;
+	uint8_t addr[16] = {0};
+	int i;
+
+	if (prefixlen > 8 * sizeof(addr))
+		prefixlen = 8 * sizeof(addr);
+	i = prefixlen / 8;
+	memset(addr, 0xff, i);
+	if (i < sizeof(addr))
+		addr[i++] = 0xff << (8 - (prefixlen % 8));
+	copy_addr(r, af, sa, addr, sizeof(addr), 0);
 }
 
-static void interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList)
+static void copy_lladdr(struct sockaddr **r, union sockany *sa, void *addr,
+			size_t addrlen, int ifindex, unsigned short hatype)
 {
-    struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
-
-    size_t l_nameSize = 0;
-    size_t l_addrSize = 0;
-
-    int l_addedNetmask = 0;
-
-    size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
-    struct rtattr *l_rta;
-    for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
-    {
-        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
-        if(l_info->ifa_family == AF_PACKET)
-        {
-            continue;
-        }
-
-        switch(l_rta->rta_type)
-        {
-            case IFA_ADDRESS:
-            case IFA_LOCAL:
-                if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
-                { // make room for netmask
-                    l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
-                    l_addedNetmask = 1;
-                }
-            case IFA_BROADCAST:
-                l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
-                break;
-            case IFA_LABEL:
-                l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
-                break;
-            default:
-                break;
-        }
-    }
-
-    struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
-    memset(l_entry, 0, sizeof(struct ifaddrs));
-    l_entry->ifa_name = p_links[l_info->ifa_index - 1]->ifa_name;
-
-    char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
-    char *l_addr = l_name + l_nameSize;
-
-    l_entry->ifa_flags = l_info->ifa_flags | p_links[l_info->ifa_index - 1]->ifa_flags;
-
-    l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
-    for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
-    {
-        void *l_rtaData = RTA_DATA(l_rta);
-        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
-        switch(l_rta->rta_type)
-        {
-            case IFA_ADDRESS:
-            case IFA_BROADCAST:
-            case IFA_LOCAL:
-            {
-                size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
-                makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
-                if(l_info->ifa_family == AF_INET6)
-                {
-                    if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
-                    {
-                        ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
-                    }
-                }
-
-                if(l_rta->rta_type == IFA_ADDRESS)
-                { // apparently in a point-to-point network IFA_ADDRESS contains the dest address and IFA_LOCAL contains the local address
-                    if(l_entry->ifa_addr)
-                    {
-                        l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
-                    }
-                    else
-                    {
-                        l_entry->ifa_addr = (struct sockaddr *)l_addr;
-                    }
-                }
-                else if(l_rta->rta_type == IFA_LOCAL)
-                {
-                    if(l_entry->ifa_addr)
-                    {
-                        l_entry->ifa_dstaddr = l_entry->ifa_addr;
-                    }
-                    l_entry->ifa_addr = (struct sockaddr *)l_addr;
-                }
-                else
-                {
-                    l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
-                }
-                l_addr += NLMSG_ALIGN(l_addrLen);
-                break;
-            }
-            case IFA_LABEL:
-                strncpy(l_name, l_rtaData, l_rtaDataSize);
-                l_name[l_rtaDataSize] = '\0';
-                l_entry->ifa_name = l_name;
-                break;
-            default:
-                break;
-        }
-    }
-
-    if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
-    {
-        unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
-        unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
-        char l_mask[16] = {0};
-        unsigned i;
-        for(i=0; i<(l_prefix/8); ++i)
-        {
-            l_mask[i] = 0xff;
-        }
-        if (l_prefix % 8) {
-            l_mask[i] = 0xff << (8 - (l_prefix % 8));
-        }
-
-        makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
-        l_entry->ifa_netmask = (struct sockaddr *)l_addr;
-    }
-
-    addToEnd(p_resultList, l_entry);
+	if (addrlen > sizeof(sa->ll.sll_addr))
+		return;
+	sa->ll.sll_family = AF_PACKET;
+	sa->ll.sll_ifindex = ifindex;
+	sa->ll.sll_hatype = hatype;
+	sa->ll.sll_halen = addrlen;
+	memcpy(sa->ll.sll_addr, addr, addrlen);
+	*r = &sa->sa;
 }
 
-static void interpret(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_links, struct ifaddrs **p_resultList)
+static int netlink_msg_to_ifaddr(void *pctx, struct nlmsghdr *h)
 {
-    pid_t l_pid = getpid();
-    for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
-    {
-        unsigned int l_nlsize = p_netlinkList->m_size;
-        struct nlmsghdr *l_hdr;
-        for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
-        {
-            if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
-            {
-                continue;
-            }
-
-            if(l_hdr->nlmsg_type == NLMSG_DONE)
-            {
-                break;
-            }
-
-            if(l_hdr->nlmsg_type == RTM_NEWLINK)
-            {
-                interpretLink(l_hdr, p_links, p_resultList);
-            }
-            else if(l_hdr->nlmsg_type == RTM_NEWADDR)
-            {
-                interpretAddr(l_hdr, p_links, p_resultList);
-            }
-        }
-    }
+	struct ifaddrs_ctx *ctx = pctx;
+	struct ifaddrs_storage *ifs, *ifs0;
+	struct ifinfomsg *ifi = NLMSG_DATA(h);
+	struct ifaddrmsg *ifa = NLMSG_DATA(h);
+	struct rtattr *rta;
+	int stats_len = 0;
+
+	if (h->nlmsg_type == RTM_NEWLINK) {
+		for (rta = __NLMSG_RTA(h, sizeof(*ifi)); __NLMSG_RTAOK(rta, h);
+		     rta = __RTA_NEXT(rta)) {
+			if (rta->rta_type != IFLA_STATS)
+				continue;
+			stats_len = __RTA_DATALEN(rta);
+			break;
+		}
+	} else {
+		for (ifs0 = ctx->hash[ifa->ifa_index % IFADDRS_HASH_SIZE]; ifs0;
+		     ifs0 = ifs0->hash_next)
+			if (ifs0->index == ifa->ifa_index)
+				break;
+		if (!ifs0)
+			return 0;
+	}
+
+	ifs = calloc(1, sizeof(struct ifaddrs_storage) + stats_len);
+	if (ifs == 0)
+		return -1;
+
+	if (h->nlmsg_type == RTM_NEWLINK) {
+		ifs->index = ifi->ifi_index;
+		ifs->ifa.ifa_flags = ifi->ifi_flags;
+
+		for (rta = __NLMSG_RTA(h, sizeof(*ifi)); __NLMSG_RTAOK(rta, h); rta = __RTA_NEXT(rta)) {
+			switch (rta->rta_type) {
+			case IFLA_IFNAME:
+				if (__RTA_DATALEN(rta) < sizeof(ifs->name)) {
+					memcpy(ifs->name, __RTA_DATA(rta),
+					       __RTA_DATALEN(rta));
+					ifs->ifa.ifa_name = ifs->name;
+				}
+				break;
+			case IFLA_ADDRESS:
+				copy_lladdr(&ifs->ifa.ifa_addr, &ifs->addr,
+					    __RTA_DATA(rta), __RTA_DATALEN(rta),
+					    ifi->ifi_index, ifi->ifi_type);
+				break;
+			case IFLA_BROADCAST:
+				copy_lladdr(&ifs->ifa.ifa_broadaddr, &ifs->ifu,
+					    __RTA_DATA(rta), __RTA_DATALEN(rta),
+					    ifi->ifi_index, ifi->ifi_type);
+				break;
+			case IFLA_STATS:
+				ifs->ifa.ifa_data = (void *)(ifs + 1);
+				memcpy(ifs->ifa.ifa_data, __RTA_DATA(rta),
+				       __RTA_DATALEN(rta));
+				break;
+			}
+		}
+		if (ifs->ifa.ifa_name) {
+			unsigned int bucket = ifs->index % IFADDRS_HASH_SIZE;
+			ifs->hash_next = ctx->hash[bucket];
+			ctx->hash[bucket] = ifs;
+		}
+	} else {
+		ifs->ifa.ifa_name = ifs0->ifa.ifa_name;
+		ifs->ifa.ifa_flags = ifs0->ifa.ifa_flags;
+		for (rta = __NLMSG_RTA(h, sizeof(*ifa)); __NLMSG_RTAOK(rta, h);
+		     rta = __RTA_NEXT(rta)) {
+			switch (rta->rta_type) {
+			case IFA_ADDRESS:
+				/* If ifa_addr is already set we, received an
+				 * IFA_LOCAL before so treat this as destination
+				 * address */
+				if (ifs->ifa.ifa_addr)
+					copy_addr(&ifs->ifa.ifa_dstaddr,
+						  ifa->ifa_family, &ifs->ifu,
+						  __RTA_DATA(rta),
+						  __RTA_DATALEN(rta),
+						  ifa->ifa_index);
+				else
+					copy_addr(&ifs->ifa.ifa_addr,
+						  ifa->ifa_family, &ifs->addr,
+						  __RTA_DATA(rta),
+						  __RTA_DATALEN(rta),
+						  ifa->ifa_index);
+				break;
+			case IFA_BROADCAST:
+				copy_addr(&ifs->ifa.ifa_broadaddr,
+					  ifa->ifa_family, &ifs->ifu,
+					  __RTA_DATA(rta), __RTA_DATALEN(rta),
+					  ifa->ifa_index);
+				break;
+			case IFA_LOCAL:
+				/* If ifa_addr is set and we get IFA_LOCAL,
+				 * assume we have a point-to-point network. Move
+				 * address to correct field. */
+				if (ifs->ifa.ifa_addr) {
+					ifs->ifu = ifs->addr;
+					ifs->ifa.ifa_dstaddr = &ifs->ifu.sa;
+					memset(&ifs->addr, 0, sizeof(ifs->addr));
+				}
+				copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family,
+					  &ifs->addr, __RTA_DATA(rta),
+					  __RTA_DATALEN(rta), ifa->ifa_index);
+				break;
+			case IFA_LABEL:
+				if (__RTA_DATALEN(rta) < sizeof(ifs->name)) {
+					memcpy(ifs->name, __RTA_DATA(rta),
+					       __RTA_DATALEN(rta));
+					ifs->ifa.ifa_name = ifs->name;
+				}
+				break;
+			}
+		}
+		if (ifs->ifa.ifa_addr)
+			gen_netmask(&ifs->ifa.ifa_netmask, ifa->ifa_family,
+				    &ifs->netmask, ifa->ifa_prefixlen);
+	}
+
+	if (ifs->ifa.ifa_name) {
+		if (!ctx->first)
+			ctx->first = ifs;
+		if (ctx->last)
+			ctx->last->ifa.ifa_next = &ifs->ifa;
+		ctx->last = ifs;
+	} else {
+		free(ifs);
+	}
+	return 0;
 }
 
-static unsigned countLinks(int p_socket, NetlinkList *p_netlinkList)
+static int __netlink_enumerate(int fd, unsigned int seq, int type, int af,
+			       int (*cb)(void *ctx, struct nlmsghdr *h),
+			       void *ctx)
 {
-    unsigned l_links = 0;
-    pid_t l_pid = getpid();
-    for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
-    {
-        unsigned int l_nlsize = p_netlinkList->m_size;
-        struct nlmsghdr *l_hdr;
-        for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
-        {
-            if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
-            {
-                continue;
-            }
-
-            if(l_hdr->nlmsg_type == NLMSG_DONE)
-            {
-                break;
-            }
-
-            if(l_hdr->nlmsg_type == RTM_NEWLINK)
-            {
-                ++l_links;
-            }
-        }
-    }
-
-    return l_links;
+	struct nlmsghdr *h;
+	union {
+		uint8_t buf[8192];
+		struct {
+			struct nlmsghdr nlh;
+			struct rtgenmsg g;
+		} req;
+		struct nlmsghdr reply;
+	} u;
+	int r, ret;
+
+	memset(&u.req, 0, sizeof(u.req));
+	u.req.nlh.nlmsg_len = sizeof(u.req);
+	u.req.nlh.nlmsg_type = type;
+	u.req.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
+	u.req.nlh.nlmsg_seq = seq;
+	u.req.g.rtgen_family = af;
+	r = send(fd, &u.req, sizeof(u.req), 0);
+	if (r < 0)
+		return r;
+
+	while (1) {
+		r = recv(fd, u.buf, sizeof(u.buf), MSG_DONTWAIT);
+		if (r <= 0)
+			return -1;
+		for (h = &u.reply; NLMSG_OK(h, (void *)&u.buf[r]);
+		     h = __NLMSG_NEXT(h)) {
+			if (h->nlmsg_type == NLMSG_DONE)
+				return 0;
+			if (h->nlmsg_type == NLMSG_ERROR)
+				return -1;
+			ret = cb(ctx, h);
+			if (ret)
+				return ret;
+		}
+	}
 }
 
-int getifaddrs(struct ifaddrs **ifap)
+static int __rtnetlink_enumerate(int link_af, int addr_af,
+				 int (*cb)(void *ctx, struct nlmsghdr *h),
+				 void *ctx)
 {
-    if(!ifap)
-    {
-        return -1;
-    }
-    *ifap = NULL;
-
-    int l_socket = netlink_socket();
-    if(l_socket < 0)
-    {
-        return -1;
-    }
-
-    NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK);
-    if(!l_linkResults)
-    {
-        close(l_socket);
-        return -1;
-    }
-
-    NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR);
-    if(!l_addrResults)
-    {
-        close(l_socket);
-        freeResultList(l_linkResults);
-        return -1;
-    }
-
-    unsigned l_numLinks = countLinks(l_socket, l_linkResults) + countLinks(l_socket, l_addrResults);
-    struct ifaddrs **l_links;
-    l_links = malloc(l_numLinks * sizeof(struct ifaddrs *));
-    if (!l_links)
-    {
-        close(l_socket);
-        freeResultList(l_linkResults);
-        return -1;
-    }
-
-    memset(l_links, 0, l_numLinks * sizeof(struct ifaddrs *));
-
-    interpret(l_socket, l_linkResults, l_links, ifap);
-    interpret(l_socket, l_addrResults, l_links, ifap);
-
-    freeResultList(l_linkResults);
-    freeResultList(l_addrResults);
-    free(l_links);
-    close(l_socket);
-    return 0;
+	int fd, r;
+
+	fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
+	if (fd < 0)
+		return -1;
+	r = __netlink_enumerate(fd, 1, RTM_GETLINK, link_af, cb, ctx);
+	if (!r)
+		r = __netlink_enumerate(fd, 2, RTM_GETADDR, addr_af, cb, ctx);
+	syscall(SYS_close, fd);
+	return r;
 }
 
-void freeifaddrs(struct ifaddrs *ifa)
+int getifaddrs(struct ifaddrs **ifap)
 {
-    struct ifaddrs *l_cur;
-    while(ifa)
-    {
-        l_cur = ifa;
-        ifa = ifa->ifa_next;
-        free(l_cur);
-    }
+	struct ifaddrs_ctx _ctx, *ctx = &_ctx;
+	int r;
+	memset(ctx, 0, sizeof *ctx);
+	r = __rtnetlink_enumerate(AF_UNSPEC, AF_UNSPEC, netlink_msg_to_ifaddr,
+				  ctx);
+	if (r == 0)
+		*ifap = &ctx->first->ifa;
+	else
+		freeifaddrs(&ctx->first->ifa);
+	return r;
 }
diff --git a/src/include/ifaddrs.h b/src/include/ifaddrs.h
index 9cd19fec1..4f1352d05 100644
--- a/src/include/ifaddrs.h
+++ b/src/include/ifaddrs.h
@@ -1,54 +1,34 @@
-/*
- * Copyright (c) 1995, 1999
- *	Berkeley Software Design, Inc.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
- */
+#ifndef _IFADDRS_H
+#define _IFADDRS_H
 
-#ifndef	_IFADDRS_H_
-#define	_IFADDRS_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <features.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
 
 struct ifaddrs {
-	struct ifaddrs  *ifa_next;
-	char		*ifa_name;
-	unsigned int	 ifa_flags;
-	struct sockaddr	*ifa_addr;
-	struct sockaddr	*ifa_netmask;
-	struct sockaddr	*ifa_dstaddr;
-	void		*ifa_data;
+	struct ifaddrs *ifa_next;
+	char *ifa_name;
+	unsigned ifa_flags;
+	struct sockaddr *ifa_addr;
+	struct sockaddr *ifa_netmask;
+	union {
+		struct sockaddr *ifu_broadaddr;
+		struct sockaddr *ifu_dstaddr;
+	} ifa_ifu;
+	void *ifa_data;
 };
+#define ifa_broadaddr ifa_ifu.ifu_broadaddr
+#define ifa_dstaddr ifa_ifu.ifu_dstaddr
 
-/*
- * This may have been defined in <net/if.h>.  Note that if <net/if.h> is
- * to be included it must be included before this header file.
- */
-#ifndef	ifa_broadaddr
-#define	ifa_broadaddr	ifa_dstaddr	/* broadcast address interface */
-#endif
+void freeifaddrs(struct ifaddrs *);
+int getifaddrs(struct ifaddrs **);
 
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-extern int getifaddrs(struct ifaddrs **ifap);
-extern void freeifaddrs(struct ifaddrs *ifa);
-__END_DECLS
+#ifdef __cplusplus
+}
+#endif
 
 #endif
diff --git a/src/lxc/tools/include/ifaddrs.c b/src/lxc/tools/include/ifaddrs.c
deleted file mode 100644
index 1f954dd7d..000000000
--- a/src/lxc/tools/include/ifaddrs.c
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
-Copyright (c) 2013, Kenneth MacKay
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#include "ifaddrs.h"
-
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <net/if_arp.h>
-#include <netinet/in.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-
-typedef struct NetlinkList
-{
-    struct NetlinkList *m_next;
-    struct nlmsghdr *m_data;
-    unsigned int m_size;
-} NetlinkList;
-
-static int netlink_socket(void)
-{
-    int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
-    if(l_socket < 0)
-    {
-        return -1;
-    }
-
-    struct sockaddr_nl l_addr;
-    memset(&l_addr, 0, sizeof(l_addr));
-    l_addr.nl_family = AF_NETLINK;
-    if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
-    {
-        close(l_socket);
-        return -1;
-    }
-
-    return l_socket;
-}
-
-static int netlink_send(int p_socket, int p_request)
-{
-    char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
-    memset(l_buffer, 0, sizeof(l_buffer));
-    struct nlmsghdr *l_hdr = (struct nlmsghdr *)l_buffer;
-    struct rtgenmsg *l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr);
-
-    l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg));
-    l_hdr->nlmsg_type = p_request;
-    l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
-    l_hdr->nlmsg_pid = 0;
-    l_hdr->nlmsg_seq = p_socket;
-    l_msg->rtgen_family = AF_UNSPEC;
-
-    struct sockaddr_nl l_addr;
-    memset(&l_addr, 0, sizeof(l_addr));
-    l_addr.nl_family = AF_NETLINK;
-    return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
-}
-
-static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
-{
-    struct msghdr l_msg;
-    struct iovec l_iov = { p_buffer, p_len };
-    struct sockaddr_nl l_addr;
-
-    for(;;)
-    {
-        l_msg.msg_name = (void *)&l_addr;
-        l_msg.msg_namelen = sizeof(l_addr);
-        l_msg.msg_iov = &l_iov;
-        l_msg.msg_iovlen = 1;
-        l_msg.msg_control = NULL;
-        l_msg.msg_controllen = 0;
-        l_msg.msg_flags = 0;
-        int l_result = recvmsg(p_socket, &l_msg, 0);
-
-        if(l_result < 0)
-        {
-            if(errno == EINTR)
-            {
-                continue;
-            }
-            return -2;
-        }
-
-        if(l_msg.msg_flags & MSG_TRUNC)
-        { // buffer was too small
-            return -1;
-        }
-        return l_result;
-    }
-}
-
-static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
-{
-    size_t l_size = 4096;
-    void *l_buffer = NULL;
-
-    for(;;)
-    {
-        free(l_buffer);
-        l_buffer = malloc(l_size);
-
-        int l_read = netlink_recv(p_socket, l_buffer, l_size);
-        *p_size = l_read;
-        if(l_read == -2)
-        {
-            free(l_buffer);
-            return NULL;
-        }
-        if(l_read >= 0)
-        {
-            pid_t l_pid = getpid();
-            struct nlmsghdr *l_hdr;
-            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))
-            {
-                if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
-                {
-                    continue;
-                }
-
-                if(l_hdr->nlmsg_type == NLMSG_DONE)
-                {
-                    *p_done = 1;
-                    break;
-                }
-
-                if(l_hdr->nlmsg_type == NLMSG_ERROR)
-                {
-                    free(l_buffer);
-                    return NULL;
-                }
-            }
-            return l_buffer;
-        }
-
-        l_size *= 2;
-    }
-}
-
-static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
-{
-    NetlinkList *l_item = malloc(sizeof(NetlinkList));
-    l_item->m_next = NULL;
-    l_item->m_data = p_data;
-    l_item->m_size = p_size;
-    return l_item;
-}
-
-static void freeResultList(NetlinkList *p_list)
-{
-    NetlinkList *l_cur;
-    while(p_list)
-    {
-        l_cur = p_list;
-        p_list = p_list->m_next;
-        free(l_cur->m_data);
-        free(l_cur);
-    }
-}
-
-static NetlinkList *getResultList(int p_socket, int p_request)
-{
-    if(netlink_send(p_socket, p_request) < 0)
-    {
-        return NULL;
-    }
-
-    NetlinkList *l_list = NULL;
-    NetlinkList *l_end = NULL;
-    int l_size;
-    int l_done = 0;
-    while(!l_done)
-    {
-        struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
-        if(!l_hdr)
-        { // error
-            freeResultList(l_list);
-            return NULL;
-        }
-
-        NetlinkList *l_item = newListItem(l_hdr, l_size);
-        if(!l_list)
-        {
-            l_list = l_item;
-        }
-        else
-        {
-            l_end->m_next = l_item;
-        }
-        l_end = l_item;
-    }
-    return l_list;
-}
-
-static size_t maxSize(size_t a, size_t b)
-{
-    return (a > b ? a : b);
-}
-
-static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
-{
-    switch(p_family)
-    {
-        case AF_INET:
-            return sizeof(struct sockaddr_in);
-        case AF_INET6:
-            return sizeof(struct sockaddr_in6);
-        case AF_PACKET:
-            return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
-        default:
-            return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
-    }
-}
-
-static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
-{
-    switch(p_family)
-    {
-        case AF_INET:
-            memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
-            break;
-        case AF_INET6:
-            memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
-            break;
-        case AF_PACKET:
-            memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
-            ((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
-            break;
-        default:
-            memcpy(p_dest->sa_data, p_data, p_size);
-            break;
-    }
-    p_dest->sa_family = p_family;
-}
-
-static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
-{
-    if(!*p_resultList)
-    {
-        *p_resultList = p_entry;
-    }
-    else
-    {
-        struct ifaddrs *l_cur = *p_resultList;
-        while(l_cur->ifa_next)
-        {
-            l_cur = l_cur->ifa_next;
-        }
-        l_cur->ifa_next = p_entry;
-    }
-}
-
-static void interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList)
-{
-    struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
-
-    size_t l_nameSize = 0;
-    size_t l_addrSize = 0;
-    size_t l_dataSize = 0;
-
-    size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
-    struct rtattr *l_rta;
-    for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
-    {
-        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
-        switch(l_rta->rta_type)
-        {
-            case IFLA_ADDRESS:
-            case IFLA_BROADCAST:
-                l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
-                break;
-            case IFLA_IFNAME:
-                l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
-                break;
-            case IFLA_STATS:
-                l_dataSize += NLMSG_ALIGN(l_rtaSize);
-                break;
-            default:
-                break;
-        }
-    }
-
-    struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize + l_dataSize);
-    memset(l_entry, 0, sizeof(struct ifaddrs));
-    l_entry->ifa_name = "";
-
-    char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
-    char *l_addr = l_name + l_nameSize;
-    char *l_data = l_addr + l_addrSize;
-
-    l_entry->ifa_flags = l_info->ifi_flags;
-
-    l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
-    for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
-    {
-        void *l_rtaData = RTA_DATA(l_rta);
-        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
-        switch(l_rta->rta_type)
-        {
-            case IFLA_ADDRESS:
-            case IFLA_BROADCAST:
-            {
-                size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
-                makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
-                ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
-                ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
-                if(l_rta->rta_type == IFLA_ADDRESS)
-                {
-                    l_entry->ifa_addr = (struct sockaddr *)l_addr;
-                }
-                else
-                {
-                    l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
-                }
-                l_addr += NLMSG_ALIGN(l_addrLen);
-                break;
-            }
-            case IFLA_IFNAME:
-                strncpy(l_name, l_rtaData, l_rtaDataSize);
-                l_name[l_rtaDataSize] = '\0';
-                l_entry->ifa_name = l_name;
-                break;
-            case IFLA_STATS:
-                memcpy(l_data, l_rtaData, l_rtaDataSize);
-                l_entry->ifa_data = l_data;
-                break;
-            default:
-                break;
-        }
-    }
-
-    addToEnd(p_resultList, l_entry);
-    p_links[l_info->ifi_index - 1] = l_entry;
-}
-
-static void interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList)
-{
-    struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
-
-    size_t l_nameSize = 0;
-    size_t l_addrSize = 0;
-
-    int l_addedNetmask = 0;
-
-    size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
-    struct rtattr *l_rta;
-    for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
-    {
-        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
-        if(l_info->ifa_family == AF_PACKET)
-        {
-            continue;
-        }
-
-        switch(l_rta->rta_type)
-        {
-            case IFA_ADDRESS:
-            case IFA_LOCAL:
-                if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
-                { // make room for netmask
-                    l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
-                    l_addedNetmask = 1;
-                }
-            case IFA_BROADCAST:
-                l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
-                break;
-            case IFA_LABEL:
-                l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
-                break;
-            default:
-                break;
-        }
-    }
-
-    struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
-    memset(l_entry, 0, sizeof(struct ifaddrs));
-    l_entry->ifa_name = p_links[l_info->ifa_index - 1]->ifa_name;
-
-    char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
-    char *l_addr = l_name + l_nameSize;
-
-    l_entry->ifa_flags = l_info->ifa_flags | p_links[l_info->ifa_index - 1]->ifa_flags;
-
-    l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
-    for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
-    {
-        void *l_rtaData = RTA_DATA(l_rta);
-        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
-        switch(l_rta->rta_type)
-        {
-            case IFA_ADDRESS:
-            case IFA_BROADCAST:
-            case IFA_LOCAL:
-            {
-                size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
-                makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
-                if(l_info->ifa_family == AF_INET6)
-                {
-                    if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
-                    {
-                        ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
-                    }
-                }
-
-                if(l_rta->rta_type == IFA_ADDRESS)
-                { // apparently in a point-to-point network IFA_ADDRESS contains the dest address and IFA_LOCAL contains the local address
-                    if(l_entry->ifa_addr)
-                    {
-                        l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
-                    }
-                    else
-                    {
-                        l_entry->ifa_addr = (struct sockaddr *)l_addr;
-                    }
-                }
-                else if(l_rta->rta_type == IFA_LOCAL)
-                {
-                    if(l_entry->ifa_addr)
-                    {
-                        l_entry->ifa_dstaddr = l_entry->ifa_addr;
-                    }
-                    l_entry->ifa_addr = (struct sockaddr *)l_addr;
-                }
-                else
-                {
-                    l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
-                }
-                l_addr += NLMSG_ALIGN(l_addrLen);
-                break;
-            }
-            case IFA_LABEL:
-                strncpy(l_name, l_rtaData, l_rtaDataSize);
-                l_name[l_rtaDataSize] = '\0';
-                l_entry->ifa_name = l_name;
-                break;
-            default:
-                break;
-        }
-    }
-
-    if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
-    {
-        unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
-        unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
-        char l_mask[16] = {0};
-        unsigned i;
-        for(i=0; i<(l_prefix/8); ++i)
-        {
-            l_mask[i] = 0xff;
-        }
-        if (l_prefix % 8) {
-            l_mask[i] = 0xff << (8 - (l_prefix % 8));
-        }
-
-        makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
-        l_entry->ifa_netmask = (struct sockaddr *)l_addr;
-    }
-
-    addToEnd(p_resultList, l_entry);
-}
-
-static void interpret(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_links, struct ifaddrs **p_resultList)
-{
-    pid_t l_pid = getpid();
-    for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
-    {
-        unsigned int l_nlsize = p_netlinkList->m_size;
-        struct nlmsghdr *l_hdr;
-        for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
-        {
-            if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
-            {
-                continue;
-            }
-
-            if(l_hdr->nlmsg_type == NLMSG_DONE)
-            {
-                break;
-            }
-
-            if(l_hdr->nlmsg_type == RTM_NEWLINK)
-            {
-                interpretLink(l_hdr, p_links, p_resultList);
-            }
-            else if(l_hdr->nlmsg_type == RTM_NEWADDR)
-            {
-                interpretAddr(l_hdr, p_links, p_resultList);
-            }
-        }
-    }
-}
-
-static unsigned countLinks(int p_socket, NetlinkList *p_netlinkList)
-{
-    unsigned l_links = 0;
-    pid_t l_pid = getpid();
-    for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
-    {
-        unsigned int l_nlsize = p_netlinkList->m_size;
-        struct nlmsghdr *l_hdr;
-        for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
-        {
-            if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
-            {
-                continue;
-            }
-
-            if(l_hdr->nlmsg_type == NLMSG_DONE)
-            {
-                break;
-            }
-
-            if(l_hdr->nlmsg_type == RTM_NEWLINK)
-            {
-                ++l_links;
-            }
-        }
-    }
-
-    return l_links;
-}
-
-int getifaddrs(struct ifaddrs **ifap)
-{
-    if(!ifap)
-    {
-        return -1;
-    }
-    *ifap = NULL;
-
-    int l_socket = netlink_socket();
-    if(l_socket < 0)
-    {
-        return -1;
-    }
-
-    NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK);
-    if(!l_linkResults)
-    {
-        close(l_socket);
-        return -1;
-    }
-
-    NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR);
-    if(!l_addrResults)
-    {
-        close(l_socket);
-        freeResultList(l_linkResults);
-        return -1;
-    }
-
-    unsigned l_numLinks = countLinks(l_socket, l_linkResults) + countLinks(l_socket, l_addrResults);
-    struct ifaddrs *l_links[l_numLinks];
-    memset(l_links, 0, l_numLinks * sizeof(struct ifaddrs *));
-
-    interpret(l_socket, l_linkResults, l_links, ifap);
-    interpret(l_socket, l_addrResults, l_links, ifap);
-
-    freeResultList(l_linkResults);
-    freeResultList(l_addrResults);
-    close(l_socket);
-    return 0;
-}
-
-void freeifaddrs(struct ifaddrs *ifa)
-{
-    struct ifaddrs *l_cur;
-    while(ifa)
-    {
-        l_cur = ifa;
-        ifa = ifa->ifa_next;
-        free(l_cur);
-    }
-}
diff --git a/src/lxc/tools/include/ifaddrs.h b/src/lxc/tools/include/ifaddrs.h
deleted file mode 100644
index 9cd19fec1..000000000
--- a/src/lxc/tools/include/ifaddrs.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 1995, 1999
- *	Berkeley Software Design, Inc.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
- */
-
-#ifndef	_IFADDRS_H_
-#define	_IFADDRS_H_
-
-struct ifaddrs {
-	struct ifaddrs  *ifa_next;
-	char		*ifa_name;
-	unsigned int	 ifa_flags;
-	struct sockaddr	*ifa_addr;
-	struct sockaddr	*ifa_netmask;
-	struct sockaddr	*ifa_dstaddr;
-	void		*ifa_data;
-};
-
-/*
- * This may have been defined in <net/if.h>.  Note that if <net/if.h> is
- * to be included it must be included before this header file.
- */
-#ifndef	ifa_broadaddr
-#define	ifa_broadaddr	ifa_dstaddr	/* broadcast address interface */
-#endif
-
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-extern int getifaddrs(struct ifaddrs **ifap);
-extern void freeifaddrs(struct ifaddrs *ifa);
-__END_DECLS
-
-#endif
diff --git a/src/lxc/tools/lxc_device.c b/src/lxc/tools/lxc_device.c
index a854a2ea3..e2f576d71 100644
--- a/src/lxc/tools/lxc_device.c
+++ b/src/lxc/tools/lxc_device.c
@@ -36,7 +36,7 @@
 #if HAVE_IFADDRS_H
 #include <ifaddrs.h>
 #else
-#include "include/ifaddrs.h"
+#include "../include/ifaddrs.h"
 #endif
 
 lxc_log_define(lxc_device, lxc);

From 83a356913735b8d4346028b748f8229067a92261 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Wed, 22 Aug 2018 20:28:52 +0200
Subject: [PATCH 2/2] Makefile: conditionalize ifaddrs.h inclusion

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 configure.ac        | 7 ++++++-
 src/lxc/Makefile.am | 7 +++++--
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/configure.ac b/configure.ac
index b2b2f71c9..0139a746b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -611,7 +611,12 @@ AC_CHECK_DECLS([PR_SET_NO_NEW_PRIVS], [], [], [#include <sys/prctl.h>])
 AC_CHECK_DECLS([PR_GET_NO_NEW_PRIVS], [], [], [#include <sys/prctl.h>])
 
 # Check for some headers
-AC_CHECK_HEADERS([sys/signalfd.h pty.h ifaddrs.h sys/memfd.h sys/personality.h utmpx.h sys/timerfd.h sys/resource.h])
+AC_CHECK_HEADERS([sys/signalfd.h pty.h sys/memfd.h sys/personality.h utmpx.h sys/timerfd.h sys/resource.h])
+
+AC_CHECK_HEADER([ifaddrs.h],
+	AM_CONDITIONAL(HAVE_IFADDRS_H, true)
+	AC_DEFINE(HAVE_IFADDRS_H, 1, [Have ifaddrs.h]),
+	AM_CONDITIONAL(HAVE_IFADDRS_H, false))
 
 # lookup major()/minor()/makedev()
 AC_HEADER_MAJOR
diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index 68311a90d..0322a0d65 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -132,9 +132,12 @@ liblxc_la_SOURCES = af_unix.c af_unix.h \
 		    version.h \
 		    $(LSM_SOURCES)
 
+if !HAVE_IFADDRS_H
+liblxc_la_SOURCES += ../include/ifaddrs.c ../include/ifaddrs.h
+endif
+
 if IS_BIONIC
-liblxc_la_SOURCES += ../include/ifaddrs.c ../include/ifaddrs.h \
-		     ../include/lxcmntent.c ../include/lxcmntent.h \
+liblxc_la_SOURCES += ../include/lxcmntent.c ../include/lxcmntent.h \
 		     ../include/openpty.c ../include/openpty.h
 endif
 


More information about the lxc-devel mailing list