]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-state-file.c
network: Introduce UseCaptivePortal DHCPv4 option
[thirdparty/systemd.git] / src / network / networkd-state-file.c
CommitLineData
3b5a4fc6
YW
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include <netinet/in.h>
4#include <linux/if.h>
5
6#include "alloc-util.h"
7#include "dns-domain.h"
a2640646 8#include "escape.h"
3b5a4fc6
YW
9#include "fd-util.h"
10#include "fileio.h"
11#include "fs-util.h"
12#include "network-internal.h"
13#include "networkd-link.h"
14#include "networkd-manager-bus.h"
15#include "networkd-manager.h"
16#include "networkd-network.h"
17#include "networkd-state-file.h"
18#include "ordered-set.h"
19#include "set.h"
20#include "strv.h"
21#include "tmpfile-util.h"
22
cf453507 23static int ordered_set_put_dns_server(OrderedSet **s, int ifindex, struct in_addr_full *dns) {
3b5a4fc6
YW
24 const char *p;
25 int r;
26
27 assert(s);
28 assert(dns);
29
30 if (dns->ifindex != 0 && dns->ifindex != ifindex)
31 return 0;
32
33 p = in_addr_full_to_string(dns);
34 if (!p)
35 return 0;
36
37 r = ordered_set_put_strdup(s, p);
38 if (r == -EEXIST)
39 return 0;
40
41 return r;
42}
43
cf453507 44static int ordered_set_put_dns_servers(OrderedSet **s, int ifindex, struct in_addr_full **dns, unsigned n) {
3b5a4fc6
YW
45 int r, c = 0;
46
47 assert(s);
48 assert(dns || n == 0);
49
50 for (unsigned i = 0; i < n; i++) {
51 r = ordered_set_put_dns_server(s, ifindex, dns[i]);
52 if (r < 0)
53 return r;
54
55 c += r;
56 }
57
58 return c;
59}
60
cf453507
YW
61static int ordered_set_put_in4_addr(OrderedSet **s, const struct in_addr *address) {
62 _cleanup_free_ char *p = NULL;
3b5a4fc6
YW
63 int r;
64
65 assert(s);
66 assert(address);
67
68 r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
69 if (r < 0)
70 return r;
71
cf453507
YW
72 r = ordered_set_ensure_allocated(s, &string_hash_ops_free);
73 if (r < 0)
74 return r;
75
76 r = ordered_set_consume(*s, TAKE_PTR(p));
3b5a4fc6
YW
77 if (r == -EEXIST)
78 return 0;
79
80 return r;
81}
82
44e1f7e3 83static int ordered_set_put_in4_addrv(
cf453507 84 OrderedSet **s,
44e1f7e3
YW
85 const struct in_addr *addresses,
86 size_t n,
87 bool (*predicate)(const struct in_addr *addr)) {
88
3b5a4fc6
YW
89 int r, c = 0;
90
91 assert(s);
92 assert(n == 0 || addresses);
93
94 for (size_t i = 0; i < n; i++) {
95 if (predicate && !predicate(&addresses[i]))
96 continue;
97 r = ordered_set_put_in4_addr(s, addresses+i);
98 if (r < 0)
99 return r;
100
101 c += r;
102 }
103
104 return c;
105}
106
107int manager_save(Manager *m) {
cf453507 108 _cleanup_ordered_set_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL;
bcdcc596 109 const char *operstate_str, *carrier_state_str, *address_state_str, *ipv4_address_state_str, *ipv6_address_state_str, *online_state_str;
3b5a4fc6
YW
110 LinkOperationalState operstate = LINK_OPERSTATE_OFF;
111 LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF;
8430841b
L
112 LinkAddressState ipv4_address_state = LINK_ADDRESS_STATE_OFF, ipv6_address_state = LINK_ADDRESS_STATE_OFF,
113 address_state = LINK_ADDRESS_STATE_OFF;
bcdcc596
114 LinkOnlineState online_state;
115 size_t links_offline = 0, links_online = 0;
d23a66f2 116 _cleanup_(unlink_and_freep) char *temp_path = NULL;
3b5a4fc6
YW
117 _cleanup_strv_free_ char **p = NULL;
118 _cleanup_fclose_ FILE *f = NULL;
119 Link *link;
120 int r;
121
122 assert(m);
4c78dc17
YW
123
124 if (isempty(m->state_file))
125 return 0; /* Do not update state file when running in test mode. */
3b5a4fc6 126
6eab614d 127 HASHMAP_FOREACH(link, m->links_by_index) {
3b5a4fc6
YW
128 const struct in_addr *addresses;
129
130 if (link->flags & IFF_LOOPBACK)
131 continue;
132
90afec18
YW
133 operstate = MAX(operstate, link->operstate);
134 carrier_state = MAX(carrier_state, link->carrier_state);
135 address_state = MAX(address_state, link->address_state);
136 ipv4_address_state = MAX(ipv4_address_state, link->ipv4_address_state);
137 ipv6_address_state = MAX(ipv6_address_state, link->ipv6_address_state);
8430841b 138
3b5a4fc6
YW
139 if (!link->network)
140 continue;
141
bcdcc596
142 if (link->network->required_for_online) {
143 if (link->online_state == LINK_ONLINE_STATE_OFFLINE)
144 links_offline++;
145 else if (link->online_state == LINK_ONLINE_STATE_ONLINE)
146 links_online++;
147 }
148
3b5a4fc6 149 /* First add the static configured entries */
f5fbe71d 150 if (link->n_dns != UINT_MAX)
cf453507 151 r = ordered_set_put_dns_servers(&dns, link->ifindex, link->dns, link->n_dns);
3b5a4fc6 152 else
cf453507 153 r = ordered_set_put_dns_servers(&dns, link->ifindex, link->network->dns, link->network->n_dns);
3b5a4fc6
YW
154 if (r < 0)
155 return r;
156
cf453507 157 r = ordered_set_put_strdupv(&ntp, link->ntp ?: link->network->ntp);
3b5a4fc6
YW
158 if (r < 0)
159 return r;
160
cf453507 161 r = ordered_set_put_string_set(&search_domains, link->search_domains ?: link->network->search_domains);
3b5a4fc6
YW
162 if (r < 0)
163 return r;
164
cf453507 165 r = ordered_set_put_string_set(&route_domains, link->route_domains ?: link->network->route_domains);
3b5a4fc6
YW
166 if (r < 0)
167 return r;
168
169 if (!link->dhcp_lease)
170 continue;
171
172 /* Secondly, add the entries acquired via DHCP */
173 if (link->network->dhcp_use_dns) {
174 r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
175 if (r > 0) {
cf453507 176 r = ordered_set_put_in4_addrv(&dns, addresses, r, in4_addr_is_non_local);
3b5a4fc6
YW
177 if (r < 0)
178 return r;
179 } else if (r < 0 && r != -ENODATA)
180 return r;
181 }
182
183 if (link->network->dhcp_use_ntp) {
184 r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
185 if (r > 0) {
cf453507 186 r = ordered_set_put_in4_addrv(&ntp, addresses, r, in4_addr_is_non_local);
3b5a4fc6
YW
187 if (r < 0)
188 return r;
189 } else if (r < 0 && r != -ENODATA)
190 return r;
191 }
192
193 if (link->network->dhcp_use_sip) {
194 r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses);
195 if (r > 0) {
cf453507 196 r = ordered_set_put_in4_addrv(&sip, addresses, r, in4_addr_is_non_local);
3b5a4fc6
YW
197 if (r < 0)
198 return r;
199 } else if (r < 0 && r != -ENODATA)
200 return r;
201 }
202
203 if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
cf453507 204 OrderedSet **target_domains;
3b5a4fc6
YW
205 const char *domainname;
206 char **domains = NULL;
207
0b6a4795 208 target_domains = link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES ? &search_domains : &route_domains;
3b5a4fc6
YW
209 r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
210 if (r >= 0) {
211 r = ordered_set_put_strdup(target_domains, domainname);
212 if (r < 0)
213 return r;
214 } else if (r != -ENODATA)
215 return r;
216
217 r = sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains);
218 if (r >= 0) {
219 r = ordered_set_put_strdupv(target_domains, domains);
220 if (r < 0)
221 return r;
222 } else if (r != -ENODATA)
223 return r;
224 }
225 }
226
227 if (carrier_state >= LINK_CARRIER_STATE_ENSLAVED)
228 carrier_state = LINK_CARRIER_STATE_CARRIER;
229
bcdcc596
230 online_state = links_online > 0 ?
231 (links_offline > 0 ? LINK_ONLINE_STATE_PARTIAL : LINK_ONLINE_STATE_ONLINE) :
232 (links_offline > 0 ? LINK_ONLINE_STATE_OFFLINE : _LINK_ONLINE_STATE_INVALID);
233
3b5a4fc6
YW
234 operstate_str = link_operstate_to_string(operstate);
235 assert(operstate_str);
236
237 carrier_state_str = link_carrier_state_to_string(carrier_state);
238 assert(carrier_state_str);
239
240 address_state_str = link_address_state_to_string(address_state);
241 assert(address_state_str);
242
8430841b
L
243 ipv4_address_state_str = link_address_state_to_string(ipv4_address_state);
244 assert(ipv4_address_state_str);
245
246 ipv6_address_state_str = link_address_state_to_string(ipv6_address_state);
247 assert(ipv6_address_state_str);
248
3b5a4fc6
YW
249 r = fopen_temporary(m->state_file, &f, &temp_path);
250 if (r < 0)
251 return r;
252
253 (void) fchmod(fileno(f), 0644);
254
255 fprintf(f,
256 "# This is private data. Do not parse.\n"
257 "OPER_STATE=%s\n"
258 "CARRIER_STATE=%s\n"
8430841b
L
259 "ADDRESS_STATE=%s\n"
260 "IPV4_ADDRESS_STATE=%s\n"
261 "IPV6_ADDRESS_STATE=%s\n",
262 operstate_str, carrier_state_str, address_state_str, ipv4_address_state_str, ipv6_address_state_str);
3b5a4fc6 263
bcdcc596
264 online_state_str = link_online_state_to_string(online_state);
265 if (online_state_str)
266 fprintf(f, "ONLINE_STATE=%s\n", online_state_str);
267
3b5a4fc6
YW
268 ordered_set_print(f, "DNS=", dns);
269 ordered_set_print(f, "NTP=", ntp);
270 ordered_set_print(f, "SIP=", sip);
271 ordered_set_print(f, "DOMAINS=", search_domains);
272 ordered_set_print(f, "ROUTE_DOMAINS=", route_domains);
273
274 r = fflush_and_check(f);
275 if (r < 0)
d23a66f2 276 return r;
3b5a4fc6
YW
277
278 r = conservative_rename(temp_path, m->state_file);
279 if (r < 0)
d23a66f2
YW
280 return r;
281
282 temp_path = mfree(temp_path);
3b5a4fc6
YW
283
284 if (m->operational_state != operstate) {
285 m->operational_state = operstate;
286 if (strv_extend(&p, "OperationalState") < 0)
287 log_oom();
288 }
289
290 if (m->carrier_state != carrier_state) {
291 m->carrier_state = carrier_state;
292 if (strv_extend(&p, "CarrierState") < 0)
293 log_oom();
294 }
295
296 if (m->address_state != address_state) {
297 m->address_state = address_state;
298 if (strv_extend(&p, "AddressState") < 0)
299 log_oom();
300 }
301
8430841b
L
302 if (m->ipv4_address_state != ipv4_address_state) {
303 m->ipv4_address_state = ipv4_address_state;
304 if (strv_extend(&p, "IPv4AddressState") < 0)
305 log_oom();
306 }
307
308 if (m->ipv6_address_state != ipv6_address_state) {
309 m->ipv6_address_state = ipv6_address_state;
310 if (strv_extend(&p, "IPv6AddressState") < 0)
311 log_oom();
312 }
313
bcdcc596
314 if (m->online_state != online_state) {
315 m->online_state = online_state;
316 if (strv_extend(&p, "OnlineState") < 0)
317 log_oom();
318 }
319
3b5a4fc6
YW
320 if (p) {
321 r = manager_send_changed_strv(m, p);
322 if (r < 0)
d23a66f2 323 log_warning_errno(r, "Could not emit changed properties, ignoring: %m");
3b5a4fc6
YW
324 }
325
326 m->dirty = false;
327
328 return 0;
3b5a4fc6
YW
329}
330
331static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) {
332 bool space = false;
333 Link *link;
334
335 assert(f);
336 assert(prefix);
337
338 if (hashmap_isempty(h))
339 return;
340
341 fputs(prefix, f);
342 HASHMAP_FOREACH(link, h) {
343 if (space)
344 fputc(' ', f);
345
346 fprintf(f, "%i", link->ifindex);
347 space = true;
348 }
349
350 fputc('\n', f);
351}
352
353static void link_save_dns(Link *link, FILE *f, struct in_addr_full **dns, unsigned n_dns, bool *space) {
56437e33
YW
354 bool _space = false;
355
356 if (!space)
357 space = &_space;
358
3b5a4fc6
YW
359 for (unsigned j = 0; j < n_dns; j++) {
360 const char *str;
361
362 if (dns[j]->ifindex != 0 && dns[j]->ifindex != link->ifindex)
363 continue;
364
365 str = in_addr_full_to_string(dns[j]);
366 if (!str)
367 continue;
368
369 if (*space)
370 fputc(' ', f);
371 fputs(str, f);
372 *space = true;
373 }
374}
375
376static void serialize_addresses(
377 FILE *f,
378 const char *lvalue,
379 bool *space,
380 char **addresses,
381 sd_dhcp_lease *lease,
382 bool conditional,
383 sd_dhcp_lease_server_type_t what,
384 sd_dhcp6_lease *lease6,
385 bool conditional6,
386 int (*lease6_get_addr)(sd_dhcp6_lease*, const struct in6_addr**),
387 int (*lease6_get_fqdn)(sd_dhcp6_lease*, char ***)) {
3b5a4fc6
YW
388
389 bool _space = false;
44e1f7e3
YW
390 int r;
391
3b5a4fc6
YW
392 if (!space)
393 space = &_space;
394
395 if (lvalue)
396 fprintf(f, "%s=", lvalue);
397 fputstrv(f, addresses, NULL, space);
398
399 if (lease && conditional) {
400 const struct in_addr *lease_addresses;
401
402 r = sd_dhcp_lease_get_servers(lease, what, &lease_addresses);
403 if (r > 0)
404 serialize_in_addrs(f, lease_addresses, r, space, in4_addr_is_non_local);
405 }
406
407 if (lease6 && conditional6 && lease6_get_addr) {
408 const struct in6_addr *in6_addrs;
409
410 r = lease6_get_addr(lease6, &in6_addrs);
411 if (r > 0)
412 serialize_in6_addrs(f, in6_addrs, r, space);
413 }
414
415 if (lease6 && conditional6 && lease6_get_fqdn) {
416 char **in6_hosts;
417
418 r = lease6_get_fqdn(lease6, &in6_hosts);
419 if (r > 0)
420 fputstrv(f, in6_hosts, NULL, space);
421 }
422
423 if (lvalue)
424 fputc('\n', f);
425}
426
56437e33
YW
427static void link_save_domains(Link *link, FILE *f, OrderedSet *static_domains, DHCPUseDomains use_domains) {
428 bool space = false;
429 const char *p;
430
431 assert(link);
432 assert(link->network);
433 assert(f);
434
435 ORDERED_SET_FOREACH(p, static_domains)
436 fputs_with_space(f, p, NULL, &space);
437
438 if (use_domains == DHCP_USE_DOMAINS_NO)
439 return;
440
441 if (link->dhcp_lease && link->network->dhcp_use_domains == use_domains) {
442 const char *domainname;
443 char **domains;
444
445 if (sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname) >= 0)
446 fputs_with_space(f, domainname, NULL, &space);
447 if (sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains) >= 0)
448 fputstrv(f, domains, NULL, &space);
449 }
450
451 if (link->dhcp6_lease && link->network->dhcp6_use_domains == use_domains) {
452 char **domains;
453
454 if (sd_dhcp6_lease_get_domains(link->dhcp6_lease, &domains) >= 0)
455 fputstrv(f, domains, NULL, &space);
456 }
457
458 if (link->network->ipv6_accept_ra_use_domains == use_domains) {
459 NDiscDNSSL *dd;
460
461 SET_FOREACH(dd, link->ndisc_dnssl)
462 fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
463 }
464}
465
3b5a4fc6 466int link_save(Link *link) {
edb88a72
RP
467 const char *admin_state, *oper_state, *carrier_state, *address_state, *ipv4_address_state, *ipv6_address_state,
468 *dhcp_captive_portal = NULL;
d23a66f2 469 _cleanup_(unlink_and_freep) char *temp_path = NULL;
3b5a4fc6
YW
470 _cleanup_fclose_ FILE *f = NULL;
471 int r;
472
473 assert(link);
3b5a4fc6
YW
474 assert(link->manager);
475
4c78dc17
YW
476 if (isempty(link->state_file))
477 return 0; /* Do not update state files when running in test mode. */
478
d23a66f2 479 if (link->state == LINK_STATE_LINGER)
3b5a4fc6 480 return 0;
3b5a4fc6
YW
481
482 link_lldp_save(link);
483
484 admin_state = link_state_to_string(link->state);
485 assert(admin_state);
486
487 oper_state = link_operstate_to_string(link->operstate);
488 assert(oper_state);
489
490 carrier_state = link_carrier_state_to_string(link->carrier_state);
491 assert(carrier_state);
492
493 address_state = link_address_state_to_string(link->address_state);
494 assert(address_state);
495
8430841b
L
496 ipv4_address_state = link_address_state_to_string(link->ipv4_address_state);
497 assert(ipv4_address_state);
498
499 ipv6_address_state = link_address_state_to_string(link->ipv6_address_state);
500 assert(ipv6_address_state);
501
3b5a4fc6
YW
502 r = fopen_temporary(link->state_file, &f, &temp_path);
503 if (r < 0)
d23a66f2 504 return r;
3b5a4fc6
YW
505
506 (void) fchmod(fileno(f), 0644);
507
508 fprintf(f,
509 "# This is private data. Do not parse.\n"
510 "ADMIN_STATE=%s\n"
511 "OPER_STATE=%s\n"
512 "CARRIER_STATE=%s\n"
8430841b
L
513 "ADDRESS_STATE=%s\n"
514 "IPV4_ADDRESS_STATE=%s\n"
515 "IPV6_ADDRESS_STATE=%s\n",
516 admin_state, oper_state, carrier_state, address_state, ipv4_address_state, ipv6_address_state);
3b5a4fc6
YW
517
518 if (link->network) {
56437e33 519 const char *online_state;
a2640646 520 bool space = false;
3b5a4fc6 521
bcdcc596
522 online_state = link_online_state_to_string(link->online_state);
523 if (online_state)
524 fprintf(f, "ONLINE_STATE=%s\n", online_state);
525
3b5a4fc6
YW
526 fprintf(f, "REQUIRED_FOR_ONLINE=%s\n",
527 yes_no(link->network->required_for_online));
528
529 LinkOperationalStateRange st = link->network->required_operstate_for_online;
530 fprintf(f, "REQUIRED_OPER_STATE_FOR_ONLINE=%s%s%s\n",
531 strempty(link_operstate_to_string(st.min)),
532 st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? ":" : "",
533 st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? strempty(link_operstate_to_string(st.max)) : "");
534
8430841b
L
535 fprintf(f, "REQUIRED_FAMILY_FOR_ONLINE=%s\n",
536 link_required_address_family_to_string(link->network->required_family_for_online));
537
3b5a4fc6
YW
538 fprintf(f, "ACTIVATION_POLICY=%s\n",
539 activation_policy_to_string(link->network->activation_policy));
540
541 fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
542
a2640646
DDM
543 fputs("NETWORK_FILE_DROPINS=\"", f);
544 STRV_FOREACH(d, link->network->dropins) {
545 _cleanup_free_ char *escaped = NULL;
546
547 escaped = xescape(*d, ":");
548 if (!escaped)
549 return -ENOMEM;
550
551 fputs_with_space(f, escaped, ":", &space);
552 }
553 fputs("\"\n", f);
554
3b5a4fc6
YW
555 /************************************************************/
556
56437e33
YW
557 fputs("DNS=", f);
558 if (link->n_dns != UINT_MAX)
559 link_save_dns(link, f, link->dns, link->n_dns, NULL);
560 else {
561 space = false;
562 link_save_dns(link, f, link->network->dns, link->network->n_dns, &space);
3b5a4fc6 563
56437e33
YW
564 serialize_addresses(f, NULL, &space,
565 NULL,
566 link->dhcp_lease,
567 link->network->dhcp_use_dns,
568 SD_DHCP_LEASE_DNS,
569 link->dhcp6_lease,
570 link->network->dhcp6_use_dns,
571 sd_dhcp6_lease_get_dns,
572 NULL);
573
574 if (link->network->ipv6_accept_ra_use_dns) {
575 NDiscRDNSS *dd;
576
577 SET_FOREACH(dd, link->ndisc_rdnss)
578 serialize_in6_addrs(f, &dd->address, 1, &space);
579 }
3b5a4fc6
YW
580 }
581
582 fputc('\n', f);
583
584 /************************************************************/
585
56437e33
YW
586 if (link->ntp) {
587 fputs("NTP=", f);
588 fputstrv(f, link->ntp, NULL, NULL);
589 fputc('\n', f);
590 } else
591 serialize_addresses(f, "NTP", NULL,
592 link->network->ntp,
593 link->dhcp_lease,
594 link->network->dhcp_use_ntp,
595 SD_DHCP_LEASE_NTP,
596 link->dhcp6_lease,
597 link->network->dhcp6_use_ntp,
598 sd_dhcp6_lease_get_ntp_addrs,
599 sd_dhcp6_lease_get_ntp_fqdn);
3b5a4fc6
YW
600
601 serialize_addresses(f, "SIP", NULL,
602 NULL,
603 link->dhcp_lease,
604 link->network->dhcp_use_sip,
605 SD_DHCP_LEASE_SIP,
606 NULL, false, NULL, NULL);
607
608 /************************************************************/
609
edb88a72
RP
610 if (link->dhcp_lease && link->network->dhcp_use_captive_portal) {
611 r = sd_dhcp_lease_get_captive_portal(link->dhcp_lease, &dhcp_captive_portal);
612 if (r < 0 && r != -ENODATA)
613 return r;
614 }
615
616 if (dhcp_captive_portal)
617 fprintf(f, "CAPTIVE_PORTAL=%s\n", dhcp_captive_portal);
618
619 /************************************************************/
620
3b5a4fc6 621 fputs("DOMAINS=", f);
56437e33
YW
622 if (link->search_domains)
623 link_save_domains(link, f, link->search_domains, DHCP_USE_DOMAINS_NO);
624 else
625 link_save_domains(link, f, link->network->search_domains, DHCP_USE_DOMAINS_YES);
3b5a4fc6
YW
626 fputc('\n', f);
627
628 /************************************************************/
629
630 fputs("ROUTE_DOMAINS=", f);
56437e33
YW
631 if (link->route_domains)
632 link_save_domains(link, f, link->route_domains, DHCP_USE_DOMAINS_NO);
633 else
634 link_save_domains(link, f, link->network->route_domains, DHCP_USE_DOMAINS_ROUTE);
3b5a4fc6
YW
635 fputc('\n', f);
636
637 /************************************************************/
638
639 fprintf(f, "LLMNR=%s\n",
640 resolve_support_to_string(link->llmnr >= 0 ? link->llmnr : link->network->llmnr));
641
642 /************************************************************/
643
644 fprintf(f, "MDNS=%s\n",
645 resolve_support_to_string(link->mdns >= 0 ? link->mdns : link->network->mdns));
646
647 /************************************************************/
648
649 int dns_default_route =
650 link->dns_default_route >= 0 ? link->dns_default_route :
651 link->network->dns_default_route;
652 if (dns_default_route >= 0)
653 fprintf(f, "DNS_DEFAULT_ROUTE=%s\n", yes_no(dns_default_route));
654
655 /************************************************************/
656
657 DnsOverTlsMode dns_over_tls_mode =
658 link->dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID ? link->dns_over_tls_mode :
659 link->network->dns_over_tls_mode;
660 if (dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID)
661 fprintf(f, "DNS_OVER_TLS=%s\n", dns_over_tls_mode_to_string(dns_over_tls_mode));
662
663 /************************************************************/
664
665 DnssecMode dnssec_mode =
666 link->dnssec_mode != _DNSSEC_MODE_INVALID ? link->dnssec_mode :
667 link->network->dnssec_mode;
668 if (dnssec_mode != _DNSSEC_MODE_INVALID)
669 fprintf(f, "DNSSEC=%s\n", dnssec_mode_to_string(dnssec_mode));
670
671 /************************************************************/
672
673 Set *nta_anchors = link->dnssec_negative_trust_anchors;
674 if (set_isempty(nta_anchors))
675 nta_anchors = link->network->dnssec_negative_trust_anchors;
676
677 if (!set_isempty(nta_anchors)) {
678 const char *n;
679
680 fputs("DNSSEC_NTA=", f);
681 space = false;
682 SET_FOREACH(n, nta_anchors)
683 fputs_with_space(f, n, NULL, &space);
684 fputc('\n', f);
685 }
686 }
687
688 print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links);
689 print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links);
690
691 if (link->dhcp_lease) {
692 r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
693 if (r < 0)
d23a66f2 694 return r;
3b5a4fc6
YW
695
696 fprintf(f,
697 "DHCP_LEASE=%s\n",
698 link->lease_file);
699 } else
700 (void) unlink(link->lease_file);
701
702 r = link_serialize_dhcp6_client(link, f);
703 if (r < 0)
d23a66f2 704 return r;
3b5a4fc6
YW
705
706 r = fflush_and_check(f);
707 if (r < 0)
d23a66f2 708 return r;
3b5a4fc6
YW
709
710 r = conservative_rename(temp_path, link->state_file);
711 if (r < 0)
d23a66f2 712 return r;
3b5a4fc6 713
d23a66f2 714 temp_path = mfree(temp_path);
3b5a4fc6 715
d23a66f2 716 return 0;
3b5a4fc6
YW
717}
718
719void link_dirty(Link *link) {
720 int r;
721
722 assert(link);
723 assert(link->manager);
724
725 /* The serialized state in /run is no longer up-to-date. */
726
727 /* Also mark manager dirty as link is dirty */
728 link->manager->dirty = true;
729
730 r = set_ensure_put(&link->manager->dirty_links, NULL, link);
731 if (r <= 0)
732 /* Ignore allocation errors and don't take another ref if the link was already dirty */
733 return;
734 link_ref(link);
735}
736
737void link_clean(Link *link) {
738 assert(link);
739 assert(link->manager);
740
741 /* The serialized state in /run is up-to-date */
742
743 link_unref(set_remove(link->manager->dirty_links, link));
744}
745
746int link_save_and_clean(Link *link) {
747 int r;
748
749 r = link_save(link);
750 if (r < 0)
751 return r;
752
753 link_clean(link);
754 return 0;
755}