diff options
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.patch | 684 |
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 - |