From: Timo Teras <timo.teras@iki.fi>
To: Timo Teras <timo.teras@iki.fi>
Cc: musl@lists.openwall.com, dalias@aerifal.cx, justin@specialbusservice.com
Subject: Re: if_nameindex/getifaddrs and dhcpcd issue
Date: Wed, 9 Apr 2014 17:02:22 +0300 [thread overview]
Message-ID: <20140409170222.786b7bee@vostro> (raw)
In-Reply-To: <20140408190807.7dc6b184@vostro>
On Tue, 8 Apr 2014 19:08:07 +0300
Timo Teras <timo.teras@iki.fi> wrote:
> > > I'm willing to write an alternative getifaddrs() and
> > > if_nameindex() implementations using netlink. Perhaps let's see
> > > how they end up?
> >
> > It wouldn't hurt; if they're not upstreamed they could still be used
> > as a separate library for the one application which needs this
> > functionality (dhcpcd).
>
> Yeah. I'll play with this and see what I come up with. I'll also
> delete the bad kernel #define's and try to do them a bit better - not
> sure how well I succeed that at, though.
Posting here the current version of my patch as requested.
While it has some corner cases still that need cleaning, it's a good
start. It implements the APIs, and is usable in read world.
From 4a82a84fb4fbfdae48f14bf86df0fd92086b7556 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
next prev parent reply other threads:[~2014-04-09 14:02 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-04-08 9:11 Natanael Copa
2014-04-08 10:07 ` Justin Cormack
2014-04-08 12:25 ` Timo Teras
2014-04-08 14:23 ` Natanael Copa
2014-04-08 15:45 ` Rich Felker
2014-04-08 16:08 ` Timo Teras
2014-04-08 16:19 ` Justin Cormack
2014-04-08 22:41 ` Rich Felker
2014-04-09 7:17 ` u-igbb
2014-04-09 22:20 ` Rich Felker
2014-04-09 22:32 ` Justin Cormack
2014-04-10 7:40 ` u-igbb
2014-04-10 7:52 ` Rich Felker
2014-04-09 14:02 ` Timo Teras [this message]
2014-04-10 0:55 ` Rich Felker
2014-04-09 7:55 ` Natanael Copa
2014-04-08 12:54 ` Szabolcs Nagy
2014-04-08 13:42 ` Rich Felker
2014-04-08 14:16 ` Justin Cormack
2014-04-08 15:38 ` Rich Felker
2014-04-09 7:13 ` Natanael Copa
2014-04-09 22:18 ` Rich Felker
2014-04-08 21:16 ` Natanael Copa
2014-04-08 21:30 ` Justin Cormack
2014-04-08 22:59 ` Rich Felker
2014-04-08 14:27 ` Natanael Copa
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20140409170222.786b7bee@vostro \
--to=timo.teras@iki.fi \
--cc=dalias@aerifal.cx \
--cc=justin@specialbusservice.com \
--cc=musl@lists.openwall.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/musl/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).