]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/sd-network.c
sd-network: expose DNS information
[thirdparty/systemd.git] / src / network / sd-network.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7 Copyright 2014 Tom Gundersen
8
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
13
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 ***/
22
23 #include <unistd.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <sys/inotify.h>
27 #include <sys/poll.h>
28 #include <net/if.h>
29
30 #include "util.h"
31 #include "macro.h"
32 #include "strv.h"
33 #include "fileio.h"
34 #include "sd-network.h"
35 #include "network-internal.h"
36 #include "dhcp-lease-internal.h"
37
38 static int link_get_flags(unsigned index, unsigned *flags) {
39 _cleanup_free_ char *s = NULL, *p = NULL;
40 int r;
41
42 assert(index);
43 assert(flags);
44
45 if (asprintf(&p, "/run/systemd/network/links/%u", index) < 0)
46 return -ENOMEM;
47
48 r = parse_env_file(p, NEWLINE, "FLAGS", &s, NULL);
49 if (r == -ENOENT)
50 return -ENODATA;
51 else if (r < 0)
52 return r;
53 else if (!s)
54 return -EIO;
55
56 return safe_atou(s, flags);
57 }
58
59 _public_ int sd_network_link_is_loopback(unsigned index) {
60 unsigned flags;
61 int r;
62
63 r = link_get_flags(index, &flags);
64 if (r < 0)
65 return 0;
66
67 return flags & IFF_LOOPBACK;
68 }
69
70 _public_ int sd_network_get_link_state(unsigned index, char **state) {
71 _cleanup_free_ char *s = NULL, *p = NULL;
72 int r;
73
74 assert_return(index, -EINVAL);
75 assert_return(state, -EINVAL);
76
77 if (asprintf(&p, "/run/systemd/network/links/%u", index) < 0)
78 return -ENOMEM;
79
80 r = parse_env_file(p, NEWLINE, "ADMIN_STATE", &s, NULL);
81 if (r == -ENOENT)
82 return -ENODATA;
83 else if (r < 0)
84 return r;
85 else if (!s)
86 return -EIO;
87
88 if (streq(s, "unmanaged"))
89 return -EUNATCH;
90 else if (streq(s, "initializing"))
91 return -EBUSY;
92
93 *state = s;
94 s = NULL;
95
96 return 0;
97 }
98
99 _public_ int sd_network_get_operational_state(char **state) {
100 _cleanup_free_ char *s = NULL;
101 int r;
102
103 assert_return(state, -EINVAL);
104
105 r = parse_env_file("/run/systemd/network/state", NEWLINE, "OPER_STATE",
106 &s, NULL);
107 if (r == -ENOENT)
108 return -ENODATA;
109 else if (r < 0)
110 return r;
111 else if (!s)
112 return -EIO;
113
114 *state = s;
115 s = NULL;
116
117 return 0;
118 }
119
120 _public_ int sd_network_get_link_operational_state(unsigned index, char **state) {
121 _cleanup_free_ char *s = NULL, *p = NULL;
122 int r;
123
124 assert_return(index, -EINVAL);
125 assert_return(state, -EINVAL);
126
127 if (asprintf(&p, "/run/systemd/network/links/%u", index) < 0)
128 return -ENOMEM;
129
130 r = parse_env_file(p, NEWLINE, "OPER_STATE", &s, NULL);
131 if (r == -ENOENT)
132 return -ENODATA;
133 else if (r < 0)
134 return r;
135 else if (!s)
136 return -EIO;
137
138 *state = s;
139 s = NULL;
140
141 return 0;
142 }
143
144 _public_ int sd_network_get_dhcp_lease(unsigned index, sd_dhcp_lease **ret) {
145 sd_dhcp_lease *lease;
146 char *p, *s = NULL;
147 int r;
148
149 assert_return(index, -EINVAL);
150 assert_return(ret, -EINVAL);
151
152 if (asprintf(&p, "/run/systemd/network/links/%u", index) < 0)
153 return -ENOMEM;
154
155 r = parse_env_file(p, NEWLINE, "DHCP_LEASE", &s, NULL);
156 free(p);
157
158 if (r < 0) {
159 free(s);
160 return r;
161 } else if (!s)
162 return -EIO;
163
164 r = dhcp_lease_load(s, &lease);
165 if (r < 0)
166 return r;
167
168 *ret = lease;
169
170 return 0;
171 }
172
173 _public_ int sd_network_get_dns(unsigned index, struct in_addr **addr, size_t *addr_size) {
174 _cleanup_free_ char *p = NULL, *s = NULL;
175 int r;
176
177 assert_return(index, -EINVAL);
178 assert_return(addr, -EINVAL);
179 assert_return(addr_size, -EINVAL);
180
181 if (asprintf(&p, "/run/systemd/network/links/%u", index) < 0)
182 return -ENOMEM;
183
184 r = parse_env_file(p, NEWLINE, "DNS", &s, NULL);
185 if (r < 0)
186 return r;
187 else if (!s)
188 return -EIO;
189
190 return deserialize_in_addrs(addr, addr_size, s);
191 }
192
193 _public_ int sd_network_get_dns6(unsigned index, struct in6_addr **addr, size_t *addr_size) {
194 _cleanup_free_ char *p = NULL, *s = NULL;
195 int r;
196
197 assert_return(index, -EINVAL);
198 assert_return(addr, -EINVAL);
199 assert_return(addr_size, -EINVAL);
200
201 if (asprintf(&p, "/run/systemd/network/links/%u", index) < 0)
202 return -ENOMEM;
203
204 r = parse_env_file(p, NEWLINE, "DNS", &s, NULL);
205 if (r < 0)
206 return r;
207 else if (!s)
208 return -EIO;
209
210 return deserialize_in6_addrs(addr, addr_size, s);
211 }
212
213 _public_ int sd_network_dhcp_use_dns(unsigned index) {
214 _cleanup_free_ char *p = NULL, *s = NULL;
215 int r;
216
217 assert_return(index, -EINVAL);
218
219 if (asprintf(&p, "/run/systemd/network/links/%u", index) < 0)
220 return -ENOMEM;
221
222 r = parse_env_file(p, NEWLINE, "DHCP_USE_DNS", &s, NULL);
223 if (r < 0)
224 return r;
225 else if (!s)
226 return -EIO;
227
228 return parse_boolean(s);
229 }
230
231 _public_ int sd_network_get_ifindices(unsigned **indices) {
232 _cleanup_closedir_ DIR *d;
233 int r = 0;
234 unsigned n = 0;
235 _cleanup_free_ uid_t *l = NULL;
236
237 d = opendir("/run/systemd/network/links/");
238 if (!d)
239 return -errno;
240
241 for (;;) {
242 struct dirent *de;
243 int k;
244 unsigned index;
245
246 errno = 0;
247 de = readdir(d);
248 if (!de && errno != 0)
249 return -errno;
250
251 if (!de)
252 break;
253
254 dirent_ensure_type(d, de);
255
256 if (!dirent_is_file(de))
257 continue;
258
259 k = safe_atou(de->d_name, &index);
260 if (k < 0)
261 continue;
262
263 if (indices) {
264 if ((unsigned) r >= n) {
265 unsigned *t;
266
267 n = MAX(16, 2*r);
268 t = realloc(l, sizeof(unsigned) * n);
269 if (!t)
270 return -ENOMEM;
271
272 l = t;
273 }
274
275 assert((unsigned) r < n);
276 l[r++] = index;
277 } else
278 r++;
279 }
280
281 if (indices) {
282 *indices = l;
283 l = NULL;
284 }
285
286 return r;
287 }
288
289 static inline int MONITOR_TO_FD(sd_network_monitor *m) {
290 return (int) (unsigned long) m - 1;
291 }
292
293 static inline sd_network_monitor* FD_TO_MONITOR(int fd) {
294 return (sd_network_monitor*) (unsigned long) (fd + 1);
295 }
296
297 _public_ int sd_network_monitor_new(const char *category, sd_network_monitor **m) {
298 int fd, k;
299 bool good = false;
300
301 assert_return(m, -EINVAL);
302
303 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
304 if (fd < 0)
305 return -errno;
306
307 if (!category || streq(category, "links")) {
308 k = inotify_add_watch(fd, "/run/systemd/network/links/", IN_MOVED_TO|IN_DELETE);
309 if (k < 0) {
310 safe_close(fd);
311 return -errno;
312 }
313
314 good = true;
315 }
316
317 if (!category || streq(category, "leases")) {
318 k = inotify_add_watch(fd, "/run/systemd/network/leases/", IN_MOVED_TO|IN_DELETE);
319 if (k < 0) {
320 safe_close(fd);
321 return -errno;
322 }
323
324 good = true;
325 }
326
327 if (!good) {
328 close_nointr(fd);
329 return -EINVAL;
330 }
331
332 *m = FD_TO_MONITOR(fd);
333 return 0;
334 }
335
336 _public_ sd_network_monitor* sd_network_monitor_unref(sd_network_monitor *m) {
337 int fd;
338
339 assert_return(m, NULL);
340
341 fd = MONITOR_TO_FD(m);
342 close_nointr(fd);
343
344 return NULL;
345 }
346
347 _public_ int sd_network_monitor_flush(sd_network_monitor *m) {
348
349 assert_return(m, -EINVAL);
350
351 return flush_fd(MONITOR_TO_FD(m));
352 }
353
354 _public_ int sd_network_monitor_get_fd(sd_network_monitor *m) {
355
356 assert_return(m, -EINVAL);
357
358 return MONITOR_TO_FD(m);
359 }
360
361 _public_ int sd_network_monitor_get_events(sd_network_monitor *m) {
362
363 assert_return(m, -EINVAL);
364
365 /* For now we will only return POLLIN here, since we don't
366 * need anything else ever for inotify. However, let's have
367 * this API to keep our options open should we later on need
368 * it. */
369 return POLLIN;
370 }
371
372 _public_ int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *timeout_usec) {
373
374 assert_return(m, -EINVAL);
375 assert_return(timeout_usec, -EINVAL);
376
377 /* For now we will only return (uint64_t) -1, since we don't
378 * need any timeout. However, let's have this API to keep our
379 * options open should we later on need it. */
380 *timeout_usec = (uint64_t) -1;
381 return 0;
382 }