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