diff options
author | Timo Teräs <timo.teras@iki.fi> | 2014-04-08 14:03:16 +0000 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2014-07-29 20:57:31 -0400 |
commit | 08e4052c43692a9306c5c638d70fba7f7ba08c52 (patch) | |
tree | c6163802d24ed751bb5942ff862e17217083807b /src/network/netlink.c | |
parent | cbb609b3db500e6aebe15762abebc4cb23563b8a (diff) | |
download | musl-08e4052c43692a9306c5c638d70fba7f7ba08c52.tar.gz |
reimplement if_nameindex and getifaddrs using netlink
the previous implementations had several deficiencies, the most severe
of which was the inability to report unconfigured interfaces or
interfaces without ipv4 addresses. among the options discussed for
fixing this, using netlink turned out to be the one with the least
cost and most additional advantages. other improvements include:
if_nameindex now avoids duplicates in the list it produces, but still
includes legacy-style interface aliases if any are in use.
getifaddrs now reports hardware addresses and includes the scope_id
for link-local ipv6 addresses in the resulting address.
Diffstat (limited to 'src/network/netlink.c')
-rw-r--r-- | src/network/netlink.c | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/src/network/netlink.c b/src/network/netlink.c new file mode 100644 index 00000000..94dba7f5 --- /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; +} |