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