summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nss-myhostname/netlink.c256
1 files changed, 125 insertions, 131 deletions
diff --git a/src/nss-myhostname/netlink.c b/src/nss-myhostname/netlink.c
index 53c3b501be..2329f00943 100644
--- a/src/nss-myhostname/netlink.c
+++ b/src/nss-myhostname/netlink.c
@@ -35,174 +35,168 @@
#include <stdlib.h>
#include "ifconf.h"
+#include "macro.h"
+#include "util.h"
-int ifconf_acquire_addresses(struct address **_list, unsigned *_n_list) {
+#define SEQ 4711
+static int read_reply(int fd, struct address **list, unsigned *n_list) {
+ ssize_t bytes;
+ struct cmsghdr *cmsg;
+ struct ucred *ucred;
+ struct nlmsghdr *p;
+ uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
struct {
struct nlmsghdr hdr;
- struct rtgenmsg gen;
- } req;
- struct rtgenmsg *gen;
- int fd, r, on = 1;
- uint32_t seq = 4711;
- struct address *list = NULL;
- unsigned n_list = 0;
-
- fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
- if (fd < 0)
+ struct ifaddrmsg ifaddrmsg;
+ uint8_t payload[16*1024];
+ } resp;
+ struct iovec iov = {
+ .iov_base = &resp,
+ .iov_len = sizeof(resp),
+ };
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = cred_buffer,
+ .msg_controllen = sizeof(cred_buffer),
+ .msg_flags = 0,
+ };
+
+ assert(fd >= 0);
+ assert(list);
+
+ bytes = recvmsg(fd, &msg, 0);
+ if (bytes < 0)
return -errno;
- if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
- r = -errno;
- goto finish;
- }
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS)
+ return -EIO;
- memset(&req, 0, sizeof(req));
- req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
- req.hdr.nlmsg_type = RTM_GETADDR;
- req.hdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP|NLM_F_ACK;
- req.hdr.nlmsg_seq = seq;
- req.hdr.nlmsg_pid = 0;
+ ucred = (struct ucred*) CMSG_DATA(cmsg);
+ if (ucred->uid != 0 || ucred->pid != 0)
+ return 0;
- gen = NLMSG_DATA(&req.hdr);
- gen->rtgen_family = AF_UNSPEC;
+ for (p = &resp.hdr; bytes > 0; p = NLMSG_NEXT(p, bytes)) {
+ struct ifaddrmsg *ifaddrmsg;
+ struct rtattr *a;
+ size_t l;
+ void *local = NULL, *address = NULL;
- if (send(fd, &req, req.hdr.nlmsg_len, 0) < 0) {
- r = -errno;
- goto finish;
- }
+ if (!NLMSG_OK(p, (size_t) bytes))
+ return -EIO;
- for (;;) {
- ssize_t bytes;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- struct ucred *ucred;
- struct iovec iov;
- struct nlmsghdr *p;
- uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
- struct {
- struct nlmsghdr hdr;
- struct ifaddrmsg ifaddrmsg;
- uint8_t payload[16*1024];
- } resp;
-
- memset(&iov, 0, sizeof(iov));
- iov.iov_base = &resp;
- iov.iov_len = sizeof(resp);
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = cred_buffer;
- msg.msg_controllen = sizeof(cred_buffer);
- msg.msg_flags = 0;
-
- bytes = recvmsg(fd, &msg, 0);
- if (bytes < 0) {
- r = -errno;
- goto finish;
- }
+ if (p->nlmsg_seq != SEQ)
+ continue;
+
+ if (p->nlmsg_type == NLMSG_DONE)
+ return 1;
+
+ if (p->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *nlmsgerr;
- cmsg = CMSG_FIRSTHDR(&msg);
- if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS) {
- r = -EIO;
- goto finish;
+ nlmsgerr = NLMSG_DATA(p);
+ return -nlmsgerr->error;
}
- ucred = (struct ucred*) CMSG_DATA(cmsg);
- if (ucred->uid != 0 || ucred->pid != 0)
+ if (p->nlmsg_type != RTM_NEWADDR)
continue;
- for (p = &resp.hdr; bytes > 0; p = NLMSG_NEXT(p, bytes)) {
- struct ifaddrmsg *ifaddrmsg;
- struct rtattr *a;
- size_t l;
- void *local = NULL, *address = NULL;
+ ifaddrmsg = NLMSG_DATA(p);
- if (!NLMSG_OK(p, (size_t) bytes)) {
- r = -EIO;
- goto finish;
- }
+ if (ifaddrmsg->ifa_family != AF_INET &&
+ ifaddrmsg->ifa_family != AF_INET6)
+ continue;
- if (p->nlmsg_seq != seq)
- continue;
+ if (ifaddrmsg->ifa_scope == RT_SCOPE_HOST ||
+ ifaddrmsg->ifa_scope == RT_SCOPE_NOWHERE)
+ continue;
- if (p->nlmsg_type == NLMSG_DONE) {
- r = 0;
- goto finish;
- }
+ if (ifaddrmsg->ifa_flags & IFA_F_DEPRECATED)
+ continue;
- if (p->nlmsg_type == NLMSG_ERROR) {
- struct nlmsgerr *nlmsgerr;
+ l = NLMSG_PAYLOAD(p, sizeof(struct ifaddrmsg));
+ a = IFA_RTA(ifaddrmsg);
- nlmsgerr = NLMSG_DATA(p);
- r = -nlmsgerr->error;
- goto finish;
- }
+ while (RTA_OK(a, l)) {
- if (p->nlmsg_type != RTM_NEWADDR)
- continue;
+ if (a->rta_type == IFA_ADDRESS)
+ address = RTA_DATA(a);
+ else if (a->rta_type == IFA_LOCAL)
+ local = RTA_DATA(a);
- ifaddrmsg = NLMSG_DATA(p);
+ a = RTA_NEXT(a, l);
+ }
- if (ifaddrmsg->ifa_family != AF_INET &&
- ifaddrmsg->ifa_family != AF_INET6)
- continue;
+ if (local)
+ address = local;
- if (ifaddrmsg->ifa_scope == RT_SCOPE_HOST ||
- ifaddrmsg->ifa_scope == RT_SCOPE_NOWHERE)
- continue;
+ if (!address)
+ continue;
- if (ifaddrmsg->ifa_flags & IFA_F_DEPRECATED)
- continue;
+ *list = realloc(*list, (*n_list+1) * sizeof(struct address));
+ if (!*list)
+ return -ENOMEM;
- l = NLMSG_PAYLOAD(p, sizeof(struct ifaddrmsg));
- a = IFA_RTA(ifaddrmsg);
+ (*list)[*n_list].family = ifaddrmsg->ifa_family;
+ (*list)[*n_list].scope = ifaddrmsg->ifa_scope;
+ memcpy((*list)[*n_list].address,
+ address, ifaddrmsg->ifa_family == AF_INET ? 4 : 16);
+ (*list)[*n_list].ifindex = ifaddrmsg->ifa_index;
- while (RTA_OK(a, l)) {
+ (*n_list)++;
+ }
- if (a->rta_type == IFA_ADDRESS)
- address = RTA_DATA(a);
- else if (a->rta_type == IFA_LOCAL)
- local = RTA_DATA(a);
+ return 0;
+}
- a = RTA_NEXT(a, l);
- }
- if (local)
- address = local;
+int ifconf_acquire_addresses(struct address **_list, unsigned *_n_list) {
- if (!address)
- continue;
+ struct {
+ struct nlmsghdr hdr;
+ struct rtgenmsg gen;
+ } req = { {
+ .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
+ .nlmsg_type = RTM_GETADDR,
+ .nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP|NLM_F_ACK,
+ .nlmsg_seq = SEQ,
+ .nlmsg_pid = 0,
+ }, {
+ .rtgen_family = AF_UNSPEC,
+ }
+ };
+ int r, on = 1;
+ struct address *list = NULL;
+ unsigned n_list = 0;
+ int _cleanup_close_ fd;
- list = realloc(list, (n_list+1) * sizeof(struct address));
- if (!list) {
- r = -ENOMEM;
- goto finish;
- }
+ fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd < 0)
+ return -errno;
- list[n_list].family = ifaddrmsg->ifa_family;
- list[n_list].scope = ifaddrmsg->ifa_scope;
- memcpy(list[n_list].address, address, ifaddrmsg->ifa_family == AF_INET ? 4 : 16);
- list[n_list].ifindex = ifaddrmsg->ifa_index;
+ if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0)
+ return -errno;
- n_list++;
- }
- }
+ if (send(fd, &req, req.hdr.nlmsg_len, 0) < 0)
+ return -errno;
-finish:
- close(fd);
+ while((r = read_reply(fd, &list, &n_list)) == 0)
+ ;
- if (r < 0)
+ if (r < 0) {
free(list);
- else {
- qsort(list, n_list, sizeof(struct address), address_compare);
-
- *_list = list;
- *_n_list = n_list;
+ return r;
}
- return r;
+ assert(n_list == 0 || list);
+ qsort(list, n_list, sizeof(struct address), address_compare);
+
+ *_list = list;
+ *_n_list = n_list;
+
+ return 0;
}