]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-network/sd-network.c
test: add smoke tests for `--network-namespace-path`
[thirdparty/systemd.git] / src / libsystemd / sd-network / sd-network.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2011 Lennart Poettering
6 Copyright 2014 Tom Gundersen
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <errno.h>
23 #include <poll.h>
24 #include <string.h>
25 #include <sys/inotify.h>
26
27 #include "sd-network.h"
28
29 #include "alloc-util.h"
30 #include "fd-util.h"
31 #include "fileio.h"
32 #include "fs-util.h"
33 #include "macro.h"
34 #include "parse-util.h"
35 #include "stdio-util.h"
36 #include "string-util.h"
37 #include "strv.h"
38 #include "util.h"
39
40 _public_ int sd_network_get_operational_state(char **state) {
41 _cleanup_free_ char *s = NULL;
42 int r;
43
44 assert_return(state, -EINVAL);
45
46 r = parse_env_file("/run/systemd/netif/state", NEWLINE, "OPER_STATE", &s, NULL);
47 if (r == -ENOENT)
48 return -ENODATA;
49 if (r < 0)
50 return r;
51 if (isempty(s))
52 return -ENODATA;
53
54 *state = s;
55 s = NULL;
56
57 return 0;
58 }
59
60 static int network_get_strv(const char *key, char ***ret) {
61 _cleanup_strv_free_ char **a = NULL;
62 _cleanup_free_ char *s = NULL;
63 int r;
64
65 assert_return(ret, -EINVAL);
66
67 r = parse_env_file("/run/systemd/netif/state", NEWLINE, key, &s, NULL);
68 if (r == -ENOENT)
69 return -ENODATA;
70 if (r < 0)
71 return r;
72 if (isempty(s)) {
73 *ret = NULL;
74 return 0;
75 }
76
77 a = strv_split(s, " ");
78 if (!a)
79 return -ENOMEM;
80
81 strv_uniq(a);
82 r = strv_length(a);
83
84 *ret = a;
85 a = NULL;
86
87 return r;
88 }
89
90 _public_ int sd_network_get_dns(char ***ret) {
91 return network_get_strv("DNS", ret);
92 }
93
94 _public_ int sd_network_get_ntp(char ***ret) {
95 return network_get_strv("NTP", ret);
96 }
97
98 _public_ int sd_network_get_search_domains(char ***ret) {
99 return network_get_strv("DOMAINS", ret);
100 }
101
102 _public_ int sd_network_get_route_domains(char ***ret) {
103 return network_get_strv("ROUTE_DOMAINS", ret);
104 }
105
106 static int network_link_get_string(int ifindex, const char *field, char **ret) {
107 char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
108 _cleanup_free_ char *s = NULL;
109 int r;
110
111 assert_return(ifindex > 0, -EINVAL);
112 assert_return(ret, -EINVAL);
113
114 xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
115
116 r = parse_env_file(path, NEWLINE, field, &s, NULL);
117 if (r == -ENOENT)
118 return -ENODATA;
119 if (r < 0)
120 return r;
121 if (isempty(s))
122 return -ENODATA;
123
124 *ret = s;
125 s = NULL;
126
127 return 0;
128 }
129
130 static int network_link_get_strv(int ifindex, const char *key, char ***ret) {
131 char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
132 _cleanup_strv_free_ char **a = NULL;
133 _cleanup_free_ char *s = NULL;
134 int r;
135
136 assert_return(ifindex > 0, -EINVAL);
137 assert_return(ret, -EINVAL);
138
139 xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
140 r = parse_env_file(path, NEWLINE, key, &s, NULL);
141 if (r == -ENOENT)
142 return -ENODATA;
143 if (r < 0)
144 return r;
145 if (isempty(s)) {
146 *ret = NULL;
147 return 0;
148 }
149
150 a = strv_split(s, " ");
151 if (!a)
152 return -ENOMEM;
153
154 strv_uniq(a);
155 r = strv_length(a);
156
157 *ret = a;
158 a = NULL;
159
160 return r;
161 }
162
163 _public_ int sd_network_link_get_setup_state(int ifindex, char **state) {
164 return network_link_get_string(ifindex, "ADMIN_STATE", state);
165 }
166
167 _public_ int sd_network_link_get_network_file(int ifindex, char **filename) {
168 return network_link_get_string(ifindex, "NETWORK_FILE", filename);
169 }
170
171 _public_ int sd_network_link_get_operational_state(int ifindex, char **state) {
172 return network_link_get_string(ifindex, "OPER_STATE", state);
173 }
174
175 _public_ int sd_network_link_get_required_for_online(int ifindex) {
176 _cleanup_free_ char *s = NULL;
177 int r;
178
179 r = network_link_get_string(ifindex, "REQUIRED_FOR_ONLINE", &s);
180 if (r < 0) {
181 /* Handle -ENODATA as RequiredForOnline=yes, for compatibility */
182 if (r == -ENODATA)
183 return true;
184 return r;
185 }
186
187 return parse_boolean(s);
188 }
189
190 _public_ int sd_network_link_get_llmnr(int ifindex, char **llmnr) {
191 return network_link_get_string(ifindex, "LLMNR", llmnr);
192 }
193
194 _public_ int sd_network_link_get_mdns(int ifindex, char **mdns) {
195 return network_link_get_string(ifindex, "MDNS", mdns);
196 }
197
198 _public_ int sd_network_link_get_dnssec(int ifindex, char **dnssec) {
199 return network_link_get_string(ifindex, "DNSSEC", dnssec);
200 }
201
202 _public_ int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char ***nta) {
203 return network_link_get_strv(ifindex, "DNSSEC_NTA", nta);
204 }
205
206 _public_ int sd_network_link_get_timezone(int ifindex, char **ret) {
207 return network_link_get_string(ifindex, "TIMEZONE", ret);
208 }
209
210 _public_ int sd_network_link_get_dns(int ifindex, char ***ret) {
211 return network_link_get_strv(ifindex, "DNS", ret);
212 }
213
214 _public_ int sd_network_link_get_ntp(int ifindex, char ***ret) {
215 return network_link_get_strv(ifindex, "NTP", ret);
216 }
217
218 _public_ int sd_network_link_get_search_domains(int ifindex, char ***ret) {
219 return network_link_get_strv(ifindex, "DOMAINS", ret);
220 }
221
222 _public_ int sd_network_link_get_route_domains(int ifindex, char ***ret) {
223 return network_link_get_strv(ifindex, "ROUTE_DOMAINS", ret);
224 }
225
226 static int network_link_get_ifindexes(int ifindex, const char *key, int **ret) {
227 char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
228 _cleanup_free_ int *ifis = NULL;
229 _cleanup_free_ char *s = NULL;
230 size_t allocated = 0, c = 0;
231 const char *x;
232 int r;
233
234 assert_return(ifindex > 0, -EINVAL);
235 assert_return(ret, -EINVAL);
236
237 xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
238 r = parse_env_file(path, NEWLINE, key, &s, NULL);
239 if (r == -ENOENT)
240 return -ENODATA;
241 if (r < 0)
242 return r;
243
244 for (x = s;;) {
245 _cleanup_free_ char *word = NULL;
246
247 r = extract_first_word(&x, &word, NULL, 0);
248 if (r < 0)
249 return r;
250 if (r == 0)
251 break;
252
253 r = parse_ifindex(word, &ifindex);
254 if (r < 0)
255 return r;
256
257 if (!GREEDY_REALLOC(ifis, allocated, c + 2))
258 return -ENOMEM;
259
260 ifis[c++] = ifindex;
261 }
262
263 if (ifis)
264 ifis[c] = 0; /* Let's add a 0 ifindex to the end, to be nice */
265
266 *ret = ifis;
267 ifis = NULL;
268
269 return c;
270 }
271
272 _public_ int sd_network_link_get_carrier_bound_to(int ifindex, int **ret) {
273 return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_TO", ret);
274 }
275
276 _public_ int sd_network_link_get_carrier_bound_by(int ifindex, int **ret) {
277 return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_BY", ret);
278 }
279
280 static inline int MONITOR_TO_FD(sd_network_monitor *m) {
281 return (int) (unsigned long) m - 1;
282 }
283
284 static inline sd_network_monitor* FD_TO_MONITOR(int fd) {
285 return (sd_network_monitor*) (unsigned long) (fd + 1);
286 }
287
288 static int monitor_add_inotify_watch(int fd) {
289 int k;
290
291 k = inotify_add_watch(fd, "/run/systemd/netif/links/", IN_MOVED_TO|IN_DELETE);
292 if (k >= 0)
293 return 0;
294 else if (errno != ENOENT)
295 return -errno;
296
297 k = inotify_add_watch(fd, "/run/systemd/netif/", IN_CREATE|IN_ISDIR);
298 if (k >= 0)
299 return 0;
300 else if (errno != ENOENT)
301 return -errno;
302
303 k = inotify_add_watch(fd, "/run/systemd/", IN_CREATE|IN_ISDIR);
304 if (k < 0)
305 return -errno;
306
307 return 0;
308 }
309
310 _public_ int sd_network_monitor_new(sd_network_monitor **m, const char *category) {
311 _cleanup_close_ int fd = -1;
312 int k;
313 bool good = false;
314
315 assert_return(m, -EINVAL);
316
317 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
318 if (fd < 0)
319 return -errno;
320
321 if (!category || streq(category, "links")) {
322 k = monitor_add_inotify_watch(fd);
323 if (k < 0)
324 return k;
325
326 good = true;
327 }
328
329 if (!good)
330 return -EINVAL;
331
332 *m = FD_TO_MONITOR(fd);
333 fd = -1;
334
335 return 0;
336 }
337
338 _public_ sd_network_monitor* sd_network_monitor_unref(sd_network_monitor *m) {
339 int fd;
340
341 if (m) {
342 fd = MONITOR_TO_FD(m);
343 close_nointr(fd);
344 }
345
346 return NULL;
347 }
348
349 _public_ int sd_network_monitor_flush(sd_network_monitor *m) {
350 union inotify_event_buffer buffer;
351 struct inotify_event *e;
352 ssize_t l;
353 int fd, k;
354
355 assert_return(m, -EINVAL);
356
357 fd = MONITOR_TO_FD(m);
358
359 l = read(fd, &buffer, sizeof(buffer));
360 if (l < 0) {
361 if (IN_SET(errno, EAGAIN, EINTR))
362 return 0;
363
364 return -errno;
365 }
366
367 FOREACH_INOTIFY_EVENT(e, buffer, l) {
368 if (e->mask & IN_ISDIR) {
369 k = monitor_add_inotify_watch(fd);
370 if (k < 0)
371 return k;
372
373 k = inotify_rm_watch(fd, e->wd);
374 if (k < 0)
375 return -errno;
376 }
377 }
378
379 return 0;
380 }
381
382 _public_ int sd_network_monitor_get_fd(sd_network_monitor *m) {
383
384 assert_return(m, -EINVAL);
385
386 return MONITOR_TO_FD(m);
387 }
388
389 _public_ int sd_network_monitor_get_events(sd_network_monitor *m) {
390
391 assert_return(m, -EINVAL);
392
393 /* For now we will only return POLLIN here, since we don't
394 * need anything else ever for inotify. However, let's have
395 * this API to keep our options open should we later on need
396 * it. */
397 return POLLIN;
398 }
399
400 _public_ int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *timeout_usec) {
401
402 assert_return(m, -EINVAL);
403 assert_return(timeout_usec, -EINVAL);
404
405 /* For now we will only return (uint64_t) -1, since we don't
406 * need any timeout. However, let's have this API to keep our
407 * options open should we later on need it. */
408 *timeout_usec = (uint64_t) -1;
409 return 0;
410 }