summaryrefslogtreecommitdiffstats
path: root/main/musl/1002-reimplement-if_nameindex-and-getifaddrs-using-netlin.patch
diff options
context:
space:
mode:
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.patch684
1 files changed, 0 insertions, 684 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
deleted file mode 100644
index 909b5b26c..000000000
--- a/main/musl/1002-reimplement-if_nameindex-and-getifaddrs-using-netlin.patch
+++ /dev/null
@@ -1,684 +0,0 @@
-From 2ab2413e746a5b0e6996eeb7bc10739207b0b560 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 | 52 ++++++++
- src/network/__netlink.h | 100 +++++++++++++++
- src/network/getifaddrs.c | 312 ++++++++++++++++++++++++---------------------
- src/network/if_nameindex.c | 130 +++++++++++++------
- 4 files changed, 409 insertions(+), 185 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..d02714c
---- /dev/null
-+++ b/src/network/__netlink.c
-@@ -0,0 +1,52 @@
-+#include <errno.h>
-+#include <string.h>
-+#include <syscall.h>
-+#include <sys/socket.h>
-+#include "__netlink.h"
-+
-+static int __netlink_enumerate(int fd, unsigned int seq, int type, int af,
-+ int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx)
-+{
-+ 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 __rtnetlink_enumerate(int link_af, int addr_af, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx)
-+{
-+ 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;
-+}
-diff --git a/src/network/__netlink.h b/src/network/__netlink.h
-new file mode 100644
-index 0000000..2476da1
---- /dev/null
-+++ b/src/network/__netlink.h
-@@ -0,0 +1,100 @@
-+#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_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_NEWLINK 16
-+#define RTM_GETLINK 18
-+#define RTM_NEWADDR 20
-+#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 */
-+
-+#define IFLA_ADDRESS 1
-+#define IFLA_BROADCAST 2
-+#define IFLA_IFNAME 3
-+#define IFLA_STATS 7
-+
-+/* 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;
-+};
-+
-+#define IFA_ADDRESS 1
-+#define IFA_LOCAL 2
-+#define IFA_LABEL 3
-+#define IFA_BROADCAST 4
-+
-+/* musl */
-+
-+#define NETLINK_ALIGN(len) (((len)+3) & ~3)
-+#define NLMSG_DATA(nlh) ((void*)((char*)(nlh)+sizeof(struct nlmsghdr)))
-+#define NLMSG_DATALEN(nlh) ((nlh)->nlmsg_len-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)+sizeof(struct rtattr)))
-+#define RTA_DATALEN(rta) ((rta)->rta_len-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)+sizeof(struct nlmsghdr)+NETLINK_ALIGN(len)))
-+#define NLMSG_RTAOK(rta,nlh) RTA_OK(rta,NLMSG_DATAEND(nlh))
-+
-+#define IFADDRS_HASH_SIZE 64
-+
-+int __rtnetlink_enumerate(int link_af, int addr_af, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx);
-diff --git a/src/network/getifaddrs.c b/src/network/getifaddrs.c
-index 5a94cc7..18fc710 100644
---- a/src/network/getifaddrs.c
-+++ b/src/network/getifaddrs.c
-@@ -1,181 +1,201 @@
--/* (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 <syscall.h>
-+#include <net/if.h>
-+#include <netinet/in.h>
-+#include "__netlink.h"
-
--typedef union {
-- struct sockaddr_in6 v6;
-+/* 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];
-+};
-+
-+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)
-+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 copy_addr(struct sockaddr **r, int af, union sockany *sa, void *addr, size_t addrlen, int ifindex)
- {
-- stor *head = (stor *) ifp;
-- while(head) {
-- void *p = head;
-- head = (stor *) head->next;
-- free(p);
-+ 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 ipv6netmask(unsigned prefix_length, struct sockaddr_in6 *sa)
-+static void gen_netmask(struct sockaddr **r, int af, union sockany *sa, int prefixlen)
- {
-- 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;
-- }
-+ 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 dealwithipv6(stor **list, stor** head)
-+static void copy_lladdr(struct sockaddr **r, union sockany *sa, void *addr, size_t addrlen, int ifindex, unsigned short hatype)
- {
-- 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;
-- }
-- }
-- out:
-- fclose(f);
-+ 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;
- }
-
--int getifaddrs(struct ifaddrs **ifap)
-+static int __handle(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, *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;
- }
-- 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;
-+
-+ 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;
- }
- }
-- 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;
-+ 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:
-+ copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index);
-+ 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. */
-+ copy_addr(&ifs->ifa.ifa_broadaddr, ifa->ifa_family, &ifs->ifu, 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;
- }
-- head->ifa.ifa_ifu.ifu_dstaddr = (struct sockaddr*) &head->dst;
- }
-+ 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);
- }
-- close(sock);
-- void* last = 0;
-- for(head = list; head; head=(stor*)head->next) last=head;
-- head = last;
-- dealwithipv6(&list, &head);
-- *ifap = (struct ifaddrs*) list;
- return 0;
-- err:
-- close(sock);
-- err2:
-- freeifaddrs((struct ifaddrs*) list);
-- return -1;
- }
-
-+int getifaddrs(struct ifaddrs **ifap)
-+{
-+ struct ifaddrs_ctx _ctx, *ctx = &_ctx;
-+ int r;
-+ memset(ctx, 0, sizeof *ctx);
-+ r = __rtnetlink_enumerate(AF_UNSPEC, AF_UNSPEC, __handle, ctx);
-+ 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..2ad7474 100644
---- a/src/network/if_nameindex.c
-+++ b/src/network/if_nameindex.c
-@@ -1,55 +1,107 @@
- #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"
-
--static void *do_nameindex(int s, size_t n)
--{
-- size_t i, len, k;
-- struct ifconf conf;
-- struct if_nameindex *idx;
-+struct ifnamemap {
-+ unsigned int hash_next;
-+ unsigned int index;
-+ unsigned char namelen;
-+ char name[IFNAMSIZ];
-+};
-
-- idx = malloc(n * (sizeof(struct if_nameindex)+sizeof(struct ifreq)));
-- if (!idx) return 0;
-+struct ifnameindexctx {
-+ unsigned int num, allocated, str_bytes;
-+ struct ifnamemap *list;
-+ unsigned int hash[IFADDRS_HASH_SIZE];
-+};
-
-- 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;
-+static int __handle(void *pctx, struct nlmsghdr *h)
-+{
-+ struct ifnameindexctx *ctx = pctx;
-+ struct ifnamemap *map;
-+ struct rtattr *rta;
-+ unsigned int i;
-+ int index, type, namelen, bucket;
-+
-+ if (h->nlmsg_type == RTM_NEWLINK) {
-+ struct ifinfomsg *ifi = NLMSG_DATA(h);
-+ index = ifi->ifi_index;
-+ type = IFLA_IFNAME;
-+ rta = NLMSG_RTA(h, sizeof(*ifi));
-+ } else {
-+ struct ifaddrmsg *ifa = NLMSG_DATA(h);
-+ index = ifa->ifa_index;
-+ type = IFA_LABEL;
-+ rta = NLMSG_RTA(h, sizeof(*ifa));
- }
-+ for (; NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) {
-+ if (rta->rta_type != type) continue;
-+
-+ namelen = RTA_DATALEN(rta) - 1;
-+ if (namelen > IFNAMSIZ) return 0;
-
-- 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;
-+ /* suppress duplicates */
-+ bucket = index % IFADDRS_HASH_SIZE;
-+ i = ctx->hash[bucket];
-+ while (i) {
-+ map = &ctx->list[i-1];
-+ if (map->index == index &&
-+ map->namelen == namelen &&
-+ memcmp(map->name, RTA_DATA(rta), namelen) == 0)
-+ return 0;
-+ i = map->hash_next;
- }
-- idx[i-k].if_index = conf.ifc_req[i].ifr_ifindex;
-- idx[i-k].if_name = conf.ifc_req[i].ifr_name;
-- }
-- idx[i-k].if_name = 0;
-- idx[i-k].if_index = 0;
-
-- return idx;
-+ if (ctx->num >= ctx->allocated) {
-+ size_t a = ctx->allocated ? ctx->allocated * 2 + 1 : 8;
-+ if (a > SIZE_MAX/sizeof *map) return -1;
-+ map = realloc(ctx->list, a * sizeof *map);
-+ if (!map) return -1;
-+ ctx->list = map;
-+ ctx->allocated = a;
-+ }
-+ map = &ctx->list[ctx->num];
-+ map->index = index;
-+ map->namelen = namelen;
-+ memcpy(map->name, RTA_DATA(rta), namelen);
-+ ctx->str_bytes += namelen + 1;
-+ ctx->num++;
-+ map->hash_next = ctx->hash[bucket];
-+ ctx->hash[bucket] = ctx->num;
-+ return 0;
-+ }
-+ 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 = 0, *d;
-+ struct ifnamemap *s;
-+ char *p;
-+ int i;
-+
-+ memset(ctx, 0, sizeof(*ctx));
-+ if (__rtnetlink_enumerate(AF_UNSPEC, AF_INET, __handle, ctx) < 0) goto err;
-+
-+ ifs = malloc(sizeof(struct if_nameindex[ctx->num+1]) + ctx->str_bytes);
-+ if (!ifs) goto err;
-+
-+ p = (char*)(ifs + ctx->num + 1);
-+ for (i = ctx->num, d = ifs, s = ctx->list; i; i--, s++, d++) {
-+ d->if_index = s->index;
-+ d->if_name = p;
-+ memcpy(p, s->name, s->namelen);
-+ p += s->namelen;
-+ *p++ = 0;
- }
-- errno = ENOBUFS;
-- return p;
-+ d->if_index = 0;
-+ d->if_name = 0;
-+err:
-+ free(ctx->list);
-+ return ifs;
- }
---
-2.0.2
-