1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /***
3   Copyright © 2017 Intel Corporation. All rights reserved.
4 ***/
5 
6 #include <netinet/icmp6.h>
7 #include <arpa/inet.h>
8 
9 #include "dns-domain.h"
10 #include "networkd-address-generation.h"
11 #include "networkd-address.h"
12 #include "networkd-dhcp-prefix-delegation.h"
13 #include "networkd-link.h"
14 #include "networkd-manager.h"
15 #include "networkd-network.h"
16 #include "networkd-queue.h"
17 #include "networkd-radv.h"
18 #include "networkd-route-util.h"
19 #include "parse-util.h"
20 #include "radv-internal.h"
21 #include "string-util.h"
22 #include "string-table.h"
23 #include "strv.h"
24 
network_adjust_radv(Network * network)25 void network_adjust_radv(Network *network) {
26         assert(network);
27 
28         /* After this function is called, network->router_prefix_delegation can be treated as a boolean. */
29 
30         if (network->dhcp_pd < 0)
31                 /* For backward compatibility. */
32                 network->dhcp_pd = FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_DHCP6);
33 
34         if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
35                 if (network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE)
36                         log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link-local addressing is disabled. "
37                                     "Disabling IPv6PrefixDelegation=.", network->filename);
38 
39                 network->router_prefix_delegation = RADV_PREFIX_DELEGATION_NONE;
40         }
41 
42         if (network->router_prefix_delegation == RADV_PREFIX_DELEGATION_NONE) {
43                 network->n_router_dns = 0;
44                 network->router_dns = mfree(network->router_dns);
45                 network->router_search_domains = ordered_set_free(network->router_search_domains);
46         }
47 
48         if (!FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_STATIC)) {
49                 network->prefixes_by_section = hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
50                 network->route_prefixes_by_section = hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
51         }
52 }
53 
link_radv_enabled(Link * link)54 bool link_radv_enabled(Link *link) {
55         assert(link);
56 
57         if (!link_may_have_ipv6ll(link))
58                 return false;
59 
60         if (link->hw_addr.length != ETH_ALEN)
61                 return false;
62 
63         return link->network->router_prefix_delegation;
64 }
65 
prefix_free(Prefix * prefix)66 Prefix *prefix_free(Prefix *prefix) {
67         if (!prefix)
68                 return NULL;
69 
70         if (prefix->network) {
71                 assert(prefix->section);
72                 hashmap_remove(prefix->network->prefixes_by_section, prefix->section);
73         }
74 
75         config_section_free(prefix->section);
76         set_free(prefix->tokens);
77 
78         return mfree(prefix);
79 }
80 
81 DEFINE_SECTION_CLEANUP_FUNCTIONS(Prefix, prefix_free);
82 
prefix_new_static(Network * network,const char * filename,unsigned section_line,Prefix ** ret)83 static int prefix_new_static(Network *network, const char *filename, unsigned section_line, Prefix **ret) {
84         _cleanup_(config_section_freep) ConfigSection *n = NULL;
85         _cleanup_(prefix_freep) Prefix *prefix = NULL;
86         int r;
87 
88         assert(network);
89         assert(ret);
90         assert(filename);
91         assert(section_line > 0);
92 
93         r = config_section_new(filename, section_line, &n);
94         if (r < 0)
95                 return r;
96 
97         prefix = hashmap_get(network->prefixes_by_section, n);
98         if (prefix) {
99                 *ret = TAKE_PTR(prefix);
100                 return 0;
101         }
102 
103         prefix = new(Prefix, 1);
104         if (!prefix)
105                 return -ENOMEM;
106 
107         *prefix = (Prefix) {
108                 .network = network,
109                 .section = TAKE_PTR(n),
110 
111                 .preferred_lifetime = RADV_DEFAULT_PREFERRED_LIFETIME_USEC,
112                 .valid_lifetime = RADV_DEFAULT_VALID_LIFETIME_USEC,
113                 .onlink = true,
114                 .address_auto_configuration = true,
115         };
116 
117         r = hashmap_ensure_put(&network->prefixes_by_section, &config_section_hash_ops, prefix->section, prefix);
118         if (r < 0)
119                 return r;
120 
121         *ret = TAKE_PTR(prefix);
122         return 0;
123 }
124 
route_prefix_free(RoutePrefix * prefix)125 RoutePrefix *route_prefix_free(RoutePrefix *prefix) {
126         if (!prefix)
127                 return NULL;
128 
129         if (prefix->network) {
130                 assert(prefix->section);
131                 hashmap_remove(prefix->network->route_prefixes_by_section, prefix->section);
132         }
133 
134         config_section_free(prefix->section);
135 
136         return mfree(prefix);
137 }
138 
139 DEFINE_SECTION_CLEANUP_FUNCTIONS(RoutePrefix, route_prefix_free);
140 
route_prefix_new_static(Network * network,const char * filename,unsigned section_line,RoutePrefix ** ret)141 static int route_prefix_new_static(Network *network, const char *filename, unsigned section_line, RoutePrefix **ret) {
142         _cleanup_(config_section_freep) ConfigSection *n = NULL;
143         _cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL;
144         int r;
145 
146         assert(network);
147         assert(ret);
148         assert(filename);
149         assert(section_line > 0);
150 
151         r = config_section_new(filename, section_line, &n);
152         if (r < 0)
153                 return r;
154 
155         prefix = hashmap_get(network->route_prefixes_by_section, n);
156         if (prefix) {
157                 *ret = TAKE_PTR(prefix);
158                 return 0;
159         }
160 
161         prefix = new(RoutePrefix, 1);
162         if (!prefix)
163                 return -ENOMEM;
164 
165         *prefix = (RoutePrefix) {
166                 .network = network,
167                 .section = TAKE_PTR(n),
168 
169                 .lifetime = RADV_DEFAULT_VALID_LIFETIME_USEC,
170         };
171 
172         r = hashmap_ensure_put(&network->route_prefixes_by_section, &config_section_hash_ops, prefix->section, prefix);
173         if (r < 0)
174                 return r;
175 
176         *ret = TAKE_PTR(prefix);
177         return 0;
178 }
179 
link_request_radv_addresses(Link * link)180 int link_request_radv_addresses(Link *link) {
181         Prefix *p;
182         int r;
183 
184         assert(link);
185 
186         if (!link_radv_enabled(link))
187                 return 0;
188 
189         HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
190                 _cleanup_set_free_ Set *addresses = NULL;
191                 struct in6_addr *a;
192 
193                 if (!p->assign)
194                         continue;
195 
196                 /* radv_generate_addresses() below requires the prefix length <= 64. */
197                 if (p->prefixlen > 64)
198                         continue;
199 
200                 r = radv_generate_addresses(link, p->tokens, &p->prefix, p->prefixlen, &addresses);
201                 if (r < 0)
202                         return r;
203 
204                 SET_FOREACH(a, addresses) {
205                         _cleanup_(address_freep) Address *address = NULL;
206 
207                         r = address_new(&address);
208                         if (r < 0)
209                                 return -ENOMEM;
210 
211                         address->source = NETWORK_CONFIG_SOURCE_STATIC;
212                         address->family = AF_INET6;
213                         address->in_addr.in6 = *a;
214                         address->prefixlen = p->prefixlen;
215                         address->route_metric = p->route_metric;
216 
217                         r = link_request_static_address(link, TAKE_PTR(address), true);
218                         if (r < 0)
219                                 return r;
220                 }
221         }
222 
223         return 0;
224 }
225 
usec_to_lifetime(usec_t usec)226 static uint32_t usec_to_lifetime(usec_t usec) {
227         uint64_t t;
228 
229         if (usec == USEC_INFINITY)
230                 return UINT32_MAX;
231 
232         t = DIV_ROUND_UP(usec, USEC_PER_SEC);
233         if (t >= UINT32_MAX)
234                 return UINT32_MAX;
235 
236         return (uint32_t) t;
237 }
238 
radv_set_prefix(Link * link,Prefix * prefix)239 static int radv_set_prefix(Link *link, Prefix *prefix) {
240         _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
241         int r;
242 
243         assert(link);
244         assert(link->radv);
245         assert(prefix);
246 
247         r = sd_radv_prefix_new(&p);
248         if (r < 0)
249                 return r;
250 
251         r = sd_radv_prefix_set_prefix(p, &prefix->prefix, prefix->prefixlen);
252         if (r < 0)
253                 return r;
254 
255         r = sd_radv_prefix_set_preferred_lifetime(p, prefix->preferred_lifetime, USEC_INFINITY);
256         if (r < 0)
257                 return r;
258 
259         r = sd_radv_prefix_set_valid_lifetime(p, prefix->valid_lifetime, USEC_INFINITY);
260         if (r < 0)
261                 return r;
262 
263         r = sd_radv_prefix_set_onlink(p, prefix->onlink);
264         if (r < 0)
265                 return r;
266 
267         r = sd_radv_prefix_set_address_autoconfiguration(p, prefix->address_auto_configuration);
268         if (r < 0)
269                 return r;
270 
271         return sd_radv_add_prefix(link->radv, p);
272 }
273 
radv_set_route_prefix(Link * link,RoutePrefix * prefix)274 static int radv_set_route_prefix(Link *link, RoutePrefix *prefix) {
275         _cleanup_(sd_radv_route_prefix_unrefp) sd_radv_route_prefix *p = NULL;
276         int r;
277 
278         assert(link);
279         assert(link->radv);
280         assert(prefix);
281 
282         r = sd_radv_route_prefix_new(&p);
283         if (r < 0)
284                 return r;
285 
286         r = sd_radv_route_prefix_set_prefix(p, &prefix->prefix, prefix->prefixlen);
287         if (r < 0)
288                 return r;
289 
290         r = sd_radv_route_prefix_set_lifetime(p, prefix->lifetime, USEC_INFINITY);
291         if (r < 0)
292                 return r;
293 
294         return sd_radv_add_route_prefix(link->radv, p);
295 }
296 
network_get_ipv6_dns(Network * network,struct in6_addr ** ret_addresses,size_t * ret_size)297 static int network_get_ipv6_dns(Network *network, struct in6_addr **ret_addresses, size_t *ret_size) {
298         _cleanup_free_ struct in6_addr *addresses = NULL;
299         size_t n_addresses = 0;
300 
301         assert(network);
302         assert(ret_addresses);
303         assert(ret_size);
304 
305         for (size_t i = 0; i < network->n_dns; i++) {
306                 union in_addr_union *addr;
307 
308                 if (network->dns[i]->family != AF_INET6)
309                         continue;
310 
311                 addr = &network->dns[i]->address;
312 
313                 if (in_addr_is_null(AF_INET6, addr) ||
314                     in_addr_is_link_local(AF_INET6, addr) ||
315                     in_addr_is_localhost(AF_INET6, addr))
316                         continue;
317 
318                 if (!GREEDY_REALLOC(addresses, n_addresses + 1))
319                         return -ENOMEM;
320 
321                 addresses[n_addresses++] = addr->in6;
322         }
323 
324         *ret_addresses = TAKE_PTR(addresses);
325         *ret_size = n_addresses;
326 
327         return n_addresses;
328 }
329 
radv_set_dns(Link * link,Link * uplink)330 static int radv_set_dns(Link *link, Link *uplink) {
331         _cleanup_free_ struct in6_addr *dns = NULL;
332         size_t n_dns;
333         int r;
334 
335         if (!link->network->router_emit_dns)
336                 return 0;
337 
338         if (link->network->router_dns) {
339                 struct in6_addr *p;
340 
341                 dns = new(struct in6_addr, link->network->n_router_dns);
342                 if (!dns)
343                         return -ENOMEM;
344 
345                 p = dns;
346                 for (size_t i = 0; i < link->network->n_router_dns; i++)
347                         if (in6_addr_is_null(&link->network->router_dns[i])) {
348                                 if (in6_addr_is_set(&link->ipv6ll_address))
349                                         *(p++) = link->ipv6ll_address;
350                         } else
351                                 *(p++) = link->network->router_dns[i];
352 
353                 n_dns = p - dns;
354 
355                 goto set_dns;
356         }
357 
358         r = network_get_ipv6_dns(link->network, &dns, &n_dns);
359         if (r > 0)
360                 goto set_dns;
361 
362         if (uplink) {
363                 assert(uplink->network);
364 
365                 r = network_get_ipv6_dns(uplink->network, &dns, &n_dns);
366                 if (r > 0)
367                         goto set_dns;
368         }
369 
370         return 0;
371 
372 set_dns:
373         return sd_radv_set_rdnss(link->radv,
374                                  usec_to_lifetime(link->network->router_dns_lifetime_usec),
375                                  dns, n_dns);
376 }
377 
radv_set_domains(Link * link,Link * uplink)378 static int radv_set_domains(Link *link, Link *uplink) {
379         _cleanup_free_ char **s = NULL; /* just free() because the strings are owned by the set */
380         OrderedSet *search_domains;
381 
382         if (!link->network->router_emit_domains)
383                 return 0;
384 
385         search_domains = link->network->router_search_domains;
386 
387         if (search_domains)
388                 goto set_domains;
389 
390         search_domains = link->network->search_domains;
391         if (search_domains)
392                 goto set_domains;
393 
394         if (uplink) {
395                 assert(uplink->network);
396 
397                 search_domains = uplink->network->search_domains;
398                 if (search_domains)
399                         goto set_domains;
400         }
401 
402         return 0;
403 
404 set_domains:
405         s = ordered_set_get_strv(search_domains);
406         if (!s)
407                 return log_oom();
408 
409         return sd_radv_set_dnssl(link->radv,
410                                  usec_to_lifetime(link->network->router_dns_lifetime_usec),
411                                  s);
412 
413 }
414 
radv_find_uplink(Link * link,Link ** ret)415 static int radv_find_uplink(Link *link, Link **ret) {
416         int r;
417 
418         assert(link);
419 
420         if (link->network->router_uplink_name)
421                 return link_get_by_name(link->manager, link->network->router_uplink_name, ret);
422 
423         if (link->network->router_uplink_index > 0)
424                 return link_get_by_index(link->manager, link->network->router_uplink_index, ret);
425 
426         if (link->network->router_uplink_index == UPLINK_INDEX_AUTO) {
427                 if (link_dhcp_pd_is_enabled(link))
428                         r = dhcp_pd_find_uplink(link, ret); /* When DHCP-PD is enabled, use its uplink. */
429                 else
430                         r = manager_find_uplink(link->manager, AF_INET6, link, ret);
431                 if (r < 0)
432                         /* It is not necessary to propagate error in automatic selection. */
433                         *ret = NULL;
434                 return 0;
435         }
436 
437         *ret = NULL;
438         return 0;
439 }
440 
radv_configure(Link * link)441 static int radv_configure(Link *link) {
442         Link *uplink = NULL;
443         RoutePrefix *q;
444         Prefix *p;
445         int r;
446 
447         assert(link);
448         assert(link->network);
449 
450         if (link->radv)
451                 return -EBUSY;
452 
453         r = sd_radv_new(&link->radv);
454         if (r < 0)
455                 return r;
456 
457         r = sd_radv_attach_event(link->radv, link->manager->event, 0);
458         if (r < 0)
459                 return r;
460 
461         r = sd_radv_set_mac(link->radv, &link->hw_addr.ether);
462         if (r < 0)
463                 return r;
464 
465         r = sd_radv_set_ifindex(link->radv, link->ifindex);
466         if (r < 0)
467                 return r;
468 
469         r = sd_radv_set_managed_information(link->radv, link->network->router_managed);
470         if (r < 0)
471                 return r;
472 
473         r = sd_radv_set_other_information(link->radv, link->network->router_other_information);
474         if (r < 0)
475                 return r;
476 
477         r = sd_radv_set_router_lifetime(link->radv, link->network->router_lifetime_usec);
478         if (r < 0)
479                 return r;
480 
481         if (link->network->router_lifetime_usec > 0) {
482                 r = sd_radv_set_preference(link->radv, link->network->router_preference);
483                 if (r < 0)
484                         return r;
485         }
486 
487         HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
488                 r = radv_set_prefix(link, p);
489                 if (r < 0 && r != -EEXIST)
490                         return r;
491         }
492 
493         HASHMAP_FOREACH(q, link->network->route_prefixes_by_section) {
494                 r = radv_set_route_prefix(link, q);
495                 if (r < 0 && r != -EEXIST)
496                         return r;
497         }
498 
499         (void) radv_find_uplink(link, &uplink);
500 
501         r = radv_set_dns(link, uplink);
502         if (r < 0)
503                 return log_link_debug_errno(link, r, "Could not set RA DNS: %m");
504 
505         r = radv_set_domains(link, uplink);
506         if (r < 0)
507                 return log_link_debug_errno(link, r, "Could not set RA Domains: %m");
508 
509         return 0;
510 }
511 
radv_update_mac(Link * link)512 int radv_update_mac(Link *link) {
513         bool restart;
514         int r;
515 
516         assert(link);
517 
518         if (!link->radv)
519                 return 0;
520 
521         restart = sd_radv_is_running(link->radv);
522 
523         r = sd_radv_stop(link->radv);
524         if (r < 0)
525                 return r;
526 
527         r = sd_radv_set_mac(link->radv, &link->hw_addr.ether);
528         if (r < 0)
529                 return r;
530 
531         if (restart) {
532                 r = sd_radv_start(link->radv);
533                 if (r < 0)
534                         return r;
535         }
536 
537         return 0;
538 }
539 
radv_is_ready_to_configure(Link * link)540 static int radv_is_ready_to_configure(Link *link) {
541         bool needs_uplink = false;
542         int r;
543 
544         assert(link);
545         assert(link->network);
546 
547         if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
548                 return false;
549 
550         if (in6_addr_is_null(&link->ipv6ll_address))
551                 return false;
552 
553         if (link->hw_addr.length != ETH_ALEN || hw_addr_is_null(&link->hw_addr))
554                 return false;
555 
556         if (link->network->router_emit_dns && !link->network->router_dns) {
557                 _cleanup_free_ struct in6_addr *dns = NULL;
558                 size_t n_dns;
559 
560                 r = network_get_ipv6_dns(link->network, &dns, &n_dns);
561                 if (r < 0)
562                         return r;
563 
564                 needs_uplink = r == 0;
565         }
566 
567         if (link->network->router_emit_domains &&
568             !link->network->router_search_domains &&
569             !link->network->search_domains)
570                 needs_uplink = true;
571 
572         if (needs_uplink) {
573                 Link *uplink = NULL;
574 
575                 if (radv_find_uplink(link, &uplink) < 0)
576                         return false;
577 
578                 if (uplink && !uplink->network)
579                         return false;
580         }
581 
582         return true;
583 }
584 
radv_process_request(Request * req,Link * link,void * userdata)585 static int radv_process_request(Request *req, Link *link, void *userdata) {
586         int r;
587 
588         assert(link);
589 
590         r = radv_is_ready_to_configure(link);
591         if (r <= 0)
592                 return r;
593 
594         r = radv_configure(link);
595         if (r < 0)
596                 return log_link_warning_errno(link, r, "Failed to configure IPv6 Router Advertisement engine: %m");
597 
598         if (link_has_carrier(link)) {
599                 r = radv_start(link);
600                 if (r < 0)
601                         return log_link_warning_errno(link, r, "Failed to start IPv6 Router Advertisement engine: %m");
602         }
603 
604         log_link_debug(link, "IPv6 Router Advertisement engine is configured%s.",
605                        link_has_carrier(link) ? " and started." : "");
606         return 1;
607 }
608 
link_request_radv(Link * link)609 int link_request_radv(Link *link) {
610         int r;
611 
612         assert(link);
613 
614         if (!link_radv_enabled(link))
615                 return 0;
616 
617         if (link->radv)
618                 return 0;
619 
620         r = link_queue_request(link, REQUEST_TYPE_RADV, radv_process_request, NULL);
621         if (r < 0)
622                 return log_link_warning_errno(link, r, "Failed to request configuring of the IPv6 Router Advertisement engine: %m");
623 
624         log_link_debug(link, "Requested configuring of the IPv6 Router Advertisement engine.");
625         return 0;
626 }
627 
radv_start(Link * link)628 int radv_start(Link *link) {
629         int r;
630 
631         assert(link);
632         assert(link->network);
633 
634         if (!link->radv)
635                 return 0;
636 
637         if (!link_has_carrier(link))
638                 return 0;
639 
640         if (in6_addr_is_null(&link->ipv6ll_address))
641                 return 0;
642 
643         if (sd_radv_is_running(link->radv))
644                 return 0;
645 
646         if (link->network->dhcp_pd_announce) {
647                 r = dhcp_request_prefix_delegation(link);
648                 if (r < 0)
649                         return log_link_debug_errno(link, r, "Failed to request DHCP delegated subnet prefix: %m");
650         }
651 
652         log_link_debug(link, "Starting IPv6 Router Advertisements");
653         return sd_radv_start(link->radv);
654 }
655 
radv_add_prefix(Link * link,const struct in6_addr * prefix,uint8_t prefix_len,usec_t lifetime_preferred_usec,usec_t lifetime_valid_usec)656 int radv_add_prefix(
657                 Link *link,
658                 const struct in6_addr *prefix,
659                 uint8_t prefix_len,
660                 usec_t lifetime_preferred_usec,
661                 usec_t lifetime_valid_usec) {
662 
663         _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
664         int r;
665 
666         assert(link);
667 
668         if (!link->radv)
669                 return 0;
670 
671         r = sd_radv_prefix_new(&p);
672         if (r < 0)
673                 return r;
674 
675         r = sd_radv_prefix_set_prefix(p, prefix, prefix_len);
676         if (r < 0)
677                 return r;
678 
679         r = sd_radv_prefix_set_preferred_lifetime(p, RADV_DEFAULT_PREFERRED_LIFETIME_USEC, lifetime_preferred_usec);
680         if (r < 0)
681                 return r;
682 
683         r = sd_radv_prefix_set_valid_lifetime(p, RADV_DEFAULT_VALID_LIFETIME_USEC, lifetime_valid_usec);
684         if (r < 0)
685                 return r;
686 
687         r = sd_radv_add_prefix(link->radv, p);
688         if (r < 0 && r != -EEXIST)
689                 return r;
690 
691         return 0;
692 }
693 
prefix_section_verify(Prefix * p)694 static int prefix_section_verify(Prefix *p) {
695         assert(p);
696 
697         if (section_is_invalid(p->section))
698                 return -EINVAL;
699 
700         if (in6_addr_is_null(&p->prefix))
701                 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
702                                          "%s: [IPv6Prefix] section without Prefix= field configured, "
703                                          "or specified prefix is the null address. "
704                                          "Ignoring [IPv6Prefix] section from line %u.",
705                                          p->section->filename, p->section->line);
706 
707         if (p->prefixlen < 3 || p->prefixlen > 128)
708                 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
709                                          "%s: Invalid prefix length %u is specified in [IPv6Prefix] section. "
710                                          "Valid range is 3…128. Ignoring [IPv6Prefix] section from line %u.",
711                                          p->section->filename, p->prefixlen, p->section->line);
712 
713         if (p->prefixlen > 64) {
714                 _cleanup_free_ char *str = NULL;
715 
716                 if (p->assign)
717                         (void) in6_addr_prefix_to_string(&p->prefix, p->prefixlen, &str);
718 
719                 log_info("%s: Unusual prefix length %u (> 64) is specified in [IPv6Prefix] section from line %u%s%s.",
720                          p->section->filename, p->prefixlen, p->section->line,
721                          p->assign ? ", refusing to assign an address in " : "",
722                          p->assign ? strna(str) : "");
723 
724                 p->assign = false;
725         }
726 
727         if (p->valid_lifetime == 0)
728                 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
729                                          "%s: The valid lifetime of prefix cannot be zero. "
730                                          "Ignoring [IPv6Prefix] section from line %u.",
731                                          p->section->filename, p->section->line);
732 
733         if (p->preferred_lifetime > p->valid_lifetime)
734                 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
735                                          "%s: The preferred lifetime %s is longer than the valid lifetime %s. "
736                                          "Ignoring [IPv6Prefix] section from line %u.",
737                                          p->section->filename,
738                                          FORMAT_TIMESPAN(p->preferred_lifetime, USEC_PER_SEC),
739                                          FORMAT_TIMESPAN(p->valid_lifetime, USEC_PER_SEC),
740                                          p->section->line);
741 
742         return 0;
743 }
744 
network_drop_invalid_prefixes(Network * network)745 void network_drop_invalid_prefixes(Network *network) {
746         Prefix *p;
747 
748         assert(network);
749 
750         HASHMAP_FOREACH(p, network->prefixes_by_section)
751                 if (prefix_section_verify(p) < 0)
752                         prefix_free(p);
753 }
754 
route_prefix_section_verify(RoutePrefix * p)755 static int route_prefix_section_verify(RoutePrefix *p) {
756         if (section_is_invalid(p->section))
757                 return -EINVAL;
758 
759         if (p->prefixlen > 128)
760                 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
761                                          "%s: Invalid prefix length %u is specified in [IPv6RoutePrefix] section. "
762                                          "Valid range is 0…128. Ignoring [IPv6RoutePrefix] section from line %u.",
763                                          p->section->filename, p->prefixlen, p->section->line);
764 
765         if (p->lifetime == 0)
766                 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
767                                          "%s: The lifetime of route cannot be zero. "
768                                          "Ignoring [IPv6RoutePrefix] section from line %u.",
769                                          p->section->filename, p->section->line);
770 
771         return 0;
772 }
773 
network_drop_invalid_route_prefixes(Network * network)774 void network_drop_invalid_route_prefixes(Network *network) {
775         RoutePrefix *p;
776 
777         assert(network);
778 
779         HASHMAP_FOREACH(p, network->route_prefixes_by_section)
780                 if (route_prefix_section_verify(p) < 0)
781                         route_prefix_free(p);
782 }
783 
config_parse_prefix(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)784 int config_parse_prefix(
785                 const char *unit,
786                 const char *filename,
787                 unsigned line,
788                 const char *section,
789                 unsigned section_line,
790                 const char *lvalue,
791                 int ltype,
792                 const char *rvalue,
793                 void *data,
794                 void *userdata) {
795 
796         _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
797         Network *network = userdata;
798         union in_addr_union a;
799         int r;
800 
801         assert(filename);
802         assert(section);
803         assert(lvalue);
804         assert(rvalue);
805         assert(userdata);
806 
807         r = prefix_new_static(network, filename, section_line, &p);
808         if (r < 0)
809                 return log_oom();
810 
811         r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &p->prefixlen);
812         if (r < 0) {
813                 log_syntax(unit, LOG_WARNING, filename, line, r,
814                            "Prefix is invalid, ignoring assignment: %s", rvalue);
815                 return 0;
816         }
817 
818         (void) in6_addr_mask(&a.in6, p->prefixlen);
819         p->prefix = a.in6;
820 
821         TAKE_PTR(p);
822         return 0;
823 }
824 
config_parse_prefix_boolean(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)825 int config_parse_prefix_boolean(
826                 const char *unit,
827                 const char *filename,
828                 unsigned line,
829                 const char *section,
830                 unsigned section_line,
831                 const char *lvalue,
832                 int ltype,
833                 const char *rvalue,
834                 void *data,
835                 void *userdata) {
836 
837         _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
838         Network *network = userdata;
839         int r;
840 
841         assert(filename);
842         assert(section);
843         assert(lvalue);
844         assert(rvalue);
845         assert(userdata);
846 
847         r = prefix_new_static(network, filename, section_line, &p);
848         if (r < 0)
849                 return log_oom();
850 
851         r = parse_boolean(rvalue);
852         if (r < 0) {
853                 log_syntax(unit, LOG_WARNING, filename, line, r,
854                            "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
855                 return 0;
856         }
857 
858         if (streq(lvalue, "OnLink"))
859                 p->onlink = r;
860         else if (streq(lvalue, "AddressAutoconfiguration"))
861                 p->address_auto_configuration = r;
862         else if (streq(lvalue, "Assign"))
863                 p->assign = r;
864         else
865                 assert_not_reached();
866 
867         TAKE_PTR(p);
868         return 0;
869 }
870 
config_parse_prefix_lifetime(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)871 int config_parse_prefix_lifetime(
872                 const char *unit,
873                 const char *filename,
874                 unsigned line,
875                 const char *section,
876                 unsigned section_line,
877                 const char *lvalue,
878                 int ltype,
879                 const char *rvalue,
880                 void *data,
881                 void *userdata) {
882 
883         _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
884         Network *network = userdata;
885         usec_t usec;
886         int r;
887 
888         assert(filename);
889         assert(section);
890         assert(lvalue);
891         assert(rvalue);
892         assert(userdata);
893 
894         r = prefix_new_static(network, filename, section_line, &p);
895         if (r < 0)
896                 return log_oom();
897 
898         r = parse_sec(rvalue, &usec);
899         if (r < 0) {
900                 log_syntax(unit, LOG_WARNING, filename, line, r,
901                            "Lifetime is invalid, ignoring assignment: %s", rvalue);
902                 return 0;
903         }
904 
905         if (usec != USEC_INFINITY && DIV_ROUND_UP(usec, USEC_PER_SEC) >= UINT32_MAX) {
906                 log_syntax(unit, LOG_WARNING, filename, line, 0,
907                            "Lifetime is too long, ignoring assignment: %s", rvalue);
908                 return 0;
909         }
910 
911         if (streq(lvalue, "PreferredLifetimeSec"))
912                 p->preferred_lifetime = usec;
913         else if (streq(lvalue, "ValidLifetimeSec"))
914                 p->valid_lifetime = usec;
915         else
916                 assert_not_reached();
917 
918         TAKE_PTR(p);
919         return 0;
920 }
921 
config_parse_prefix_metric(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)922 int config_parse_prefix_metric(
923                 const char *unit,
924                 const char *filename,
925                 unsigned line,
926                 const char *section,
927                 unsigned section_line,
928                 const char *lvalue,
929                 int ltype,
930                 const char *rvalue,
931                 void *data,
932                 void *userdata) {
933 
934         _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
935         Network *network = userdata;
936         int r;
937 
938         assert(filename);
939         assert(section);
940         assert(lvalue);
941         assert(rvalue);
942         assert(userdata);
943 
944         r = prefix_new_static(network, filename, section_line, &p);
945         if (r < 0)
946                 return log_oom();
947 
948         r = safe_atou32(rvalue, &p->route_metric);
949         if (r < 0) {
950                 log_syntax(unit, LOG_WARNING, filename, line, r,
951                            "Failed to parse %s=, ignoring assignment: %s",
952                            lvalue, rvalue);
953                 return 0;
954         }
955 
956         TAKE_PTR(p);
957         return 0;
958 }
959 
config_parse_prefix_token(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)960 int config_parse_prefix_token(
961                 const char *unit,
962                 const char *filename,
963                 unsigned line,
964                 const char *section,
965                 unsigned section_line,
966                 const char *lvalue,
967                 int ltype,
968                 const char *rvalue,
969                 void *data,
970                 void *userdata) {
971 
972         _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
973         Network *network = userdata;
974         int r;
975 
976         assert(filename);
977         assert(section);
978         assert(lvalue);
979         assert(rvalue);
980         assert(userdata);
981 
982         r = prefix_new_static(network, filename, section_line, &p);
983         if (r < 0)
984                 return log_oom();
985 
986         r = config_parse_address_generation_type(unit, filename, line, section, section_line,
987                                                  lvalue, ltype, rvalue, &p->tokens, userdata);
988         if (r < 0)
989                 return r;
990 
991         TAKE_PTR(p);
992         return 0;
993 }
994 
config_parse_route_prefix(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)995 int config_parse_route_prefix(
996                 const char *unit,
997                 const char *filename,
998                 unsigned line,
999                 const char *section,
1000                 unsigned section_line,
1001                 const char *lvalue,
1002                 int ltype,
1003                 const char *rvalue,
1004                 void *data,
1005                 void *userdata) {
1006 
1007         _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL;
1008         Network *network = userdata;
1009         union in_addr_union a;
1010         int r;
1011 
1012         assert(filename);
1013         assert(section);
1014         assert(lvalue);
1015         assert(rvalue);
1016         assert(userdata);
1017 
1018         r = route_prefix_new_static(network, filename, section_line, &p);
1019         if (r < 0)
1020                 return log_oom();
1021 
1022         r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &p->prefixlen);
1023         if (r < 0) {
1024                 log_syntax(unit, LOG_WARNING, filename, line, r,
1025                            "Route prefix is invalid, ignoring assignment: %s", rvalue);
1026                 return 0;
1027         }
1028 
1029         (void) in6_addr_mask(&a.in6, p->prefixlen);
1030         p->prefix = a.in6;
1031 
1032         TAKE_PTR(p);
1033         return 0;
1034 }
1035 
config_parse_route_prefix_lifetime(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1036 int config_parse_route_prefix_lifetime(
1037                 const char *unit,
1038                 const char *filename,
1039                 unsigned line,
1040                 const char *section,
1041                 unsigned section_line,
1042                 const char *lvalue,
1043                 int ltype,
1044                 const char *rvalue,
1045                 void *data,
1046                 void *userdata) {
1047 
1048         _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL;
1049         Network *network = userdata;
1050         usec_t usec;
1051         int r;
1052 
1053         assert(filename);
1054         assert(section);
1055         assert(lvalue);
1056         assert(rvalue);
1057         assert(userdata);
1058 
1059         r = route_prefix_new_static(network, filename, section_line, &p);
1060         if (r < 0)
1061                 return log_oom();
1062 
1063         r = parse_sec(rvalue, &usec);
1064         if (r < 0) {
1065                 log_syntax(unit, LOG_WARNING, filename, line, r,
1066                            "Route lifetime is invalid, ignoring assignment: %s", rvalue);
1067                 return 0;
1068         }
1069 
1070         if (usec != USEC_INFINITY && DIV_ROUND_UP(usec, USEC_PER_SEC) >= UINT32_MAX) {
1071                 log_syntax(unit, LOG_WARNING, filename, line, 0,
1072                            "Lifetime is too long, ignoring assignment: %s", rvalue);
1073                 return 0;
1074         }
1075 
1076         p->lifetime = usec;
1077 
1078         TAKE_PTR(p);
1079         return 0;
1080 }
1081 
config_parse_radv_dns(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1082 int config_parse_radv_dns(
1083                 const char *unit,
1084                 const char *filename,
1085                 unsigned line,
1086                 const char *section,
1087                 unsigned section_line,
1088                 const char *lvalue,
1089                 int ltype,
1090                 const char *rvalue,
1091                 void *data,
1092                 void *userdata) {
1093 
1094         Network *n = data;
1095         int r;
1096 
1097         assert(filename);
1098         assert(lvalue);
1099         assert(rvalue);
1100 
1101         if (isempty(rvalue)) {
1102                 n->n_router_dns = 0;
1103                 n->router_dns = mfree(n->router_dns);
1104                 return 0;
1105         }
1106 
1107         for (const char *p = rvalue;;) {
1108                 _cleanup_free_ char *w = NULL;
1109                 union in_addr_union a;
1110 
1111                 r = extract_first_word(&p, &w, NULL, 0);
1112                 if (r == -ENOMEM)
1113                         return log_oom();
1114                 if (r < 0) {
1115                         log_syntax(unit, LOG_WARNING, filename, line, r,
1116                                    "Failed to extract word, ignoring: %s", rvalue);
1117                         return 0;
1118                 }
1119                 if (r == 0)
1120                         return 0;
1121 
1122                 if (streq(w, "_link_local"))
1123                         a = IN_ADDR_NULL;
1124                 else {
1125                         r = in_addr_from_string(AF_INET6, w, &a);
1126                         if (r < 0) {
1127                                 log_syntax(unit, LOG_WARNING, filename, line, r,
1128                                            "Failed to parse DNS server address, ignoring: %s", w);
1129                                 continue;
1130                         }
1131 
1132                         if (in_addr_is_null(AF_INET6, &a)) {
1133                                 log_syntax(unit, LOG_WARNING, filename, line, 0,
1134                                            "DNS server address is null, ignoring: %s", w);
1135                                 continue;
1136                         }
1137                 }
1138 
1139                 struct in6_addr *m;
1140                 m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
1141                 if (!m)
1142                         return log_oom();
1143 
1144                 m[n->n_router_dns++] = a.in6;
1145                 n->router_dns = m;
1146         }
1147 }
1148 
config_parse_radv_search_domains(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1149 int config_parse_radv_search_domains(
1150                 const char *unit,
1151                 const char *filename,
1152                 unsigned line,
1153                 const char *section,
1154                 unsigned section_line,
1155                 const char *lvalue,
1156                 int ltype,
1157                 const char *rvalue,
1158                 void *data,
1159                 void *userdata) {
1160 
1161         Network *n = data;
1162         int r;
1163 
1164         assert(filename);
1165         assert(lvalue);
1166         assert(rvalue);
1167 
1168         if (isempty(rvalue)) {
1169                 n->router_search_domains = ordered_set_free(n->router_search_domains);
1170                 return 0;
1171         }
1172 
1173         for (const char *p = rvalue;;) {
1174                 _cleanup_free_ char *w = NULL, *idna = NULL;
1175 
1176                 r = extract_first_word(&p, &w, NULL, 0);
1177                 if (r == -ENOMEM)
1178                         return log_oom();
1179                 if (r < 0) {
1180                         log_syntax(unit, LOG_WARNING, filename, line, r,
1181                                    "Failed to extract word, ignoring: %s", rvalue);
1182                         return 0;
1183                 }
1184                 if (r == 0)
1185                         return 0;
1186 
1187                 r = dns_name_apply_idna(w, &idna);
1188                 if (r < 0) {
1189                         log_syntax(unit, LOG_WARNING, filename, line, r,
1190                                    "Failed to apply IDNA to domain name '%s', ignoring: %m", w);
1191                         continue;
1192                 } else if (r == 0)
1193                         /* transfer ownership to simplify subsequent operations */
1194                         idna = TAKE_PTR(w);
1195 
1196                 r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops_free);
1197                 if (r < 0)
1198                         return log_oom();
1199 
1200                 r = ordered_set_consume(n->router_search_domains, TAKE_PTR(idna));
1201                 if (r < 0)
1202                         return log_oom();
1203         }
1204 }
1205 
1206 static const char * const radv_prefix_delegation_table[_RADV_PREFIX_DELEGATION_MAX] = {
1207         [RADV_PREFIX_DELEGATION_NONE]   = "no",
1208         [RADV_PREFIX_DELEGATION_STATIC] = "static",
1209         [RADV_PREFIX_DELEGATION_DHCP6]  = "dhcpv6",
1210         [RADV_PREFIX_DELEGATION_BOTH]   = "yes",
1211 };
1212 
1213 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(
1214                 radv_prefix_delegation,
1215                 RADVPrefixDelegation,
1216                 RADV_PREFIX_DELEGATION_BOTH);
1217 
config_parse_router_prefix_delegation(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1218 int config_parse_router_prefix_delegation(
1219                 const char *unit,
1220                 const char *filename,
1221                 unsigned line,
1222                 const char *section,
1223                 unsigned section_line,
1224                 const char *lvalue,
1225                 int ltype,
1226                 const char *rvalue,
1227                 void *data,
1228                 void *userdata) {
1229 
1230         RADVPrefixDelegation val, *ra = data;
1231         int r;
1232 
1233         assert(filename);
1234         assert(lvalue);
1235         assert(rvalue);
1236         assert(data);
1237 
1238         if (streq(lvalue, "IPv6SendRA")) {
1239                 r = parse_boolean(rvalue);
1240                 if (r < 0) {
1241                         log_syntax(unit, LOG_WARNING, filename, line, r,
1242                                    "Invalid %s= setting, ignoring assignment: %s", lvalue, rvalue);
1243                         return 0;
1244                 }
1245 
1246                 /* When IPv6SendRA= is enabled, only static prefixes are sent by default, and users
1247                  * need to explicitly enable DHCPv6PrefixDelegation=. */
1248                 *ra = r ? RADV_PREFIX_DELEGATION_STATIC : RADV_PREFIX_DELEGATION_NONE;
1249                 return 0;
1250         }
1251 
1252         /* For backward compatibility */
1253         val = radv_prefix_delegation_from_string(rvalue);
1254         if (val < 0) {
1255                 log_syntax(unit, LOG_WARNING, filename, line, val,
1256                            "Invalid %s= setting, ignoring assignment: %s", lvalue, rvalue);
1257                 return 0;
1258         }
1259 
1260         *ra = val;
1261         return 0;
1262 }
1263 
config_parse_router_lifetime(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1264 int config_parse_router_lifetime(
1265                 const char *unit,
1266                 const char *filename,
1267                 unsigned line,
1268                 const char *section,
1269                 unsigned section_line,
1270                 const char *lvalue,
1271                 int ltype,
1272                 const char *rvalue,
1273                 void *data,
1274                 void *userdata) {
1275 
1276         usec_t usec, *lifetime = data;
1277         int r;
1278 
1279         assert(filename);
1280         assert(section);
1281         assert(lvalue);
1282         assert(rvalue);
1283         assert(data);
1284 
1285         if (isempty(rvalue)) {
1286                 *lifetime = RADV_DEFAULT_ROUTER_LIFETIME_USEC;
1287                 return 0;
1288         }
1289 
1290         r = parse_sec(rvalue, &usec);
1291         if (r < 0) {
1292                 log_syntax(unit, LOG_WARNING, filename, line, r,
1293                            "Failed to parse router lifetime, ignoring assignment: %s", rvalue);
1294                 return 0;
1295         }
1296         if (usec > 0) {
1297                 if (usec < RADV_MIN_ROUTER_LIFETIME_USEC) {
1298                         log_syntax(unit, LOG_WARNING, filename, line, 0,
1299                                    "Router lifetime %s is too short, using %s.",
1300                                    FORMAT_TIMESPAN(usec, USEC_PER_SEC),
1301                                    FORMAT_TIMESPAN(RADV_MIN_ROUTER_LIFETIME_USEC, USEC_PER_SEC));
1302                         usec = RADV_MIN_ROUTER_LIFETIME_USEC;
1303                 } else if (usec > RADV_MAX_ROUTER_LIFETIME_USEC) {
1304                         log_syntax(unit, LOG_WARNING, filename, line, 0,
1305                                    "Router lifetime %s is too large, using %s.",
1306                                    FORMAT_TIMESPAN(usec, USEC_PER_SEC),
1307                                    FORMAT_TIMESPAN(RADV_MAX_ROUTER_LIFETIME_USEC, USEC_PER_SEC));
1308                         usec = RADV_MAX_ROUTER_LIFETIME_USEC;
1309                 }
1310         }
1311 
1312         *lifetime = usec;
1313         return 0;
1314 }
1315 
config_parse_router_preference(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1316 int config_parse_router_preference(
1317                 const char *unit,
1318                 const char *filename,
1319                 unsigned line,
1320                 const char *section,
1321                 unsigned section_line,
1322                 const char *lvalue,
1323                 int ltype,
1324                 const char *rvalue,
1325                 void *data,
1326                 void *userdata) {
1327 
1328         Network *network = userdata;
1329 
1330         assert(filename);
1331         assert(section);
1332         assert(lvalue);
1333         assert(rvalue);
1334         assert(data);
1335 
1336         if (streq(rvalue, "high"))
1337                 network->router_preference = SD_NDISC_PREFERENCE_HIGH;
1338         else if (STR_IN_SET(rvalue, "medium", "normal", "default"))
1339                 network->router_preference = SD_NDISC_PREFERENCE_MEDIUM;
1340         else if (streq(rvalue, "low"))
1341                 network->router_preference = SD_NDISC_PREFERENCE_LOW;
1342         else
1343                 log_syntax(unit, LOG_WARNING, filename, line, 0,
1344                            "Invalid router preference, ignoring assignment: %s", rvalue);
1345 
1346         return 0;
1347 }
1348