aboutsummaryrefslogtreecommitdiffstats
path: root/main/musl/1002-reimplement-if_nameindex-and-getifaddrs-using-netlin.patch
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2014-04-09 13:25:31 +0300
committerTimo Teräs <timo.teras@iki.fi>2014-04-09 13:27:19 +0300
commita488eea97d8d9d53f9a361465b341221246377f5 (patch)
tree6fb83b9029119d329ea1ecdf4f1cbfbbb56280f0 /main/musl/1002-reimplement-if_nameindex-and-getifaddrs-using-netlin.patch
parent195f616f91ed4bd9733ef60e9945fdb292904162 (diff)
downloadaports-a488eea97d8d9d53f9a361465b341221246377f5.tar.bz2
aports-a488eea97d8d9d53f9a361465b341221246377f5.tar.xz
main/musl: reimplement getifaddrs() and if_nameindex() with netlink
this fixes issues with dhcpcd. cherry-pick also one more printf formatting fix from musl git.
Diffstat (limited to 'main/musl/1002-reimplement-if_nameindex-and-getifaddrs-using-netlin.patch')
-rw-r--r--main/musl/1002-reimplement-if_nameindex-and-getifaddrs-using-netlin.patch726
1 files changed, 726 insertions, 0 deletions
diff --git a/main/musl/1002-reimplement-if_nameindex-and-getifaddrs-using-netlin.patch b/main/musl/1002-reimplement-if_nameindex-and-getifaddrs-using-netlin.patch
new file mode 100644
index 0000000000..f740e20672
--- /dev/null
+++ b/main/musl/1002-reimplement-if_nameindex-and-getifaddrs-using-netlin.patch
@@ -0,0 +1,726 @@
+From 274b49ab1c7296fc13076b3ed8ca30050487a343 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi>
+Date: Tue, 8 Apr 2014 14:03:16 +0000
+Subject: [PATCH] reimplement if_nameindex and getifaddrs using netlink
+
+---
+ src/network/__netlink.c | 68 ++++++++++
+ src/network/__netlink.h | 143 ++++++++++++++++++++
+ src/network/getifaddrs.c | 322 ++++++++++++++++++++++++---------------------
+ src/network/if_nameindex.c | 105 +++++++++------
+ 4 files changed, 451 insertions(+), 187 deletions(-)
+ create mode 100644 src/network/__netlink.c
+ create mode 100644 src/network/__netlink.h
+
+diff --git a/src/network/__netlink.c b/src/network/__netlink.c
+new file mode 100644
+index 0000000..d0c9fab
+--- /dev/null
++++ b/src/network/__netlink.c
+@@ -0,0 +1,68 @@
++#define _GNU_SOURCE
++#include <errno.h>
++#include <string.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <sys/socket.h>
++#include <sys/param.h>
++#include "__netlink.h"
++
++struct __netlink_handle {
++ int fd;
++ unsigned int seq;
++ size_t bufsize;
++};
++
++struct __netlink_handle *__netlink_open(int type)
++{
++ struct __netlink_handle *nh;
++ int bufsize = getpagesize();
++ /* required buffer size is MIN(8192,pagesize)-sizeof(struct skb_shared_info)
++ * the estimate for skb_shared_info size is conservative, but gives enough
++ * space to fit struct __netlink_handle including malloc overhead in one page . */
++ if (bufsize > 8192) bufsize = 8192;
++ bufsize -= 128;
++ nh = malloc(sizeof(struct __netlink_handle) + bufsize);
++ if (!nh) return 0;
++ nh->fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, type);
++ if (nh->fd < 0) { free(nh); return 0; }
++ nh->seq = 1;
++ nh->bufsize = bufsize;
++ return nh;
++}
++
++void __netlink_close(struct __netlink_handle *nh)
++{
++ close(nh->fd);
++ free(nh);
++}
++
++int __netlink_enumerate(struct __netlink_handle *nh, int type, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx)
++{
++ struct nlmsghdr *h;
++ void *buf = (void*)(nh+1);
++ struct {
++ struct nlmsghdr nlh;
++ struct rtgenmsg g;
++ } *req = buf;
++ int r, ret = 0;
++
++ memset(req, 0, NETLINK_ALIGN(sizeof(*req)));
++ req->nlh.nlmsg_len = sizeof(*req);
++ req->nlh.nlmsg_type = type;
++ req->nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
++ req->nlh.nlmsg_seq = nh->seq++;
++ req->g.rtgen_family = AF_UNSPEC;
++ r = send(nh->fd, req, sizeof(*req), 0);
++ if (r < 0) return r;
++
++ while (1) {
++ r = recv(nh->fd, buf, nh->bufsize, MSG_DONTWAIT);
++ if (r <= 0) return -1;
++ for (h = (struct nlmsghdr*) buf; NLMSG_OK(h, (void*)((uint8_t*)buf+r)); h = NLMSG_NEXT(h)) {
++ if (h->nlmsg_type == NLMSG_DONE) return ret;
++ if (h->nlmsg_type == NLMSG_ERROR) return -1;
++ if (!ret) ret = cb(ctx, h);
++ }
++ }
++}
+diff --git a/src/network/__netlink.h b/src/network/__netlink.h
+new file mode 100644
+index 0000000..94728f3
+--- /dev/null
++++ b/src/network/__netlink.h
+@@ -0,0 +1,143 @@
++#include <stdint.h>
++
++/* linux/netlink.h */
++
++#define NETLINK_ROUTE 0
++
++struct nlmsghdr {
++ uint32_t nlmsg_len;
++ uint16_t nlmsg_type;
++ uint16_t nlmsg_flags;
++ uint32_t nlmsg_seq;
++ uint32_t nlmsg_pid;
++};
++
++#define NLM_F_REQUEST 1
++#define NLM_F_MULTI 2
++#define NLM_F_ACK 4
++#define NLM_F_ECHO 8
++#define NLM_F_DUMP_INTR 16
++
++#define NLM_F_ROOT 0x100
++#define NLM_F_MATCH 0x200
++#define NLM_F_ATOMIC 0x400
++#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH)
++
++#define NLMSG_NOOP 0x1
++#define NLMSG_ERROR 0x2
++#define NLMSG_DONE 0x3
++#define NLMSG_OVERRUN 0x4
++
++/* linux/rtnetlink.h */
++
++#define RTM_GETLINK 18
++#define RTM_GETADDR 22
++
++struct rtattr {
++ unsigned short rta_len;
++ unsigned short rta_type;
++};
++
++struct rtgenmsg {
++ unsigned char rtgen_family;
++};
++
++struct ifinfomsg {
++ unsigned char ifi_family;
++ unsigned char __ifi_pad;
++ unsigned short ifi_type;
++ int ifi_index;
++ unsigned ifi_flags;
++ unsigned ifi_change;
++};
++
++/* linux/if_link.h */
++
++enum {
++ IFLA_UNSPEC,
++ IFLA_ADDRESS,
++ IFLA_BROADCAST,
++ IFLA_IFNAME,
++ IFLA_MTU,
++ IFLA_LINK,
++ IFLA_QDISC,
++ IFLA_STATS,
++ IFLA_COST,
++ IFLA_PRIORITY,
++ IFLA_MASTER,
++ IFLA_WIRELESS,
++ IFLA_PROTINFO,
++ IFLA_TXQLEN,
++ IFLA_MAP,
++ IFLA_WEIGHT,
++ IFLA_OPERSTATE,
++ IFLA_LINKMODE,
++ IFLA_LINKINFO,
++ IFLA_NET_NS_PID,
++ IFLA_IFALIAS,
++ IFLA_NUM_VF,
++ IFLA_VFINFO_LIST,
++ IFLA_STATS64,
++ IFLA_VF_PORTS,
++ IFLA_PORT_SELF,
++ IFLA_AF_SPEC,
++ IFLA_GROUP,
++ IFLA_NET_NS_FD,
++ IFLA_EXT_MASK,
++ IFLA_PROMISCUITY,
++ IFLA_NUM_TX_QUEUES,
++ IFLA_NUM_RX_QUEUES,
++ IFLA_CARRIER,
++ IFLA_PHYS_PORT_ID,
++ __IFLA_MAX
++};
++
++/* linux/if_addr.h */
++
++struct ifaddrmsg {
++ uint8_t ifa_family;
++ uint8_t ifa_prefixlen;
++ uint8_t ifa_flags;
++ uint8_t ifa_scope;
++ uint32_t ifa_index;
++};
++
++enum {
++ IFA_UNSPEC,
++ IFA_ADDRESS,
++ IFA_LOCAL,
++ IFA_LABEL,
++ IFA_BROADCAST,
++ IFA_ANYCAST,
++ IFA_CACHEINFO,
++ IFA_MULTICAST,
++ __IFA_MAX
++};
++
++/* musl */
++
++#define NETLINK_ALIGN(len) (((len)+3) & ~3)
++#define NLMSG_DATA(nlh) ((void*)((char*)(nlh)+NETLINK_ALIGN(sizeof(struct nlmsghdr))))
++#define NLMSG_DATALEN(nlh) ((nlh)->nlmsg_len-NETLINK_ALIGN(sizeof(struct nlmsghdr)))
++#define NLMSG_DATAEND(nlh) ((char*)(nlh)+(nlh)->nlmsg_len)
++#define NLMSG_NEXT(nlh) (struct nlmsghdr*)((char*)(nlh)+NETLINK_ALIGN((nlh)->nlmsg_len))
++#define NLMSG_OK(nlh,end) (NLMSG_DATA(nlh) <= (end) && \
++ (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
++ (void*)NLMSG_NEXT(nlh) <= (end))
++
++#define RTA_DATA(rta) ((void*)((char*)(rta)+NETLINK_ALIGN(sizeof(struct rtattr))))
++#define RTA_DATALEN(rta) ((rta)->rta_len-NETLINK_ALIGN(sizeof(struct rtattr)))
++#define RTA_DATAEND(rta) ((char*)(rta)+(rta)->rta_len)
++#define RTA_NEXT(rta) (struct rtattr*)((char*)(rta)+NETLINK_ALIGN((rta)->rta_len))
++#define RTA_OK(rta,end) (RTA_DATA(rta) <= (void*)(end) && \
++ (rta)->rta_len >= sizeof(struct rtattr) && \
++ (void*)RTA_NEXT(rta) <= (void*)(end))
++
++#define NLMSG_RTA(nlh,len) ((void*)((char*)(nlh)+NETLINK_ALIGN(sizeof(struct nlmsghdr))+NETLINK_ALIGN(len)))
++#define NLMSG_RTAOK(rta,nlh) RTA_OK(rta,NLMSG_DATAEND(nlh))
++
++struct __netlink_handle;
++
++struct __netlink_handle *__netlink_open(int type);
++void __netlink_close(struct __netlink_handle *h);
++int __netlink_enumerate(struct __netlink_handle *h, int type, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx);
+diff --git a/src/network/getifaddrs.c b/src/network/getifaddrs.c
+index 5a94cc7..5b1ebe7 100644
+--- a/src/network/getifaddrs.c
++++ b/src/network/getifaddrs.c
+@@ -1,181 +1,209 @@
+-/* (C) 2013 John Spencer. released under musl's standard MIT license. */
+-#undef _GNU_SOURCE
+ #define _GNU_SOURCE
+-#include <ifaddrs.h>
+-#include <stdlib.h>
+-#include <net/if.h> /* IFNAMSIZ, ifreq, ifconf */
+-#include <stdio.h>
+-#include <ctype.h>
+-#include <string.h>
+ #include <errno.h>
+-#include <arpa/inet.h> /* inet_pton */
++#include <string.h>
++#include <stdlib.h>
+ #include <unistd.h>
+-#include <sys/ioctl.h>
+-#include <sys/socket.h>
++#include <ifaddrs.h>
++#include <net/if.h>
++#include "__netlink.h"
+
+-typedef union {
+- struct sockaddr_in6 v6;
++/* getifaddrs() uses PF_PACKET to relay hardware addresses.
++ * But Infiniband socket address length is longer, so use this hack
++ * (like glibc) to return it anyway. */
++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];
++};
++
++union sockany {
++ struct sockaddr sa;
++ struct sockaddr_ll_hack ll;
+ struct sockaddr_in v4;
+-} soa;
++ struct sockaddr_in6 v6;
++};
+
+-typedef struct ifaddrs_storage {
++struct ifaddrs_storage {
+ struct ifaddrs ifa;
+- soa addr;
+- soa netmask;
+- soa dst;
++ struct ifaddrs_storage *hash_next;
++ union sockany addr, netmask, ifu;
++ unsigned int index;
+ char name[IFNAMSIZ+1];
+-} stor;
+-#define next ifa.ifa_next
++};
+
+-static stor* list_add(stor** list, stor** head, char* ifname)
++#define IFADDRS_HASH_SIZE 64
++struct ifaddrs_ctx {
++ struct ifaddrs_storage *first;
++ struct ifaddrs_storage *last;
++ struct ifaddrs_storage *hash[IFADDRS_HASH_SIZE];
++};
++
++void freeifaddrs(struct ifaddrs *ifp)
+ {
+- stor* curr = calloc(1, sizeof(stor));
+- if(curr) {
+- strcpy(curr->name, ifname);
+- curr->ifa.ifa_name = curr->name;
+- if(*head) (*head)->next = (struct ifaddrs*) curr;
+- *head = curr;
+- if(!*list) *list = curr;
++ struct ifaddrs *n;
++ while (ifp) {
++ n = ifp->ifa_next;
++ free(ifp);
++ ifp = n;
+ }
+- return curr;
+ }
+
+-void freeifaddrs(struct ifaddrs *ifp)
++static void addifaddrs(struct ifaddrs_ctx *ctx, struct ifaddrs_storage *add)
+ {
+- stor *head = (stor *) ifp;
+- while(head) {
+- void *p = head;
+- head = (stor *) head->next;
+- free(p);
++ if (!add->ifa.ifa_name) {
++ free(add);
++ return;
+ }
++ if (!ctx->first) ctx->first = add;
++ if (ctx->last) ctx->last->ifa.ifa_next = &add->ifa;
++ ctx->last = add;
+ }
+
+-static void ipv6netmask(unsigned prefix_length, struct sockaddr_in6 *sa)
++static struct sockaddr* copy_lladdr(union sockany *sa, struct rtattr *rta, struct ifinfomsg *ifi)
+ {
+- unsigned char* hb = sa->sin6_addr.s6_addr;
+- unsigned onebytes = prefix_length / 8;
+- unsigned bits = prefix_length % 8;
+- unsigned nullbytes = 16 - onebytes;
+- memset(hb, -1, onebytes);
+- memset(hb+onebytes, 0, nullbytes);
+- if(bits) {
+- unsigned char x = -1;
+- x <<= 8 - bits;
+- hb[onebytes] = x;
++ if (RTA_DATALEN(rta) > sizeof(sa->ll.sll_addr)) return 0;
++ sa->ll.sll_family = AF_PACKET;
++ sa->ll.sll_ifindex = ifi->ifi_index;
++ sa->ll.sll_hatype = ifi->ifi_type;
++ sa->ll.sll_halen = RTA_DATALEN(rta);
++ memcpy(sa->ll.sll_addr, RTA_DATA(rta), RTA_DATALEN(rta));
++ return &sa->sa;
++}
++
++static uint8_t *sockany_addr(int af, union sockany *sa, int *len)
++{
++ switch (af) {
++ case AF_INET: *len = 4; return (uint8_t*) &sa->v4.sin_addr;
++ case AF_INET6: *len = 16; return (uint8_t*) &sa->v6.sin6_addr;
+ }
++ return 0;
+ }
+
+-static void dealwithipv6(stor **list, stor** head)
++static struct sockaddr* copy_addr(int af, union sockany *sa, struct rtattr *rta)
+ {
+- FILE* f = fopen("/proc/net/if_inet6", "rbe");
+- /* 00000000000000000000000000000001 01 80 10 80 lo
+- A B C D E F
+- all numbers in hex
+- A = addr B=netlink device#, C=prefix length,
+- D = scope value (ipv6.h) E = interface flags (rnetlink.h, addrconf.c)
+- F = if name */
+- char v6conv[32 + 7 + 1], *v6;
+- char *line, linebuf[512];
+- if(!f) return;
+- while((line = fgets(linebuf, sizeof linebuf, f))) {
+- v6 = v6conv;
+- size_t i = 0;
+- for(; i < 8; i++) {
+- memcpy(v6, line, 4);
+- v6+=4;
+- *v6++=':';
+- line+=4;
+- }
+- --v6; *v6 = 0;
+- line++;
+- unsigned b, c, d, e;
+- char name[IFNAMSIZ+1];
+- if(5 == sscanf(line, "%x %x %x %x %s", &b, &c, &d, &e, name)) {
+- struct sockaddr_in6 sa = {0};
+- if(1 == inet_pton(AF_INET6, v6conv, &sa.sin6_addr)) {
+- sa.sin6_family = AF_INET6;
+- stor* curr = list_add(list, head, name);
+- if(!curr) goto out;
+- curr->addr.v6 = sa;
+- curr->ifa.ifa_addr = (struct sockaddr*) &curr->addr;
+- ipv6netmask(c, &sa);
+- curr->netmask.v6 = sa;
+- curr->ifa.ifa_netmask = (struct sockaddr*) &curr->netmask;
+- /* find ipv4 struct with the same interface name to copy flags */
+- stor* scan = *list;
+- for(;scan && strcmp(name, scan->name);scan=(stor*)scan->next);
+- if(scan) curr->ifa.ifa_flags = scan->ifa.ifa_flags;
+- else curr->ifa.ifa_flags = 0;
+- } else errno = 0;
+- }
++ int len;
++ uint8_t *dst = sockany_addr(af, sa, &len);
++ if (!dst || RTA_DATALEN(rta) != len) return 0;
++ sa->sa.sa_family = af;
++ memcpy(dst, RTA_DATA(rta), len);
++ return &sa->sa;
++}
++
++static struct sockaddr *gen_netmask(int af, union sockany *sa, int prefixlen)
++{
++ int maxlen, i;
++ uint8_t *dst = sockany_addr(af, sa, &maxlen);
++ if (!dst) return 0;
++ sa->sa.sa_family = af;
++ if (prefixlen > 8*maxlen) prefixlen = 8*maxlen;
++ i = prefixlen / 8;
++ memset(dst, 0xff, i);
++ if (i<maxlen) {
++ dst[i++] = 0xff << (8 - (prefixlen % 8));
++ if (i<maxlen) memset(&dst[i+1], 0x00, maxlen-i);
+ }
+- out:
+- fclose(f);
++ return &sa->sa;
+ }
+
+-int getifaddrs(struct ifaddrs **ifap)
++static int __handle_link(void *pctx, struct nlmsghdr *h)
+ {
+- stor *list = 0, *head = 0;
+- struct if_nameindex* ii = if_nameindex();
+- if(!ii) return -1;
+- size_t i;
+- for(i = 0; ii[i].if_index || ii[i].if_name; i++) {
+- stor* curr = list_add(&list, &head, ii[i].if_name);
+- if(!curr) {
+- if_freenameindex(ii);
+- goto err2;
+- }
++ struct ifaddrs_ctx *ctx = pctx;
++ struct ifaddrs_storage *ifs;
++ struct ifinfomsg *ifi = NLMSG_DATA(h);
++ struct rtattr *rta;
++ int stats_len = 0;
++
++ 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;
+ }
+- if_freenameindex(ii);
+-
+- int sock = socket(PF_INET, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_IP);
+- if(sock == -1) goto err2;
+- struct ifreq reqs[32]; /* arbitrary chosen boundary */
+- struct ifconf conf = {.ifc_len = sizeof reqs, .ifc_req = reqs};
+- if(-1 == ioctl(sock, SIOCGIFCONF, &conf)) goto err;
+- size_t reqitems = conf.ifc_len / sizeof(struct ifreq);
+- for(head = list; head; head = (stor*)head->next) {
+- for(i = 0; i < reqitems; i++) {
+- // get SIOCGIFADDR of active interfaces.
+- if(!strcmp(reqs[i].ifr_name, head->name)) {
+- head->addr.v4 = *(struct sockaddr_in*)&reqs[i].ifr_addr;
+- head->ifa.ifa_addr = (struct sockaddr*) &head->addr;
+- break;
++
++ ifs = calloc(1, sizeof(struct ifaddrs_storage) + stats_len);
++ if (ifs == 0) return -1;
++
++ 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) <= IFNAMSIZ) {
++ strncpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta));
++ ifs->ifa.ifa_name = ifs->name;
+ }
++ break;
++ case IFLA_ADDRESS:
++ ifs->ifa.ifa_addr = copy_lladdr(&ifs->addr, rta, ifi);
++ break;
++ case IFLA_BROADCAST:
++ ifs->ifa.ifa_broadaddr = copy_lladdr(&ifs->ifu, rta, ifi);
++ break;
++ case IFLA_STATS:
++ ifs->ifa.ifa_data = (void*)(ifs+1);
++ memcpy(ifs->ifa.ifa_data, RTA_DATA(rta), RTA_DATALEN(rta));
++ break;
+ }
+- struct ifreq req;
+- snprintf(req.ifr_name, sizeof req.ifr_name, "%s", head->name);
+- if(-1 == ioctl(sock, SIOCGIFFLAGS, &req)) goto err;
+-
+- head->ifa.ifa_flags = req.ifr_flags;
+- if(head->ifa.ifa_addr) {
+- /* or'ing flags with IFF_LOWER_UP on active interfaces to mimic glibc */
+- head->ifa.ifa_flags |= IFF_LOWER_UP;
+- if(-1 == ioctl(sock, SIOCGIFNETMASK, &req)) goto err;
+- head->netmask.v4 = *(struct sockaddr_in*)&req.ifr_netmask;
+- head->ifa.ifa_netmask = (struct sockaddr*) &head->netmask;
+-
+- if(head->ifa.ifa_flags & IFF_POINTOPOINT) {
+- if(-1 == ioctl(sock, SIOCGIFDSTADDR, &req)) goto err;
+- head->dst.v4 = *(struct sockaddr_in*)&req.ifr_dstaddr;
+- } else {
+- if(-1 == ioctl(sock, SIOCGIFBRDADDR, &req)) goto err;
+- head->dst.v4 = *(struct sockaddr_in*)&req.ifr_broadaddr;
+- }
+- head->ifa.ifa_ifu.ifu_dstaddr = (struct sockaddr*) &head->dst;
++ }
++ if (ifs->ifa.ifa_name) {
++ ifs->hash_next = ctx->hash[ifs->index%IFADDRS_HASH_SIZE];
++ ctx->hash[ifs->index%IFADDRS_HASH_SIZE] = ifs;
++ }
++ addifaddrs(ctx, ifs);
++ return 0;
++}
++
++static int __handle_addr(void *pctx, struct nlmsghdr *h)
++{
++ struct ifaddrs_ctx *ctx = pctx;
++ struct ifaddrs_storage *ifs, *ifs0;
++ struct ifaddrmsg *ifa = NLMSG_DATA(h);
++ struct rtattr *rta;
++
++ ifs = calloc(1, sizeof(struct ifaddrs_storage));
++ if (ifs == 0) return -1;
++
++ 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->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:
++ ifs->ifa.ifa_addr = copy_addr(ifa->ifa_family, &ifs->addr, rta);
++ if (ifs->ifa.ifa_addr)
++ ifs->ifa.ifa_netmask = gen_netmask(ifa->ifa_family, &ifs->netmask, ifa->ifa_prefixlen);
++ break;
++ case IFA_BROADCAST:
++ /* For point-to-point links this is peer, but ifa_broadaddr
++ * and ifa_dstaddr are union, so this works for both. */
++ ifs->ifa.ifa_broadaddr = copy_addr(ifa->ifa_family, &ifs->ifu, rta);
++ break;
+ }
+ }
+- close(sock);
+- void* last = 0;
+- for(head = list; head; head=(stor*)head->next) last=head;
+- head = last;
+- dealwithipv6(&list, &head);
+- *ifap = (struct ifaddrs*) list;
++
++ addifaddrs(ctx, ifs);
+ return 0;
+- err:
+- close(sock);
+- err2:
+- freeifaddrs((struct ifaddrs*) list);
+- return -1;
+ }
+
++int getifaddrs(struct ifaddrs **ifap)
++{
++ struct ifaddrs_ctx _ctx, *ctx = &_ctx;
++ struct __netlink_handle *nh;
++ int r = 0;
++
++ nh = __netlink_open(NETLINK_ROUTE);
++ if (!nh) return -1;
++ memset(ctx, 0, sizeof(*ctx));
++ if (__netlink_enumerate(nh, RTM_GETLINK, __handle_link, ctx)) r = -1;
++ if (__netlink_enumerate(nh, RTM_GETADDR, __handle_addr, ctx)) r = -1;
++ __netlink_close(nh);
++ if (r == 0) *ifap = &ctx->first->ifa;
++ else freeifaddrs(&ctx->first->ifa);
++ return r;
++}
+diff --git a/src/network/if_nameindex.c b/src/network/if_nameindex.c
+index 53b80b2..d4e8b2d 100644
+--- a/src/network/if_nameindex.c
++++ b/src/network/if_nameindex.c
+@@ -1,55 +1,80 @@
+ #define _GNU_SOURCE
+ #include <net/if.h>
+-#include <stdlib.h>
+ #include <sys/socket.h>
+-#include <sys/ioctl.h>
+ #include <errno.h>
+-#include "syscall.h"
++#include <unistd.h>
++#include <stdlib.h>
++#include <string.h>
++#include "__netlink.h"
++
++struct ifnamemap {
++ unsigned int index;
++ unsigned char namelen;
++ char name[IFNAMSIZ];
++};
+
+-static void *do_nameindex(int s, size_t n)
++struct ifnameindexctx {
++ unsigned int num;
++ unsigned int str_bytes;
++ struct ifnamemap *list;
++};
++
++static int __handle_link(void *pctx, struct nlmsghdr *h)
+ {
+- size_t i, len, k;
+- struct ifconf conf;
+- struct if_nameindex *idx;
+-
+- idx = malloc(n * (sizeof(struct if_nameindex)+sizeof(struct ifreq)));
+- if (!idx) return 0;
+-
+- conf.ifc_buf = (void *)&idx[n];
+- conf.ifc_len = len = n * sizeof(struct ifreq);
+- if (ioctl(s, SIOCGIFCONF, &conf) < 0) {
+- free(idx);
+- return 0;
+- }
+- if (conf.ifc_len == len) {
+- free(idx);
+- return (void *)-1;
+- }
++ struct ifnameindexctx *ctx = pctx;
++ struct ifinfomsg *ifim = NLMSG_DATA(h);
++ struct rtattr *rta;
++ struct ifnamemap *e;
+
+- n = conf.ifc_len / sizeof(struct ifreq);
+- for (i=k=0; i<n; i++) {
+- if (ioctl(s, SIOCGIFINDEX, &conf.ifc_req[i]) < 0) {
+- k++;
+- continue;
+- }
+- idx[i-k].if_index = conf.ifc_req[i].ifr_ifindex;
+- idx[i-k].if_name = conf.ifc_req[i].ifr_name;
++ for (rta = NLMSG_RTA(h, sizeof(*ifim)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) {
++ if (rta->rta_type != IFLA_IFNAME) continue;
++ if (RTA_DATALEN(rta) > IFNAMSIZ) return -ENOBUFS;
++
++ ctx->num++;
++ ctx->str_bytes += RTA_DATALEN(rta) + 1;
++ e = realloc(ctx->list, sizeof(struct ifnamemap[ctx->num]));
++ if (e == 0) return -ENOMEM;
++ ctx->list = e;
++
++ e = &ctx->list[ctx->num-1];
++ e->index = ifim->ifi_index;
++ e->namelen = RTA_DATALEN(rta);
++ memcpy(e->name, RTA_DATA(rta), IFNAMSIZ);
+ }
+- idx[i-k].if_name = 0;
+- idx[i-k].if_index = 0;
+
+- return idx;
++ return 0;
+ }
+
+ struct if_nameindex *if_nameindex()
+ {
+- size_t n;
+- void *p = 0;
+- int s = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
+- if (s>=0) {
+- for (n=0; (p=do_nameindex(s, n)) == (void *)-1; n++);
+- __syscall(SYS_close, s);
++ struct ifnameindexctx _ctx, *ctx = &_ctx;
++ struct if_nameindex *ifs = NULL;
++ struct __netlink_handle *nh;
++ int r, i;
++ char *p;
++
++ nh = __netlink_open(NETLINK_ROUTE);
++ if (!nh) goto err;
++ memset(ctx, 0, sizeof(*ctx));
++ r = __netlink_enumerate(nh, RTM_GETLINK, __handle_link, ctx);
++ __netlink_close(nh);
++ if (r < 0) goto err;
++
++ ifs = malloc(sizeof(struct if_nameindex[ctx->num+1]) + ctx->str_bytes);
++ if (ifs == 0) goto err;
++
++ p = (char*)ifs + sizeof(struct if_nameindex[ctx->num+1]);
++ for (i = 0; i < ctx->num; i++) {
++ ifs[i].if_index = ctx->list[i].index;
++ ifs[i].if_name = p;
++ memcpy(p, ctx->list[i].name, ctx->list[i].namelen);
++ p += ctx->list[i].namelen;
++ *p++ = 0;
+ }
+- errno = ENOBUFS;
+- return p;
++ ifs[i].if_index = 0;
++ ifs[i].if_name = 0;
++err:
++ free(ctx->list);
++ if (ifs == NULL) errno = ENOBUFS;
++ return ifs;
+ }
+--
+1.9.1
+