chiark / gitweb /
sd-network: expose DNS information
[elogind.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 }