]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/nss-myhostname/netlink.c
sd-rtnl: message - expose DUMP flag in the api
[thirdparty/systemd.git] / src / nss-myhostname / netlink.c
CommitLineData
8041b5ba
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
cbc06dcd 4 This file is part of systemd.
8041b5ba
LP
5
6 Copyright 2008-2011 Lennart Poettering
7
cbc06dcd
TG
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.
8041b5ba 12
cbc06dcd
TG
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
8041b5ba
LP
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
cbc06dcd
TG
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/>.
8041b5ba
LP
20***/
21
22#include <sys/socket.h>
23#include <sys/un.h>
24#include <asm/types.h>
25#include <inttypes.h>
26#include <linux/netlink.h>
27#include <linux/rtnetlink.h>
28#include <string.h>
29#include <assert.h>
30#include <errno.h>
31#include <limits.h>
32#include <arpa/inet.h>
33#include <unistd.h>
8041b5ba
LP
34#include <stdlib.h>
35
1df2a0fc 36#include "ifconf.h"
8041b5ba 37
d73c3269 38#define SEQ 4711
8041b5ba 39
d73c3269
ZJS
40static int read_reply(int fd, struct address **list, unsigned *n_list) {
41 ssize_t bytes;
42 struct cmsghdr *cmsg;
43 struct ucred *ucred;
44 struct nlmsghdr *p;
45 uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
8041b5ba
LP
46 struct {
47 struct nlmsghdr hdr;
d73c3269
ZJS
48 struct ifaddrmsg ifaddrmsg;
49 uint8_t payload[16*1024];
50 } resp;
51 struct iovec iov = {
52 .iov_base = &resp,
53 .iov_len = sizeof(resp),
54 };
55 struct msghdr msg = {
56 .msg_name = NULL,
57 .msg_namelen = 0,
58 .msg_iov = &iov,
59 .msg_iovlen = 1,
60 .msg_control = cred_buffer,
61 .msg_controllen = sizeof(cred_buffer),
62 .msg_flags = 0,
63 };
64
65 assert(fd >= 0);
66 assert(list);
67
68 bytes = recvmsg(fd, &msg, 0);
69 if (bytes < 0)
8041b5ba
LP
70 return -errno;
71
d73c3269
ZJS
72 cmsg = CMSG_FIRSTHDR(&msg);
73 if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS)
74 return -EIO;
8041b5ba 75
d73c3269
ZJS
76 ucred = (struct ucred*) CMSG_DATA(cmsg);
77 if (ucred->uid != 0 || ucred->pid != 0)
78 return 0;
8041b5ba 79
d73c3269
ZJS
80 for (p = &resp.hdr; bytes > 0; p = NLMSG_NEXT(p, bytes)) {
81 struct ifaddrmsg *ifaddrmsg;
82 struct rtattr *a;
83 size_t l;
84 void *local = NULL, *address = NULL;
8041b5ba 85
d73c3269
ZJS
86 if (!NLMSG_OK(p, (size_t) bytes))
87 return -EIO;
8041b5ba 88
d73c3269
ZJS
89 if (p->nlmsg_seq != SEQ)
90 continue;
91
92 if (p->nlmsg_type == NLMSG_DONE)
93 return 1;
94
95 if (p->nlmsg_type == NLMSG_ERROR) {
96 struct nlmsgerr *nlmsgerr;
8041b5ba 97
d73c3269
ZJS
98 nlmsgerr = NLMSG_DATA(p);
99 return -nlmsgerr->error;
8041b5ba
LP
100 }
101
d73c3269 102 if (p->nlmsg_type != RTM_NEWADDR)
8041b5ba
LP
103 continue;
104
d73c3269 105 ifaddrmsg = NLMSG_DATA(p);
8041b5ba 106
d73c3269
ZJS
107 if (ifaddrmsg->ifa_family != AF_INET &&
108 ifaddrmsg->ifa_family != AF_INET6)
109 continue;
8041b5ba 110
d73c3269
ZJS
111 if (ifaddrmsg->ifa_scope == RT_SCOPE_HOST ||
112 ifaddrmsg->ifa_scope == RT_SCOPE_NOWHERE)
113 continue;
8041b5ba 114
d73c3269
ZJS
115 if (ifaddrmsg->ifa_flags & IFA_F_DEPRECATED)
116 continue;
8041b5ba 117
d73c3269
ZJS
118 l = NLMSG_PAYLOAD(p, sizeof(struct ifaddrmsg));
119 a = IFA_RTA(ifaddrmsg);
8041b5ba 120
d73c3269 121 while (RTA_OK(a, l)) {
8041b5ba 122
d73c3269
ZJS
123 if (a->rta_type == IFA_ADDRESS)
124 address = RTA_DATA(a);
125 else if (a->rta_type == IFA_LOCAL)
126 local = RTA_DATA(a);
8041b5ba 127
d73c3269
ZJS
128 a = RTA_NEXT(a, l);
129 }
8041b5ba 130
d73c3269
ZJS
131 if (local)
132 address = local;
8041b5ba 133
d73c3269
ZJS
134 if (!address)
135 continue;
8041b5ba 136
d73c3269
ZJS
137 *list = realloc(*list, (*n_list+1) * sizeof(struct address));
138 if (!*list)
139 return -ENOMEM;
8041b5ba 140
d73c3269
ZJS
141 (*list)[*n_list].family = ifaddrmsg->ifa_family;
142 (*list)[*n_list].scope = ifaddrmsg->ifa_scope;
143 memcpy((*list)[*n_list].address,
144 address, ifaddrmsg->ifa_family == AF_INET ? 4 : 16);
145 (*list)[*n_list].ifindex = ifaddrmsg->ifa_index;
8041b5ba 146
d73c3269
ZJS
147 (*n_list)++;
148 }
8041b5ba 149
d73c3269
ZJS
150 return 0;
151}
8041b5ba 152
8041b5ba 153
d73c3269 154int ifconf_acquire_addresses(struct address **_list, unsigned *_n_list) {
8041b5ba 155
d73c3269
ZJS
156 struct {
157 struct nlmsghdr hdr;
158 struct rtgenmsg gen;
159 } req = { {
160 .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
161 .nlmsg_type = RTM_GETADDR,
162 .nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP|NLM_F_ACK,
163 .nlmsg_seq = SEQ,
164 .nlmsg_pid = 0,
165 }, {
166 .rtgen_family = AF_UNSPEC,
167 }
168 };
169 int r, on = 1;
170 struct address *list = NULL;
171 unsigned n_list = 0;
7464b33d 172 int fd;
8041b5ba 173
d73c3269
ZJS
174 fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
175 if (fd < 0)
176 return -errno;
8041b5ba 177
7464b33d
ZJS
178 if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
179 r = -errno;
180 goto finish;
181 }
8041b5ba 182
7464b33d
ZJS
183 if (send(fd, &req, req.hdr.nlmsg_len, 0) < 0) {
184 r = -errno;
185 goto finish;
186 }
8041b5ba 187
d73c3269
ZJS
188 while((r = read_reply(fd, &list, &n_list)) == 0)
189 ;
8041b5ba 190
7464b33d
ZJS
191finish:
192 close(fd);
193
d73c3269 194 if (r < 0) {
8041b5ba 195 free(list);
d73c3269 196 return r;
8041b5ba
LP
197 }
198
7ff7394d
ZJS
199 if (n_list)
200 qsort(list, n_list, sizeof(struct address), address_compare);
d73c3269
ZJS
201
202 *_list = list;
203 *_n_list = n_list;
204
205 return 0;
8041b5ba 206}