1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2008-2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/socket.h>
24 #include <asm/types.h>
26 #include <linux/netlink.h>
27 #include <linux/rtnetlink.h>
32 #include <arpa/inet.h>
43 static int read_reply(int fd, struct address **list, unsigned *n_list) {
48 uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
51 struct ifaddrmsg ifaddrmsg;
52 uint8_t payload[16*1024];
56 .iov_len = sizeof(resp),
63 .msg_control = cred_buffer,
64 .msg_controllen = sizeof(cred_buffer),
71 bytes = recvmsg(fd, &msg, 0);
75 cmsg = CMSG_FIRSTHDR(&msg);
76 if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS)
79 ucred = (struct ucred*) CMSG_DATA(cmsg);
80 if (ucred->uid != 0 || ucred->pid != 0)
83 for (p = &resp.hdr; bytes > 0; p = NLMSG_NEXT(p, bytes)) {
84 struct ifaddrmsg *ifaddrmsg;
87 void *local = NULL, *address = NULL;
89 if (!NLMSG_OK(p, (size_t) bytes))
92 if (p->nlmsg_seq != SEQ)
95 if (p->nlmsg_type == NLMSG_DONE)
98 if (p->nlmsg_type == NLMSG_ERROR) {
99 struct nlmsgerr *nlmsgerr;
101 nlmsgerr = NLMSG_DATA(p);
102 return -nlmsgerr->error;
105 if (p->nlmsg_type != RTM_NEWADDR)
108 ifaddrmsg = NLMSG_DATA(p);
110 if (ifaddrmsg->ifa_family != AF_INET &&
111 ifaddrmsg->ifa_family != AF_INET6)
114 if (ifaddrmsg->ifa_scope == RT_SCOPE_HOST ||
115 ifaddrmsg->ifa_scope == RT_SCOPE_NOWHERE)
118 if (ifaddrmsg->ifa_flags & IFA_F_DEPRECATED)
121 l = NLMSG_PAYLOAD(p, sizeof(struct ifaddrmsg));
122 a = IFA_RTA(ifaddrmsg);
124 while (RTA_OK(a, l)) {
126 if (a->rta_type == IFA_ADDRESS)
127 address = RTA_DATA(a);
128 else if (a->rta_type == IFA_LOCAL)
140 *list = realloc(*list, (*n_list+1) * sizeof(struct address));
144 (*list)[*n_list].family = ifaddrmsg->ifa_family;
145 (*list)[*n_list].scope = ifaddrmsg->ifa_scope;
146 memcpy((*list)[*n_list].address,
147 address, ifaddrmsg->ifa_family == AF_INET ? 4 : 16);
148 (*list)[*n_list].ifindex = ifaddrmsg->ifa_index;
157 int ifconf_acquire_addresses(struct address **_list, unsigned *_n_list) {
163 .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
164 .nlmsg_type = RTM_GETADDR,
165 .nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP|NLM_F_ACK,
169 .rtgen_family = AF_UNSPEC,
173 struct address *list = NULL;
175 int _cleanup_close_ fd;
177 fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
181 if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0)
184 if (send(fd, &req, req.hdr.nlmsg_len, 0) < 0)
187 while((r = read_reply(fd, &list, &n_list)) == 0)
195 assert(n_list == 0 || list);
196 qsort(list, n_list, sizeof(struct address), address_compare);