]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-network/sd-network.c
9d95f8b5be279a532f84250bc6d90a62ec59d1de
[thirdparty/systemd.git] / src / libsystemd / sd-network / sd-network.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <poll.h>
4 #include <sys/inotify.h>
5 #include <sys/stat.h>
6 #include <unistd.h>
7
8 #include "sd-network.h"
9
10 #include "alloc-util.h"
11 #include "env-file.h"
12 #include "errno-util.h"
13 #include "extract-word.h"
14 #include "fd-util.h"
15 #include "inotify-util.h"
16 #include "parse-util.h"
17 #include "stdio-util.h"
18 #include "string-util.h"
19 #include "strv.h"
20
21 static int network_get_string(const char *field, char **ret) {
22 _cleanup_free_ char *s = NULL;
23 int r;
24
25 assert_return(ret, -EINVAL);
26
27 r = parse_env_file(NULL, "/run/systemd/netif/state", field, &s);
28 if (r < 0)
29 return r;
30 if (isempty(s))
31 return -ENODATA;
32
33 *ret = TAKE_PTR(s);
34 return 0;
35 }
36
37 int sd_network_get_operational_state(char **ret) {
38 return network_get_string("OPER_STATE", ret);
39 }
40
41 int sd_network_get_carrier_state(char **ret) {
42 return network_get_string("CARRIER_STATE", ret);
43 }
44
45 int sd_network_get_address_state(char **ret) {
46 return network_get_string("ADDRESS_STATE", ret);
47 }
48
49 int sd_network_get_ipv4_address_state(char **ret) {
50 return network_get_string("IPV4_ADDRESS_STATE", ret);
51 }
52
53 int sd_network_get_ipv6_address_state(char **ret) {
54 return network_get_string("IPV6_ADDRESS_STATE", ret);
55 }
56
57 int sd_network_get_online_state(char **ret) {
58 return network_get_string("ONLINE_STATE", ret);
59 }
60
61 static int network_get_strv(const char *key, char ***ret) {
62 _cleanup_strv_free_ char **a = NULL;
63 _cleanup_free_ char *s = NULL;
64 int r;
65
66 assert_return(ret, -EINVAL);
67
68 r = parse_env_file(NULL, "/run/systemd/netif/state", key, &s);
69 if (r < 0)
70 return r;
71 if (isempty(s))
72 return -ENODATA;
73
74 a = strv_split(s, NULL);
75 if (!a)
76 return -ENOMEM;
77
78 strv_uniq(a);
79 r = (int) strv_length(a);
80
81 *ret = TAKE_PTR(a);
82 return r;
83 }
84
85 int sd_network_get_dns(char ***ret) {
86 return network_get_strv("DNS", ret);
87 }
88
89 int sd_network_get_ntp(char ***ret) {
90 return network_get_strv("NTP", ret);
91 }
92
93 int sd_network_get_search_domains(char ***ret) {
94 return network_get_strv("DOMAINS", ret);
95 }
96
97 int sd_network_get_route_domains(char ***ret) {
98 return network_get_strv("ROUTE_DOMAINS", ret);
99 }
100
101 static int network_link_get_string(int ifindex, const char *field, char **ret) {
102 char path[STRLEN("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex)];
103 _cleanup_free_ char *s = NULL;
104 int r;
105
106 assert_return(ifindex > 0, -EINVAL);
107 assert_return(ret, -EINVAL);
108
109 xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
110
111 r = parse_env_file(NULL, path, field, &s);
112 if (r < 0)
113 return r;
114 if (isempty(s))
115 return -ENODATA;
116
117 *ret = TAKE_PTR(s);
118 return 0;
119 }
120
121 static int network_link_get_boolean(int ifindex, const char *key) {
122 _cleanup_free_ char *s = NULL;
123 int r;
124
125 r = network_link_get_string(ifindex, key, &s);
126 if (r < 0)
127 return r;
128
129 return parse_boolean(s);
130 }
131
132 static int network_link_get_strv(int ifindex, const char *key, char ***ret) {
133 _cleanup_strv_free_ char **a = NULL;
134 _cleanup_free_ char *s = NULL;
135 int r;
136
137 assert_return(ifindex > 0, -EINVAL);
138 assert_return(ret, -EINVAL);
139
140 r = network_link_get_string(ifindex, key, &s);
141 if (r < 0)
142 return r;
143
144 a = strv_split(s, NULL);
145 if (!a)
146 return -ENOMEM;
147
148 strv_uniq(a);
149 r = (int) strv_length(a);
150
151 *ret = TAKE_PTR(a);
152 return r;
153 }
154
155 int sd_network_link_get_setup_state(int ifindex, char **ret) {
156 return network_link_get_string(ifindex, "ADMIN_STATE", ret);
157 }
158
159 int sd_network_link_get_network_file(int ifindex, char **ret) {
160 return network_link_get_string(ifindex, "NETWORK_FILE", ret);
161 }
162
163 int sd_network_link_get_netdev_file(int ifindex, char **ret) {
164 return network_link_get_string(ifindex, "NETDEV_FILE", ret);
165 }
166
167 static int link_get_config_file_dropins_internal(int ifindex, const char *field, char ***ret) {
168 _cleanup_free_ char *s = NULL;
169 int r;
170
171 assert(field);
172 assert_return(ifindex > 0, -EINVAL);
173 assert_return(ret, -EINVAL);
174
175 r = network_link_get_string(ifindex, field, &s);
176 if (r < 0)
177 return r;
178
179 r = strv_split_full(ret, s, ":", EXTRACT_CUNESCAPE);
180 if (r < 0)
181 return r;
182
183 return 0;
184 }
185
186 int sd_network_link_get_network_file_dropins(int ifindex, char ***ret) {
187 return link_get_config_file_dropins_internal(ifindex, "NETWORK_FILE_DROPINS", ret);
188 }
189
190 int sd_network_link_get_netdev_file_dropins(int ifindex, char ***ret) {
191 return link_get_config_file_dropins_internal(ifindex, "NETDEV_FILE_DROPINS", ret);
192 }
193
194 int sd_network_link_get_operational_state(int ifindex, char **ret) {
195 return network_link_get_string(ifindex, "OPER_STATE", ret);
196 }
197
198 int sd_network_link_get_required_family_for_online(int ifindex, char **ret) {
199 return network_link_get_string(ifindex, "REQUIRED_FAMILY_FOR_ONLINE", ret);
200 }
201
202 int sd_network_link_get_carrier_state(int ifindex, char **ret) {
203 return network_link_get_string(ifindex, "CARRIER_STATE", ret);
204 }
205
206 int sd_network_link_get_address_state(int ifindex, char **ret) {
207 return network_link_get_string(ifindex, "ADDRESS_STATE", ret);
208 }
209
210 int sd_network_link_get_ipv4_address_state(int ifindex, char **ret) {
211 return network_link_get_string(ifindex, "IPV4_ADDRESS_STATE", ret);
212 }
213
214 int sd_network_link_get_ipv6_address_state(int ifindex, char **ret) {
215 return network_link_get_string(ifindex, "IPV6_ADDRESS_STATE", ret);
216 }
217
218 int sd_network_link_get_online_state(int ifindex, char **ret) {
219 return network_link_get_string(ifindex, "ONLINE_STATE", ret);
220 }
221
222 int sd_network_link_get_dhcp6_client_iaid_string(int ifindex, char **ret) {
223 return network_link_get_string(ifindex, "DHCP6_CLIENT_IAID", ret);
224 }
225
226 int sd_network_link_get_dhcp6_client_duid_string(int ifindex, char **ret) {
227 return network_link_get_string(ifindex, "DHCP6_CLIENT_DUID", ret);
228 }
229
230 int sd_network_link_get_required_for_online(int ifindex) {
231 return network_link_get_boolean(ifindex, "REQUIRED_FOR_ONLINE");
232 }
233
234 int sd_network_link_get_required_operstate_for_online(int ifindex, char **ret) {
235 return network_link_get_string(ifindex, "REQUIRED_OPER_STATE_FOR_ONLINE", ret);
236 }
237
238 int sd_network_link_get_activation_policy(int ifindex, char **ret) {
239 return network_link_get_string(ifindex, "ACTIVATION_POLICY", ret);
240 }
241
242 int sd_network_link_get_llmnr(int ifindex, char **ret) {
243 return network_link_get_string(ifindex, "LLMNR", ret);
244 }
245
246 int sd_network_link_get_mdns(int ifindex, char **ret) {
247 return network_link_get_string(ifindex, "MDNS", ret);
248 }
249
250 int sd_network_link_get_dns_over_tls(int ifindex, char **ret) {
251 return network_link_get_string(ifindex, "DNS_OVER_TLS", ret);
252 }
253
254 int sd_network_link_get_dnssec(int ifindex, char **ret) {
255 return network_link_get_string(ifindex, "DNSSEC", ret);
256 }
257
258 int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char ***ret) {
259 return network_link_get_strv(ifindex, "DNSSEC_NTA", ret);
260 }
261
262 int sd_network_link_get_dns(int ifindex, char ***ret) {
263 return network_link_get_strv(ifindex, "DNS", ret);
264 }
265
266 int sd_network_link_get_ntp(int ifindex, char ***ret) {
267 return network_link_get_strv(ifindex, "NTP", ret);
268 }
269
270 int sd_network_link_get_sip(int ifindex, char ***ret) {
271 return network_link_get_strv(ifindex, "SIP", ret);
272 }
273
274 int sd_network_link_get_captive_portal(int ifindex, char **ret) {
275 return network_link_get_string(ifindex, "CAPTIVE_PORTAL", ret);
276 }
277
278 int sd_network_link_get_search_domains(int ifindex, char ***ret) {
279 return network_link_get_strv(ifindex, "DOMAINS", ret);
280 }
281
282 int sd_network_link_get_route_domains(int ifindex, char ***ret) {
283 return network_link_get_strv(ifindex, "ROUTE_DOMAINS", ret);
284 }
285
286 int sd_network_link_get_dns_default_route(int ifindex) {
287 return network_link_get_boolean(ifindex, "DNS_DEFAULT_ROUTE");
288 }
289
290 static int network_link_get_ifindexes(int ifindex, const char *key, int **ret) {
291 _cleanup_free_ int *ifis = NULL;
292 _cleanup_free_ char *s = NULL;
293 size_t c = 0;
294 int r;
295
296 assert_return(ifindex > 0, -EINVAL);
297 assert_return(ret, -EINVAL);
298
299 r = network_link_get_string(ifindex, key, &s);
300 if (r < 0)
301 return r;
302
303 for (const char *x = s;;) {
304 _cleanup_free_ char *word = NULL;
305
306 r = extract_first_word(&x, &word, NULL, 0);
307 if (r < 0)
308 return r;
309 if (r == 0)
310 break;
311
312 if (!GREEDY_REALLOC(ifis, c + 2))
313 return -ENOMEM;
314
315 r = ifis[c++] = parse_ifindex(word);
316 if (r < 0)
317 return r;
318 }
319
320 if (ifis)
321 ifis[c] = 0; /* Let's add a 0 ifindex to the end, to be nice */
322
323 *ret = TAKE_PTR(ifis);
324 return c;
325 }
326
327 int sd_network_link_get_carrier_bound_to(int ifindex, int **ret) {
328 return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_TO", ret);
329 }
330
331 int sd_network_link_get_carrier_bound_by(int ifindex, int **ret) {
332 return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_BY", ret);
333 }
334
335 int sd_network_link_get_stat(int ifindex, struct stat *ret) {
336 char path[STRLEN("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex)];
337 struct stat st;
338
339 assert_return(ifindex > 0, -EINVAL);
340
341 xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
342
343 if (stat(path, &st) < 0)
344 return -errno;
345
346 if (ret)
347 *ret = st;
348
349 return 0;
350 }
351
352 static int MONITOR_TO_FD(sd_network_monitor *m) {
353 return (int) (unsigned long) m - 1;
354 }
355
356 static sd_network_monitor* FD_TO_MONITOR(int fd) {
357 return (sd_network_monitor*) (unsigned long) (fd + 1);
358 }
359
360 static int monitor_add_inotify_watch(int fd) {
361 int wd;
362
363 wd = inotify_add_watch(fd, "/run/systemd/netif/links/", IN_MOVED_TO|IN_DELETE);
364 if (wd >= 0)
365 return wd;
366 else if (errno != ENOENT)
367 return -errno;
368
369 wd = inotify_add_watch(fd, "/run/systemd/netif/", IN_CREATE|IN_ISDIR);
370 if (wd >= 0)
371 return wd;
372 else if (errno != ENOENT)
373 return -errno;
374
375 wd = inotify_add_watch(fd, "/run/systemd/", IN_CREATE|IN_ISDIR);
376 if (wd < 0)
377 return -errno;
378
379 return wd;
380 }
381
382 int sd_network_monitor_new(sd_network_monitor **m, const char *category) {
383 _cleanup_close_ int fd = -EBADF;
384 int k;
385 bool good = false;
386
387 assert_return(m, -EINVAL);
388
389 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
390 if (fd < 0)
391 return -errno;
392
393 if (!category || streq(category, "links")) {
394 k = monitor_add_inotify_watch(fd);
395 if (k < 0)
396 return k;
397
398 good = true;
399 }
400
401 if (!good)
402 return -EINVAL;
403
404 *m = FD_TO_MONITOR(TAKE_FD(fd));
405 return 0;
406 }
407
408 sd_network_monitor* sd_network_monitor_unref(sd_network_monitor *m) {
409 if (m)
410 (void) close(MONITOR_TO_FD(m));
411
412 return NULL;
413 }
414
415 int sd_network_monitor_flush(sd_network_monitor *m) {
416 union inotify_event_buffer buffer;
417 ssize_t l;
418 int fd;
419
420 assert_return(m, -EINVAL);
421
422 fd = MONITOR_TO_FD(m);
423
424 l = read(fd, &buffer, sizeof(buffer));
425 if (l < 0) {
426 if (ERRNO_IS_TRANSIENT(errno))
427 return 0;
428
429 return -errno;
430 }
431
432 FOREACH_INOTIFY_EVENT(e, buffer, l) {
433 if (e->mask & IN_ISDIR) {
434 int wd;
435
436 wd = monitor_add_inotify_watch(fd);
437 if (wd < 0)
438 return wd;
439
440 if (wd != e->wd) {
441 if (inotify_rm_watch(fd, e->wd) < 0)
442 return -errno;
443 }
444 }
445 }
446
447 return 0;
448 }
449
450 int sd_network_monitor_get_fd(sd_network_monitor *m) {
451 assert_return(m, -EINVAL);
452
453 return MONITOR_TO_FD(m);
454 }
455
456 int sd_network_monitor_get_events(sd_network_monitor *m) {
457 assert_return(m, -EINVAL);
458
459 /* For now we will only return POLLIN here, since we don't
460 * need anything else ever for inotify. However, let's have
461 * this API to keep our options open should we later on need
462 * it. */
463 return POLLIN;
464 }
465
466 int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *ret_usec) {
467 assert_return(m, -EINVAL);
468 assert_return(ret_usec, -EINVAL);
469
470 /* For now we will only return UINT64_MAX, since we don't
471 * need any timeout. However, let's have this API to keep our
472 * options open should we later on need it. */
473 *ret_usec = UINT64_MAX;
474 return 0;
475 }