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