Blame src/unix/android-ifaddrs.c

Packit Service 7c31a4
/*
Packit Service 7c31a4
Copyright (c) 2013, Kenneth MacKay
Packit Service 7c31a4
Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement #289016)
Packit Service 7c31a4
All rights reserved.
Packit Service 7c31a4
Packit Service 7c31a4
Redistribution and use in source and binary forms, with or without modification,
Packit Service 7c31a4
are permitted provided that the following conditions are met:
Packit Service 7c31a4
 * Redistributions of source code must retain the above copyright notice, this
Packit Service 7c31a4
   list of conditions and the following disclaimer.
Packit Service 7c31a4
 * Redistributions in binary form must reproduce the above copyright notice,
Packit Service 7c31a4
   this list of conditions and the following disclaimer in the documentation
Packit Service 7c31a4
   and/or other materials provided with the distribution.
Packit Service 7c31a4
Packit Service 7c31a4
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
Packit Service 7c31a4
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
Packit Service 7c31a4
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
Packit Service 7c31a4
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
Packit Service 7c31a4
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
Packit Service 7c31a4
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
Packit Service 7c31a4
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
Packit Service 7c31a4
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit Service 7c31a4
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
Packit Service 7c31a4
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit Service 7c31a4
*/
Packit Service 7c31a4
Packit Service 7c31a4
#include "uv/android-ifaddrs.h"
Packit Service 7c31a4
#include "uv-common.h"
Packit Service 7c31a4
Packit Service 7c31a4
#include <string.h>
Packit Service 7c31a4
#include <stdlib.h>
Packit Service 7c31a4
#include <errno.h>
Packit Service 7c31a4
#include <unistd.h>
Packit Service 7c31a4
#include <sys/socket.h>
Packit Service 7c31a4
#include <net/if_arp.h>
Packit Service 7c31a4
#include <netinet/in.h>
Packit Service 7c31a4
#include <linux/netlink.h>
Packit Service 7c31a4
#include <linux/rtnetlink.h>
Packit Service 7c31a4
#include <linux/if_packet.h>
Packit Service 7c31a4
Packit Service 7c31a4
typedef struct NetlinkList
Packit Service 7c31a4
{
Packit Service 7c31a4
    struct NetlinkList *m_next;
Packit Service 7c31a4
    struct nlmsghdr *m_data;
Packit Service 7c31a4
    unsigned int m_size;
Packit Service 7c31a4
} NetlinkList;
Packit Service 7c31a4
Packit Service 7c31a4
static int netlink_socket(pid_t *p_pid)
Packit Service 7c31a4
{
Packit Service 7c31a4
    struct sockaddr_nl l_addr;
Packit Service 7c31a4
    socklen_t l_len;
Packit Service 7c31a4
Packit Service 7c31a4
    int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
Packit Service 7c31a4
    if(l_socket < 0)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        return -1;
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    memset(&l_addr, 0, sizeof(l_addr));
Packit Service 7c31a4
    l_addr.nl_family = AF_NETLINK;
Packit Service 7c31a4
    if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        close(l_socket);
Packit Service 7c31a4
        return -1;
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    l_len = sizeof(l_addr);
Packit Service 7c31a4
    if(getsockname(l_socket, (struct sockaddr *)&l_addr, &l_len) < 0)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        close(l_socket);
Packit Service 7c31a4
        return -1;
Packit Service 7c31a4
    }
Packit Service 7c31a4
    *p_pid = l_addr.nl_pid;
Packit Service 7c31a4
Packit Service 7c31a4
    return l_socket;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static int netlink_send(int p_socket, int p_request)
Packit Service 7c31a4
{
Packit Service 7c31a4
    char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
Packit Service 7c31a4
Packit Service 7c31a4
    struct nlmsghdr *l_hdr;
Packit Service 7c31a4
    struct rtgenmsg *l_msg;
Packit Service 7c31a4
    struct sockaddr_nl l_addr;
Packit Service 7c31a4
Packit Service 7c31a4
    memset(l_buffer, 0, sizeof(l_buffer));
Packit Service 7c31a4
Packit Service 7c31a4
    l_hdr = (struct nlmsghdr *)l_buffer;
Packit Service 7c31a4
    l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr);
Packit Service 7c31a4
Packit Service 7c31a4
    l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg));
Packit Service 7c31a4
    l_hdr->nlmsg_type = p_request;
Packit Service 7c31a4
    l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
Packit Service 7c31a4
    l_hdr->nlmsg_pid = 0;
Packit Service 7c31a4
    l_hdr->nlmsg_seq = p_socket;
Packit Service 7c31a4
    l_msg->rtgen_family = AF_UNSPEC;
Packit Service 7c31a4
Packit Service 7c31a4
    memset(&l_addr, 0, sizeof(l_addr));
Packit Service 7c31a4
    l_addr.nl_family = AF_NETLINK;
Packit Service 7c31a4
    return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
Packit Service 7c31a4
{
Packit Service 7c31a4
    struct sockaddr_nl l_addr;
Packit Service 7c31a4
    struct msghdr l_msg;
Packit Service 7c31a4
Packit Service 7c31a4
    struct iovec l_iov;
Packit Service 7c31a4
    l_iov.iov_base = p_buffer;
Packit Service 7c31a4
    l_iov.iov_len = p_len;
Packit Service 7c31a4
Packit Service 7c31a4
    for(;;)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        int l_result;
Packit Service 7c31a4
        l_msg.msg_name = (void *)&l_addr;
Packit Service 7c31a4
        l_msg.msg_namelen = sizeof(l_addr);
Packit Service 7c31a4
        l_msg.msg_iov = &l_iov;
Packit Service 7c31a4
        l_msg.msg_iovlen = 1;
Packit Service 7c31a4
        l_msg.msg_control = NULL;
Packit Service 7c31a4
        l_msg.msg_controllen = 0;
Packit Service 7c31a4
        l_msg.msg_flags = 0;
Packit Service 7c31a4
        l_result = recvmsg(p_socket, &l_msg, 0);
Packit Service 7c31a4
Packit Service 7c31a4
        if(l_result < 0)
Packit Service 7c31a4
        {
Packit Service 7c31a4
            if(errno == EINTR)
Packit Service 7c31a4
            {
Packit Service 7c31a4
                continue;
Packit Service 7c31a4
            }
Packit Service 7c31a4
            return -2;
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
        /* Buffer was too small */
Packit Service 7c31a4
        if(l_msg.msg_flags & MSG_TRUNC)
Packit Service 7c31a4
        {
Packit Service 7c31a4
            return -1;
Packit Service 7c31a4
        }
Packit Service 7c31a4
        return l_result;
Packit Service 7c31a4
    }
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static struct nlmsghdr *getNetlinkResponse(int p_socket, pid_t p_pid, int *p_size, int *p_done)
Packit Service 7c31a4
{
Packit Service 7c31a4
    size_t l_size = 4096;
Packit Service 7c31a4
    void *l_buffer = NULL;
Packit Service 7c31a4
Packit Service 7c31a4
    for(;;)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        int l_read;
Packit Service 7c31a4
Packit Service 7c31a4
        uv__free(l_buffer);
Packit Service 7c31a4
        l_buffer = uv__malloc(l_size);
Packit Service 7c31a4
        if (l_buffer == NULL)
Packit Service 7c31a4
        {
Packit Service 7c31a4
            return NULL;
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
        l_read = netlink_recv(p_socket, l_buffer, l_size);
Packit Service 7c31a4
        *p_size = l_read;
Packit Service 7c31a4
        if(l_read == -2)
Packit Service 7c31a4
        {
Packit Service 7c31a4
            uv__free(l_buffer);
Packit Service 7c31a4
            return NULL;
Packit Service 7c31a4
        }
Packit Service 7c31a4
        if(l_read >= 0)
Packit Service 7c31a4
        {
Packit Service 7c31a4
            struct nlmsghdr *l_hdr;
Packit Service 7c31a4
            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))
Packit Service 7c31a4
            {
Packit Service 7c31a4
                if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
Packit Service 7c31a4
                {
Packit Service 7c31a4
                    continue;
Packit Service 7c31a4
                }
Packit Service 7c31a4
Packit Service 7c31a4
                if(l_hdr->nlmsg_type == NLMSG_DONE)
Packit Service 7c31a4
                {
Packit Service 7c31a4
                    *p_done = 1;
Packit Service 7c31a4
                    break;
Packit Service 7c31a4
                }
Packit Service 7c31a4
Packit Service 7c31a4
                if(l_hdr->nlmsg_type == NLMSG_ERROR)
Packit Service 7c31a4
                {
Packit Service 7c31a4
                    uv__free(l_buffer);
Packit Service 7c31a4
                    return NULL;
Packit Service 7c31a4
                }
Packit Service 7c31a4
            }
Packit Service 7c31a4
            return l_buffer;
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
        l_size *= 2;
Packit Service 7c31a4
    }
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
Packit Service 7c31a4
{
Packit Service 7c31a4
    NetlinkList *l_item = uv__malloc(sizeof(NetlinkList));
Packit Service 7c31a4
    if (l_item == NULL)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        return NULL;
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    l_item->m_next = NULL;
Packit Service 7c31a4
    l_item->m_data = p_data;
Packit Service 7c31a4
    l_item->m_size = p_size;
Packit Service 7c31a4
    return l_item;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static void freeResultList(NetlinkList *p_list)
Packit Service 7c31a4
{
Packit Service 7c31a4
    NetlinkList *l_cur;
Packit Service 7c31a4
    while(p_list)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        l_cur = p_list;
Packit Service 7c31a4
        p_list = p_list->m_next;
Packit Service 7c31a4
        uv__free(l_cur->m_data);
Packit Service 7c31a4
        uv__free(l_cur);
Packit Service 7c31a4
    }
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static NetlinkList *getResultList(int p_socket, int p_request, pid_t p_pid)
Packit Service 7c31a4
{
Packit Service 7c31a4
    int l_size;
Packit Service 7c31a4
    int l_done;
Packit Service 7c31a4
    NetlinkList *l_list;
Packit Service 7c31a4
    NetlinkList *l_end;
Packit Service 7c31a4
Packit Service 7c31a4
    if(netlink_send(p_socket, p_request) < 0)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        return NULL;
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    l_list = NULL;
Packit Service 7c31a4
    l_end = NULL;
Packit Service 7c31a4
Packit Service 7c31a4
    l_done = 0;
Packit Service 7c31a4
    while(!l_done)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        NetlinkList *l_item;
Packit Service 7c31a4
Packit Service 7c31a4
        struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, p_pid, &l_size, &l_done);
Packit Service 7c31a4
        /* Error */
Packit Service 7c31a4
        if(!l_hdr)
Packit Service 7c31a4
        {
Packit Service 7c31a4
            freeResultList(l_list);
Packit Service 7c31a4
            return NULL;
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
        l_item = newListItem(l_hdr, l_size);
Packit Service 7c31a4
        if (!l_item)
Packit Service 7c31a4
        {
Packit Service 7c31a4
            freeResultList(l_list);
Packit Service 7c31a4
            return NULL;
Packit Service 7c31a4
        }
Packit Service 7c31a4
        if(!l_list)
Packit Service 7c31a4
        {
Packit Service 7c31a4
            l_list = l_item;
Packit Service 7c31a4
        }
Packit Service 7c31a4
        else
Packit Service 7c31a4
        {
Packit Service 7c31a4
            l_end->m_next = l_item;
Packit Service 7c31a4
        }
Packit Service 7c31a4
        l_end = l_item;
Packit Service 7c31a4
    }
Packit Service 7c31a4
    return l_list;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static size_t maxSize(size_t a, size_t b)
Packit Service 7c31a4
{
Packit Service 7c31a4
    return (a > b ? a : b);
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
Packit Service 7c31a4
{
Packit Service 7c31a4
    switch(p_family)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        case AF_INET:
Packit Service 7c31a4
            return sizeof(struct sockaddr_in);
Packit Service 7c31a4
        case AF_INET6:
Packit Service 7c31a4
            return sizeof(struct sockaddr_in6);
Packit Service 7c31a4
        case AF_PACKET:
Packit Service 7c31a4
            return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
Packit Service 7c31a4
        default:
Packit Service 7c31a4
            return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
Packit Service 7c31a4
    }
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
Packit Service 7c31a4
{
Packit Service 7c31a4
    switch(p_family)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        case AF_INET:
Packit Service 7c31a4
            memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
Packit Service 7c31a4
            break;
Packit Service 7c31a4
        case AF_INET6:
Packit Service 7c31a4
            memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
Packit Service 7c31a4
            break;
Packit Service 7c31a4
        case AF_PACKET:
Packit Service 7c31a4
            memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
Packit Service 7c31a4
            ((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
Packit Service 7c31a4
            break;
Packit Service 7c31a4
        default:
Packit Service 7c31a4
            memcpy(p_dest->sa_data, p_data, p_size);
Packit Service 7c31a4
            break;
Packit Service 7c31a4
    }
Packit Service 7c31a4
    p_dest->sa_family = p_family;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
Packit Service 7c31a4
{
Packit Service 7c31a4
    if(!*p_resultList)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        *p_resultList = p_entry;
Packit Service 7c31a4
    }
Packit Service 7c31a4
    else
Packit Service 7c31a4
    {
Packit Service 7c31a4
        struct ifaddrs *l_cur = *p_resultList;
Packit Service 7c31a4
        while(l_cur->ifa_next)
Packit Service 7c31a4
        {
Packit Service 7c31a4
            l_cur = l_cur->ifa_next;
Packit Service 7c31a4
        }
Packit Service 7c31a4
        l_cur->ifa_next = p_entry;
Packit Service 7c31a4
    }
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
Packit Service 7c31a4
{
Packit Service 7c31a4
    struct ifaddrs *l_entry;
Packit Service 7c31a4
Packit Service 7c31a4
    char *l_index;
Packit Service 7c31a4
    char *l_name;
Packit Service 7c31a4
    char *l_addr;
Packit Service 7c31a4
    char *l_data;
Packit Service 7c31a4
Packit Service 7c31a4
    struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
Packit Service 7c31a4
Packit Service 7c31a4
    size_t l_nameSize = 0;
Packit Service 7c31a4
    size_t l_addrSize = 0;
Packit Service 7c31a4
    size_t l_dataSize = 0;
Packit Service 7c31a4
Packit Service 7c31a4
    size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
Packit Service 7c31a4
    struct rtattr *l_rta;
Packit Service 7c31a4
    for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
Packit Service 7c31a4
    {
Packit Service 7c31a4
        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
Packit Service 7c31a4
        switch(l_rta->rta_type)
Packit Service 7c31a4
        {
Packit Service 7c31a4
            case IFLA_ADDRESS:
Packit Service 7c31a4
            case IFLA_BROADCAST:
Packit Service 7c31a4
                l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
Packit Service 7c31a4
                break;
Packit Service 7c31a4
            case IFLA_IFNAME:
Packit Service 7c31a4
                l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
Packit Service 7c31a4
                break;
Packit Service 7c31a4
            case IFLA_STATS:
Packit Service 7c31a4
                l_dataSize += NLMSG_ALIGN(l_rtaSize);
Packit Service 7c31a4
                break;
Packit Service 7c31a4
            default:
Packit Service 7c31a4
                break;
Packit Service 7c31a4
        }
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    l_entry = uv__malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
Packit Service 7c31a4
    if (l_entry == NULL)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        return -1;
Packit Service 7c31a4
    }
Packit Service 7c31a4
    memset(l_entry, 0, sizeof(struct ifaddrs));
Packit Service 7c31a4
    l_entry->ifa_name = "";
Packit Service 7c31a4
Packit Service 7c31a4
    l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
Packit Service 7c31a4
    l_name = l_index + sizeof(int);
Packit Service 7c31a4
    l_addr = l_name + l_nameSize;
Packit Service 7c31a4
    l_data = l_addr + l_addrSize;
Packit Service 7c31a4
Packit Service 7c31a4
    /* Save the interface index so we can look it up when handling the
Packit Service 7c31a4
     * addresses.
Packit Service 7c31a4
     */
Packit Service 7c31a4
    memcpy(l_index, &l_info->ifi_index, sizeof(int));
Packit Service 7c31a4
Packit Service 7c31a4
    l_entry->ifa_flags = l_info->ifi_flags;
Packit Service 7c31a4
Packit Service 7c31a4
    l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
Packit Service 7c31a4
    for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
Packit Service 7c31a4
    {
Packit Service 7c31a4
        void *l_rtaData = RTA_DATA(l_rta);
Packit Service 7c31a4
        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
Packit Service 7c31a4
        switch(l_rta->rta_type)
Packit Service 7c31a4
        {
Packit Service 7c31a4
            case IFLA_ADDRESS:
Packit Service 7c31a4
            case IFLA_BROADCAST:
Packit Service 7c31a4
            {
Packit Service 7c31a4
                size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
Packit Service 7c31a4
                makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
Packit Service 7c31a4
                ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
Packit Service 7c31a4
                ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
Packit Service 7c31a4
                if(l_rta->rta_type == IFLA_ADDRESS)
Packit Service 7c31a4
                {
Packit Service 7c31a4
                    l_entry->ifa_addr = (struct sockaddr *)l_addr;
Packit Service 7c31a4
                }
Packit Service 7c31a4
                else
Packit Service 7c31a4
                {
Packit Service 7c31a4
                    l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
Packit Service 7c31a4
                }
Packit Service 7c31a4
                l_addr += NLMSG_ALIGN(l_addrLen);
Packit Service 7c31a4
                break;
Packit Service 7c31a4
            }
Packit Service 7c31a4
            case IFLA_IFNAME:
Packit Service 7c31a4
                strncpy(l_name, l_rtaData, l_rtaDataSize);
Packit Service 7c31a4
                l_name[l_rtaDataSize] = '\0';
Packit Service 7c31a4
                l_entry->ifa_name = l_name;
Packit Service 7c31a4
                break;
Packit Service 7c31a4
            case IFLA_STATS:
Packit Service 7c31a4
                memcpy(l_data, l_rtaData, l_rtaDataSize);
Packit Service 7c31a4
                l_entry->ifa_data = l_data;
Packit Service 7c31a4
                break;
Packit Service 7c31a4
            default:
Packit Service 7c31a4
                break;
Packit Service 7c31a4
        }
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    addToEnd(p_resultList, l_entry);
Packit Service 7c31a4
    return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
Packit Service 7c31a4
{
Packit Service 7c31a4
    int l_num = 0;
Packit Service 7c31a4
    struct ifaddrs *l_cur = *p_links;
Packit Service 7c31a4
    while(l_cur && l_num < p_numLinks)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
Packit Service 7c31a4
        int l_index;
Packit Service 7c31a4
        memcpy(&l_index, l_indexPtr, sizeof(int));
Packit Service 7c31a4
        if(l_index == p_index)
Packit Service 7c31a4
        {
Packit Service 7c31a4
            return l_cur;
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
        l_cur = l_cur->ifa_next;
Packit Service 7c31a4
        ++l_num;
Packit Service 7c31a4
    }
Packit Service 7c31a4
    return NULL;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
Packit Service 7c31a4
{
Packit Service 7c31a4
    struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
Packit Service 7c31a4
    struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
Packit Service 7c31a4
Packit Service 7c31a4
    size_t l_nameSize = 0;
Packit Service 7c31a4
    size_t l_addrSize = 0;
Packit Service 7c31a4
Packit Service 7c31a4
    int l_addedNetmask = 0;
Packit Service 7c31a4
Packit Service 7c31a4
    size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
Packit Service 7c31a4
    struct rtattr *l_rta;
Packit Service 7c31a4
    struct ifaddrs *l_entry;
Packit Service 7c31a4
Packit Service 7c31a4
    char *l_name;
Packit Service 7c31a4
    char *l_addr;
Packit Service 7c31a4
Packit Service 7c31a4
    for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
Packit Service 7c31a4
    {
Packit Service 7c31a4
        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
Packit Service 7c31a4
        if(l_info->ifa_family == AF_PACKET)
Packit Service 7c31a4
        {
Packit Service 7c31a4
            continue;
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
        switch(l_rta->rta_type)
Packit Service 7c31a4
        {
Packit Service 7c31a4
            case IFA_ADDRESS:
Packit Service 7c31a4
            case IFA_LOCAL:
Packit Service 7c31a4
                l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
Packit Service 7c31a4
                if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
Packit Service 7c31a4
                {
Packit Service 7c31a4
                    /* Make room for netmask */
Packit Service 7c31a4
                    l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
Packit Service 7c31a4
                    l_addedNetmask = 1;
Packit Service 7c31a4
                }
Packit Service 7c31a4
                break;
Packit Service 7c31a4
            case IFA_BROADCAST:
Packit Service 7c31a4
                l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
Packit Service 7c31a4
                break;
Packit Service 7c31a4
            case IFA_LABEL:
Packit Service 7c31a4
                l_nameSize += NLMSG_ALIGN(l_rtaDataSize + 1);
Packit Service 7c31a4
                break;
Packit Service 7c31a4
            default:
Packit Service 7c31a4
                break;
Packit Service 7c31a4
        }
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    l_entry = uv__malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
Packit Service 7c31a4
    if (l_entry == NULL)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        return -1;
Packit Service 7c31a4
    }
Packit Service 7c31a4
    memset(l_entry, 0, sizeof(struct ifaddrs));
Packit Service 7c31a4
    l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");
Packit Service 7c31a4
Packit Service 7c31a4
    l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
Packit Service 7c31a4
    l_addr = l_name + l_nameSize;
Packit Service 7c31a4
Packit Service 7c31a4
    l_entry->ifa_flags = l_info->ifa_flags;
Packit Service 7c31a4
    if(l_interface)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        l_entry->ifa_flags |= l_interface->ifa_flags;
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
Packit Service 7c31a4
    for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
Packit Service 7c31a4
    {
Packit Service 7c31a4
        void *l_rtaData = RTA_DATA(l_rta);
Packit Service 7c31a4
        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
Packit Service 7c31a4
        switch(l_rta->rta_type)
Packit Service 7c31a4
        {
Packit Service 7c31a4
            case IFA_ADDRESS:
Packit Service 7c31a4
            case IFA_BROADCAST:
Packit Service 7c31a4
            case IFA_LOCAL:
Packit Service 7c31a4
            {
Packit Service 7c31a4
                size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
Packit Service 7c31a4
                makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
Packit Service 7c31a4
                if(l_info->ifa_family == AF_INET6)
Packit Service 7c31a4
                {
Packit Service 7c31a4
                    if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
Packit Service 7c31a4
                    {
Packit Service 7c31a4
                        ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
Packit Service 7c31a4
                    }
Packit Service 7c31a4
                }
Packit Service 7c31a4
Packit Service 7c31a4
                /* Apparently in a point-to-point network IFA_ADDRESS contains
Packit Service 7c31a4
                 * the dest address and IFA_LOCAL contains the local address
Packit Service 7c31a4
                 */
Packit Service 7c31a4
                if(l_rta->rta_type == IFA_ADDRESS)
Packit Service 7c31a4
                {
Packit Service 7c31a4
                    if(l_entry->ifa_addr)
Packit Service 7c31a4
                    {
Packit Service 7c31a4
                        l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
Packit Service 7c31a4
                    }
Packit Service 7c31a4
                    else
Packit Service 7c31a4
                    {
Packit Service 7c31a4
                        l_entry->ifa_addr = (struct sockaddr *)l_addr;
Packit Service 7c31a4
                    }
Packit Service 7c31a4
                }
Packit Service 7c31a4
                else if(l_rta->rta_type == IFA_LOCAL)
Packit Service 7c31a4
                {
Packit Service 7c31a4
                    if(l_entry->ifa_addr)
Packit Service 7c31a4
                    {
Packit Service 7c31a4
                        l_entry->ifa_dstaddr = l_entry->ifa_addr;
Packit Service 7c31a4
                    }
Packit Service 7c31a4
                    l_entry->ifa_addr = (struct sockaddr *)l_addr;
Packit Service 7c31a4
                }
Packit Service 7c31a4
                else
Packit Service 7c31a4
                {
Packit Service 7c31a4
                    l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
Packit Service 7c31a4
                }
Packit Service 7c31a4
                l_addr += NLMSG_ALIGN(l_addrLen);
Packit Service 7c31a4
                break;
Packit Service 7c31a4
            }
Packit Service 7c31a4
            case IFA_LABEL:
Packit Service 7c31a4
                strncpy(l_name, l_rtaData, l_rtaDataSize);
Packit Service 7c31a4
                l_name[l_rtaDataSize] = '\0';
Packit Service 7c31a4
                l_entry->ifa_name = l_name;
Packit Service 7c31a4
                break;
Packit Service 7c31a4
            default:
Packit Service 7c31a4
                break;
Packit Service 7c31a4
        }
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
Packit Service 7c31a4
    {
Packit Service 7c31a4
        unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
Packit Service 7c31a4
        unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
Packit Service 7c31a4
        unsigned char l_mask[16] = {0};
Packit Service 7c31a4
        unsigned i;
Packit Service 7c31a4
        for(i=0; i<(l_prefix/8); ++i)
Packit Service 7c31a4
        {
Packit Service 7c31a4
            l_mask[i] = 0xff;
Packit Service 7c31a4
        }
Packit Service 7c31a4
        if(l_prefix % 8)
Packit Service 7c31a4
        {
Packit Service 7c31a4
            l_mask[i] = 0xff << (8 - (l_prefix % 8));
Packit Service 7c31a4
        }
Packit Service 7c31a4
Packit Service 7c31a4
        makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
Packit Service 7c31a4
        l_entry->ifa_netmask = (struct sockaddr *)l_addr;
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    addToEnd(p_resultList, l_entry);
Packit Service 7c31a4
    return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static int interpretLinks(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
Packit Service 7c31a4
{
Packit Service 7c31a4
Packit Service 7c31a4
    int l_numLinks = 0;
Packit Service 7c31a4
    for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        unsigned int l_nlsize = p_netlinkList->m_size;
Packit Service 7c31a4
        struct nlmsghdr *l_hdr;
Packit Service 7c31a4
        for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
Packit Service 7c31a4
        {
Packit Service 7c31a4
            if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
Packit Service 7c31a4
            {
Packit Service 7c31a4
                continue;
Packit Service 7c31a4
            }
Packit Service 7c31a4
Packit Service 7c31a4
            if(l_hdr->nlmsg_type == NLMSG_DONE)
Packit Service 7c31a4
            {
Packit Service 7c31a4
                break;
Packit Service 7c31a4
            }
Packit Service 7c31a4
Packit Service 7c31a4
            if(l_hdr->nlmsg_type == RTM_NEWLINK)
Packit Service 7c31a4
            {
Packit Service 7c31a4
                if(interpretLink(l_hdr, p_resultList) == -1)
Packit Service 7c31a4
                {
Packit Service 7c31a4
                    return -1;
Packit Service 7c31a4
                }
Packit Service 7c31a4
                ++l_numLinks;
Packit Service 7c31a4
            }
Packit Service 7c31a4
        }
Packit Service 7c31a4
    }
Packit Service 7c31a4
    return l_numLinks;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
static int interpretAddrs(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
Packit Service 7c31a4
{
Packit Service 7c31a4
    for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        unsigned int l_nlsize = p_netlinkList->m_size;
Packit Service 7c31a4
        struct nlmsghdr *l_hdr;
Packit Service 7c31a4
        for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
Packit Service 7c31a4
        {
Packit Service 7c31a4
            if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
Packit Service 7c31a4
            {
Packit Service 7c31a4
                continue;
Packit Service 7c31a4
            }
Packit Service 7c31a4
Packit Service 7c31a4
            if(l_hdr->nlmsg_type == NLMSG_DONE)
Packit Service 7c31a4
            {
Packit Service 7c31a4
                break;
Packit Service 7c31a4
            }
Packit Service 7c31a4
Packit Service 7c31a4
            if(l_hdr->nlmsg_type == RTM_NEWADDR)
Packit Service 7c31a4
            {
Packit Service 7c31a4
                if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
Packit Service 7c31a4
                {
Packit Service 7c31a4
                    return -1;
Packit Service 7c31a4
                }
Packit Service 7c31a4
            }
Packit Service 7c31a4
        }
Packit Service 7c31a4
    }
Packit Service 7c31a4
    return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
int getifaddrs(struct ifaddrs **ifap)
Packit Service 7c31a4
{
Packit Service 7c31a4
    int l_socket;
Packit Service 7c31a4
    int l_result;
Packit Service 7c31a4
    int l_numLinks;
Packit Service 7c31a4
    pid_t l_pid;
Packit Service 7c31a4
    NetlinkList *l_linkResults;
Packit Service 7c31a4
    NetlinkList *l_addrResults;
Packit Service 7c31a4
Packit Service 7c31a4
    if(!ifap)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        return -1;
Packit Service 7c31a4
    }
Packit Service 7c31a4
    *ifap = NULL;
Packit Service 7c31a4
Packit Service 7c31a4
    l_socket = netlink_socket(&l_pid);
Packit Service 7c31a4
    if(l_socket < 0)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        return -1;
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    l_linkResults = getResultList(l_socket, RTM_GETLINK, l_pid);
Packit Service 7c31a4
    if(!l_linkResults)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        close(l_socket);
Packit Service 7c31a4
        return -1;
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    l_addrResults = getResultList(l_socket, RTM_GETADDR, l_pid);
Packit Service 7c31a4
    if(!l_addrResults)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        close(l_socket);
Packit Service 7c31a4
        freeResultList(l_linkResults);
Packit Service 7c31a4
        return -1;
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    l_result = 0;
Packit Service 7c31a4
    l_numLinks = interpretLinks(l_socket, l_pid, l_linkResults, ifap);
Packit Service 7c31a4
    if(l_numLinks == -1 || interpretAddrs(l_socket, l_pid, l_addrResults, ifap, l_numLinks) == -1)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        l_result = -1;
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    freeResultList(l_linkResults);
Packit Service 7c31a4
    freeResultList(l_addrResults);
Packit Service 7c31a4
    close(l_socket);
Packit Service 7c31a4
    return l_result;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
void freeifaddrs(struct ifaddrs *ifa)
Packit Service 7c31a4
{
Packit Service 7c31a4
    struct ifaddrs *l_cur;
Packit Service 7c31a4
    while(ifa)
Packit Service 7c31a4
    {
Packit Service 7c31a4
        l_cur = ifa;
Packit Service 7c31a4
        ifa = ifa->ifa_next;
Packit Service 7c31a4
        uv__free(l_cur);
Packit Service 7c31a4
    }
Packit Service 7c31a4
}