]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-radv.c
network: use string_hash_ops_free for search domains
[thirdparty/systemd.git] / src / network / networkd-radv.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
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"
b5ce4047 10#include "networkd-link.h"
c555a358 11#include "networkd-manager.h"
b5ce4047 12#include "networkd-network.h"
091214b6 13#include "networkd-radv.h"
6e849e95 14#include "parse-util.h"
6e849e95 15#include "string-util.h"
6b1dec66 16#include "string-table.h"
51517f9e 17#include "strv.h"
6e849e95 18
064dfb05 19Prefix *prefix_free(Prefix *prefix) {
6e849e95 20 if (!prefix)
064dfb05 21 return NULL;
6e849e95
PF
22
23 if (prefix->network) {
ecb0e85e
YW
24 assert(prefix->section);
25 hashmap_remove(prefix->network->prefixes_by_section, prefix->section);
6e849e95
PF
26 }
27
ecee0abe 28 network_config_section_free(prefix->section);
471e126b 29 sd_radv_prefix_unref(prefix->radv_prefix);
6e849e95 30
064dfb05 31 return mfree(prefix);
6e849e95
PF
32}
33
064dfb05
YW
34DEFINE_NETWORK_SECTION_FUNCTIONS(Prefix, prefix_free);
35
95081e08 36static int prefix_new(Prefix **ret) {
15b8332e 37 _cleanup_(prefix_freep) Prefix *prefix = NULL;
6e849e95
PF
38
39 prefix = new0(Prefix, 1);
40 if (!prefix)
41 return -ENOMEM;
42
43 if (sd_radv_prefix_new(&prefix->radv_prefix) < 0)
44 return -ENOMEM;
45
ae2a15bc 46 *ret = TAKE_PTR(prefix);
6e849e95
PF
47
48 return 0;
49}
50
a8d4a210 51static int prefix_new_static(Network *network, const char *filename, unsigned section_line, Prefix **ret) {
8e766630
LP
52 _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
53 _cleanup_(prefix_freep) Prefix *prefix = NULL;
6e849e95
PF
54 int r;
55
56 assert(network);
57 assert(ret);
ecb0e85e
YW
58 assert(filename);
59 assert(section_line > 0);
6e849e95 60
ecb0e85e
YW
61 r = network_config_section_new(filename, section_line, &n);
62 if (r < 0)
63 return r;
6e849e95 64
ecb0e85e
YW
65 prefix = hashmap_get(network->prefixes_by_section, n);
66 if (prefix) {
67 *ret = TAKE_PTR(prefix);
68 return 0;
6e849e95
PF
69 }
70
71 r = prefix_new(&prefix);
72 if (r < 0)
73 return r;
74
0f7f2769 75 prefix->network = network;
ecb0e85e 76 prefix->section = TAKE_PTR(n);
6e849e95 77
ecb0e85e
YW
78 r = hashmap_ensure_allocated(&network->prefixes_by_section, &network_config_hash_ops);
79 if (r < 0)
80 return r;
3e570042 81
ecb0e85e
YW
82 r = hashmap_put(network->prefixes_by_section, prefix->section, prefix);
83 if (r < 0)
84 return r;
6e849e95 85
1cc6c93a 86 *ret = TAKE_PTR(prefix);
6e849e95
PF
87
88 return 0;
89}
90
064dfb05 91RoutePrefix *route_prefix_free(RoutePrefix *prefix) {
203d4df5 92 if (!prefix)
064dfb05 93 return NULL;
203d4df5
SS
94
95 if (prefix->network) {
ecb0e85e
YW
96 assert(prefix->section);
97 hashmap_remove(prefix->network->route_prefixes_by_section, prefix->section);
203d4df5
SS
98 }
99
100 network_config_section_free(prefix->section);
471e126b 101 sd_radv_route_prefix_unref(prefix->radv_route_prefix);
203d4df5 102
064dfb05
YW
103 return mfree(prefix);
104}
105
106DEFINE_NETWORK_SECTION_FUNCTIONS(RoutePrefix, route_prefix_free);
107
108static int route_prefix_new(RoutePrefix **ret) {
109 _cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL;
110
111 prefix = new0(RoutePrefix, 1);
112 if (!prefix)
113 return -ENOMEM;
114
115 if (sd_radv_route_prefix_new(&prefix->radv_route_prefix) < 0)
116 return -ENOMEM;
117
118 *ret = TAKE_PTR(prefix);
119
120 return 0;
203d4df5
SS
121}
122
a8d4a210 123static int route_prefix_new_static(Network *network, const char *filename, unsigned section_line, RoutePrefix **ret) {
203d4df5 124 _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
95081e08 125 _cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL;
203d4df5
SS
126 int r;
127
128 assert(network);
129 assert(ret);
ecb0e85e
YW
130 assert(filename);
131 assert(section_line > 0);
203d4df5 132
ecb0e85e
YW
133 r = network_config_section_new(filename, section_line, &n);
134 if (r < 0)
135 return r;
203d4df5 136
ecb0e85e
YW
137 prefix = hashmap_get(network->route_prefixes_by_section, n);
138 if (prefix) {
139 *ret = TAKE_PTR(prefix);
140 return 0;
203d4df5
SS
141 }
142
143 r = route_prefix_new(&prefix);
144 if (r < 0)
145 return r;
146
147 prefix->network = network;
ecb0e85e 148 prefix->section = TAKE_PTR(n);
203d4df5 149
ecb0e85e
YW
150 r = hashmap_ensure_allocated(&network->route_prefixes_by_section, &network_config_hash_ops);
151 if (r < 0)
152 return r;
203d4df5 153
ecb0e85e
YW
154 r = hashmap_put(network->route_prefixes_by_section, prefix->section, prefix);
155 if (r < 0)
156 return r;
203d4df5
SS
157
158 *ret = TAKE_PTR(prefix);
159
160 return 0;
161}
162
13ffa39f 163void network_drop_invalid_prefixes(Network *network) {
1a7deb2f
YW
164 Prefix *prefix;
165
166 assert(network);
167
168 HASHMAP_FOREACH(prefix, network->prefixes_by_section)
169 if (section_is_invalid(prefix->section))
170 prefix_free(prefix);
171}
172
13ffa39f 173void network_drop_invalid_route_prefixes(Network *network) {
1a7deb2f
YW
174 RoutePrefix *prefix;
175
176 assert(network);
177
178 HASHMAP_FOREACH(prefix, network->route_prefixes_by_section)
179 if (section_is_invalid(prefix->section))
180 route_prefix_free(prefix);
181}
182
a8d4a210
YW
183int config_parse_prefix(
184 const char *unit,
185 const char *filename,
186 unsigned line,
187 const char *section,
188 unsigned section_line,
189 const char *lvalue,
190 int ltype,
191 const char *rvalue,
192 void *data,
193 void *userdata) {
6e849e95
PF
194
195 Network *network = userdata;
fcbf4cb7 196 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
6e849e95
PF
197 uint8_t prefixlen = 64;
198 union in_addr_union in6addr;
199 int r;
200
201 assert(filename);
202 assert(section);
203 assert(lvalue);
204 assert(rvalue);
205 assert(data);
206
207 r = prefix_new_static(network, filename, section_line, &p);
208 if (r < 0)
d96edb2c 209 return log_oom();
6e849e95
PF
210
211 r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen);
212 if (r < 0) {
d96edb2c 213 log_syntax(unit, LOG_WARNING, filename, line, r, "Prefix is invalid, ignoring assignment: %s", rvalue);
6e849e95
PF
214 return 0;
215 }
216
c9778516
YW
217 r = sd_radv_prefix_set_prefix(p->radv_prefix, &in6addr.in6, prefixlen);
218 if (r < 0) {
219 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set radv prefix, ignoring assignment: %s", rvalue);
220 return 0;
221 }
6e849e95
PF
222
223 p = NULL;
224
225 return 0;
226}
227
a8d4a210
YW
228int config_parse_prefix_flags(
229 const char *unit,
230 const char *filename,
231 unsigned line,
232 const char *section,
233 unsigned section_line,
234 const char *lvalue,
235 int ltype,
236 const char *rvalue,
237 void *data,
238 void *userdata) {
239
6e849e95 240 Network *network = userdata;
fcbf4cb7 241 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
c9778516 242 int r;
6e849e95
PF
243
244 assert(filename);
245 assert(section);
246 assert(lvalue);
247 assert(rvalue);
248 assert(data);
249
250 r = prefix_new_static(network, filename, section_line, &p);
251 if (r < 0)
d96edb2c 252 return log_oom();
6e849e95
PF
253
254 r = parse_boolean(rvalue);
255 if (r < 0) {
c9778516 256 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
6e849e95
PF
257 return 0;
258 }
259
6e849e95 260 if (streq(lvalue, "OnLink"))
c9778516 261 r = sd_radv_prefix_set_onlink(p->radv_prefix, r);
6e849e95 262 else if (streq(lvalue, "AddressAutoconfiguration"))
c9778516
YW
263 r = sd_radv_prefix_set_address_autoconfiguration(p->radv_prefix, r);
264 if (r < 0) {
265 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set %s=, ignoring assignment: %m", lvalue);
266 return 0;
267 }
6e849e95
PF
268
269 p = NULL;
270
271 return 0;
272}
273
a8d4a210
YW
274int config_parse_prefix_lifetime(
275 const char *unit,
276 const char *filename,
277 unsigned line,
278 const char *section,
279 unsigned section_line,
280 const char *lvalue,
281 int ltype,
282 const char *rvalue,
283 void *data,
284 void *userdata) {
285
6e849e95 286 Network *network = userdata;
fcbf4cb7 287 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
6e849e95
PF
288 usec_t usec;
289 int r;
290
291 assert(filename);
292 assert(section);
293 assert(lvalue);
294 assert(rvalue);
295 assert(data);
296
297 r = prefix_new_static(network, filename, section_line, &p);
298 if (r < 0)
d96edb2c 299 return log_oom();
6e849e95
PF
300
301 r = parse_sec(rvalue, &usec);
302 if (r < 0) {
d96edb2c 303 log_syntax(unit, LOG_WARNING, filename, line, r, "Lifetime is invalid, ignoring assignment: %s", rvalue);
6e849e95
PF
304 return 0;
305 }
306
307 /* a value of 0xffffffff represents infinity */
308 if (streq(lvalue, "PreferredLifetimeSec"))
309 r = sd_radv_prefix_set_preferred_lifetime(p->radv_prefix,
310 DIV_ROUND_UP(usec, USEC_PER_SEC));
311 else if (streq(lvalue, "ValidLifetimeSec"))
312 r = sd_radv_prefix_set_valid_lifetime(p->radv_prefix,
313 DIV_ROUND_UP(usec, USEC_PER_SEC));
c9778516
YW
314 if (r < 0) {
315 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set %s=, ignoring assignment: %m", lvalue);
316 return 0;
317 }
6e849e95
PF
318
319 p = NULL;
320
321 return 0;
322}
091214b6 323
bd6379ec
SS
324int config_parse_prefix_assign(
325 const char *unit,
326 const char *filename,
327 unsigned line,
328 const char *section,
329 unsigned section_line,
330 const char *lvalue,
331 int ltype,
332 const char *rvalue,
333 void *data,
334 void *userdata) {
335
336 Network *network = userdata;
337 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
338 int r;
339
340 assert(filename);
341 assert(section);
342 assert(lvalue);
343 assert(rvalue);
344 assert(data);
345
346 r = prefix_new_static(network, filename, section_line, &p);
347 if (r < 0)
d96edb2c 348 return log_oom();
bd6379ec
SS
349
350 r = parse_boolean(rvalue);
351 if (r < 0) {
d96edb2c 352 log_syntax(unit, LOG_WARNING, filename, line, r,
bd6379ec
SS
353 "Failed to parse %s=, ignoring assignment: %s",
354 lvalue, rvalue);
355 return 0;
356 }
357
358 p->assign = r;
359 p = NULL;
360
361 return 0;
362}
363
a8d4a210
YW
364int config_parse_route_prefix(
365 const char *unit,
366 const char *filename,
367 unsigned line,
368 const char *section,
369 unsigned section_line,
370 const char *lvalue,
371 int ltype,
372 const char *rvalue,
373 void *data,
374 void *userdata) {
203d4df5
SS
375
376 Network *network = userdata;
95081e08 377 _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL;
203d4df5
SS
378 uint8_t prefixlen = 64;
379 union in_addr_union in6addr;
380 int r;
381
382 assert(filename);
383 assert(section);
384 assert(lvalue);
385 assert(rvalue);
386 assert(data);
387
388 r = route_prefix_new_static(network, filename, section_line, &p);
389 if (r < 0)
d96edb2c 390 return log_oom();
203d4df5
SS
391
392 r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen);
393 if (r < 0) {
d96edb2c 394 log_syntax(unit, LOG_WARNING, filename, line, r, "Route prefix is invalid, ignoring assignment: %s", rvalue);
203d4df5
SS
395 return 0;
396 }
397
c9778516
YW
398 r = sd_radv_prefix_set_route_prefix(p->radv_route_prefix, &in6addr.in6, prefixlen);
399 if (r < 0) {
400 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set route prefix, ignoring assignment: %m");
401 return 0;
402 }
203d4df5
SS
403
404 p = NULL;
405
406 return 0;
407}
408
a8d4a210
YW
409int config_parse_route_prefix_lifetime(
410 const char *unit,
411 const char *filename,
412 unsigned line,
413 const char *section,
414 unsigned section_line,
415 const char *lvalue,
416 int ltype,
417 const char *rvalue,
418 void *data,
419 void *userdata) {
420
203d4df5 421 Network *network = userdata;
95081e08 422 _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL;
203d4df5
SS
423 usec_t usec;
424 int r;
425
426 assert(filename);
427 assert(section);
428 assert(lvalue);
429 assert(rvalue);
430 assert(data);
431
432 r = route_prefix_new_static(network, filename, section_line, &p);
433 if (r < 0)
d96edb2c 434 return log_oom();
203d4df5
SS
435
436 r = parse_sec(rvalue, &usec);
437 if (r < 0) {
d96edb2c 438 log_syntax(unit, LOG_WARNING, filename, line, r,
095b3a7d 439 "Route lifetime is invalid, ignoring assignment: %s", rvalue);
203d4df5
SS
440 return 0;
441 }
442
443 /* a value of 0xffffffff represents infinity */
444 r = sd_radv_route_prefix_set_lifetime(p->radv_route_prefix, DIV_ROUND_UP(usec, USEC_PER_SEC));
c9778516
YW
445 if (r < 0) {
446 log_syntax(unit, LOG_WARNING, filename, line, r,
447 "Failed to set route lifetime, ignoring assignment: %m");
448 return 0;
449 }
203d4df5
SS
450
451 p = NULL;
452
453 return 0;
454}
455
be023c67 456static int network_get_ipv6_dns(Network *network, struct in6_addr **ret_addresses, size_t *ret_size) {
c555a358 457 _cleanup_free_ struct in6_addr *addresses = NULL;
be023c67 458 size_t n_addresses = 0, n_allocated = 0;
c555a358
PF
459
460 assert(network);
be023c67
YW
461 assert(ret_addresses);
462 assert(ret_size);
c555a358 463
be023c67 464 for (size_t i = 0; i < network->n_dns; i++) {
c555a358
PF
465 union in_addr_union *addr;
466
e77bd3fd 467 if (network->dns[i]->family != AF_INET6)
c555a358
PF
468 continue;
469
e77bd3fd 470 addr = &network->dns[i]->address;
c555a358
PF
471
472 if (in_addr_is_null(AF_INET6, addr) ||
473 in_addr_is_link_local(AF_INET6, addr) ||
474 in_addr_is_localhost(AF_INET6, addr))
475 continue;
476
477 if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1))
478 return -ENOMEM;
479
480 addresses[n_addresses++] = addr->in6;
481 }
482
be023c67
YW
483 *ret_addresses = TAKE_PTR(addresses);
484 *ret_size = n_addresses;
c555a358
PF
485
486 return n_addresses;
487}
488
489static int radv_set_dns(Link *link, Link *uplink) {
490 _cleanup_free_ struct in6_addr *dns = NULL;
c555a358 491 usec_t lifetime_usec;
fd3ef936 492 size_t n_dns;
c555a358
PF
493 int r;
494
495 if (!link->network->router_emit_dns)
496 return 0;
497
498 if (link->network->router_dns) {
fd3ef936
YW
499 struct in6_addr *p;
500
501 dns = new(struct in6_addr, link->network->n_router_dns);
4e361acc 502 if (!dns)
c555a358
PF
503 return -ENOMEM;
504
fd3ef936
YW
505 p = dns;
506 for (size_t i = 0; i < link->network->n_router_dns; i++)
507 if (IN6_IS_ADDR_UNSPECIFIED(&link->network->router_dns[i])) {
508 if (!IN6_IS_ADDR_UNSPECIFIED(&link->ipv6ll_address))
509 *(p++) = link->ipv6ll_address;
510 } else
511 *(p++) = link->network->router_dns[i];
512
513 n_dns = p - dns;
c555a358
PF
514 lifetime_usec = link->network->router_dns_lifetime_usec;
515
516 goto set_dns;
517 }
518
519 lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC;
520
be023c67 521 r = network_get_ipv6_dns(link->network, &dns, &n_dns);
c555a358
PF
522 if (r > 0)
523 goto set_dns;
524
525 if (uplink) {
4e361acc 526 if (!uplink->network) {
349a981d
PF
527 log_link_debug(uplink, "Cannot fetch DNS servers as uplink interface is not managed by us");
528 return 0;
529 }
530
be023c67 531 r = network_get_ipv6_dns(uplink->network, &dns, &n_dns);
c555a358
PF
532 if (r > 0)
533 goto set_dns;
534 }
535
536 return 0;
537
538 set_dns:
539 return sd_radv_set_rdnss(link->radv,
540 DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC),
541 dns, n_dns);
542}
543
544static int radv_set_domains(Link *link, Link *uplink) {
5e2a51d5 545 OrderedSet *search_domains;
c555a358 546 usec_t lifetime_usec;
5e2a51d5 547 _cleanup_free_ char **s = NULL; /* just free() because the strings are owned by the set */
c555a358
PF
548
549 if (!link->network->router_emit_domains)
550 return 0;
551
552 search_domains = link->network->router_search_domains;
553 lifetime_usec = link->network->router_dns_lifetime_usec;
554
555 if (search_domains)
556 goto set_domains;
557
558 lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC;
559
560 search_domains = link->network->search_domains;
561 if (search_domains)
562 goto set_domains;
563
564 if (uplink) {
4e361acc 565 if (!uplink->network) {
349a981d
PF
566 log_link_debug(uplink, "Cannot fetch DNS search domains as uplink interface is not managed by us");
567 return 0;
568 }
569
c555a358
PF
570 search_domains = uplink->network->search_domains;
571 if (search_domains)
572 goto set_domains;
573 }
574
575 return 0;
576
577 set_domains:
5e2a51d5
ZJS
578 s = ordered_set_get_strv(search_domains);
579 if (!s)
580 return log_oom();
581
c555a358
PF
582 return sd_radv_set_dnssl(link->radv,
583 DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC),
5e2a51d5 584 s);
c555a358
PF
585
586}
587
588int radv_emit_dns(Link *link) {
589 Link *uplink;
590 int r;
591
592 uplink = manager_find_uplink(link->manager, link);
593
594 r = radv_set_dns(link, uplink);
595 if (r < 0)
596 log_link_warning_errno(link, r, "Could not set RA DNS: %m");
597
598 r = radv_set_domains(link, uplink);
599 if (r < 0)
600 log_link_warning_errno(link, r, "Could not set RA Domains: %m");
601
602 return 0;
603}
604
086b8853
YW
605static bool link_radv_enabled(Link *link) {
606 assert(link);
607
608 if (!link_ipv6ll_enabled(link))
609 return false;
610
611 return link->network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE;
612}
613
091214b6 614int radv_configure(Link *link) {
95081e08 615 int r;
091214b6
PF
616
617 assert(link);
618 assert(link->network);
619
086b8853
YW
620 if (!link_radv_enabled(link))
621 return 0;
622
091214b6
PF
623 r = sd_radv_new(&link->radv);
624 if (r < 0)
625 return r;
626
4cf85000 627 r = sd_radv_attach_event(link->radv, link->manager->event, 0);
091214b6
PF
628 if (r < 0)
629 return r;
630
631 r = sd_radv_set_mac(link->radv, &link->mac);
632 if (r < 0)
633 return r;
634
635 r = sd_radv_set_ifindex(link->radv, link->ifindex);
636 if (r < 0)
637 return r;
638
639 r = sd_radv_set_managed_information(link->radv, link->network->router_managed);
640 if (r < 0)
641 return r;
642
643 r = sd_radv_set_other_information(link->radv, link->network->router_other_information);
644 if (r < 0)
645 return r;
646
301a2fb9
PF
647 /* a value of 0xffffffff represents infinity, 0x0 means this host is
648 not a router */
091214b6 649 r = sd_radv_set_router_lifetime(link->radv,
945e3225 650 DIV_ROUND_UP(link->network->router_lifetime_usec, USEC_PER_SEC));
091214b6
PF
651 if (r < 0)
652 return r;
653
654 if (link->network->router_lifetime_usec > 0) {
655 r = sd_radv_set_preference(link->radv,
656 link->network->router_preference);
657 if (r < 0)
658 return r;
659 }
660
61c0ef4f 661 if (link->network->router_prefix_delegation & RADV_PREFIX_DELEGATION_STATIC) {
ecb0e85e
YW
662 RoutePrefix *q;
663 Prefix *p;
664
665 HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
d601b566 666 r = sd_radv_add_prefix(link->radv, p->radv_prefix, false);
59ea6e57
LP
667 if (r == -EEXIST)
668 continue;
669 if (r == -ENOEXEC) {
670 log_link_warning_errno(link, r, "[IPv6Prefix] section configured without Prefix= setting, ignoring section.");
671 continue;
672 }
673 if (r < 0)
56a23cb4
PF
674 return r;
675 }
203d4df5 676
ecb0e85e 677 HASHMAP_FOREACH(q, link->network->route_prefixes_by_section) {
95081e08 678 r = sd_radv_add_route_prefix(link->radv, q->radv_route_prefix, false);
203d4df5
SS
679 if (r == -EEXIST)
680 continue;
681 if (r < 0)
682 return r;
683 }
091214b6
PF
684 }
685
fd3ef936 686 return 0;
091214b6 687}
ca5ad760 688
be9363cc
YW
689int radv_update_mac(Link *link) {
690 bool restart;
691 int r;
692
693 assert(link);
694
695 if (!link->radv)
696 return 0;
697
698 restart = sd_radv_is_running(link->radv);
699
700 if (restart) {
701 r = sd_radv_stop(link->radv);
702 if (r < 0)
703 return r;
704 }
705
706 r = sd_radv_set_mac(link->radv, &link->mac);
707 if (r < 0)
708 return r;
709
710 if (restart) {
711 r = sd_radv_start(link->radv);
712 if (r < 0)
713 return r;
714 }
715
716 return 0;
717}
718
a8d4a210
YW
719int radv_add_prefix(
720 Link *link,
721 const struct in6_addr *prefix,
722 uint8_t prefix_len,
723 uint32_t lifetime_preferred,
724 uint32_t lifetime_valid) {
725
1d596fde
YW
726 _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
727 int r;
728
729 assert(link);
85b6a811
YW
730
731 if (!link->radv)
732 return 0;
1d596fde
YW
733
734 r = sd_radv_prefix_new(&p);
735 if (r < 0)
736 return r;
737
738 r = sd_radv_prefix_set_prefix(p, prefix, prefix_len);
739 if (r < 0)
740 return r;
741
742 r = sd_radv_prefix_set_preferred_lifetime(p, lifetime_preferred);
743 if (r < 0)
744 return r;
745
746 r = sd_radv_prefix_set_valid_lifetime(p, lifetime_valid);
747 if (r < 0)
748 return r;
749
750 r = sd_radv_add_prefix(link->radv, p, true);
751 if (r < 0 && r != -EEXIST)
752 return r;
753
754 return 0;
755}
756
ca5ad760
YW
757int config_parse_radv_dns(
758 const char *unit,
759 const char *filename,
760 unsigned line,
761 const char *section,
762 unsigned section_line,
763 const char *lvalue,
764 int ltype,
765 const char *rvalue,
766 void *data,
767 void *userdata) {
768
769 Network *n = data;
ca5ad760
YW
770 int r;
771
772 assert(filename);
773 assert(lvalue);
774 assert(rvalue);
775
d96edb2c 776 for (const char *p = rvalue;;) {
ca5ad760
YW
777 _cleanup_free_ char *w = NULL;
778 union in_addr_union a;
779
780 r = extract_first_word(&p, &w, NULL, 0);
781 if (r == -ENOMEM)
782 return log_oom();
783 if (r < 0) {
d96edb2c 784 log_syntax(unit, LOG_WARNING, filename, line, r,
ca5ad760
YW
785 "Failed to extract word, ignoring: %s", rvalue);
786 return 0;
787 }
788 if (r == 0)
d96edb2c 789 return 0;
ca5ad760 790
fd3ef936
YW
791 if (streq(w, "_link_local"))
792 a = IN_ADDR_NULL;
793 else {
794 r = in_addr_from_string(AF_INET6, w, &a);
795 if (r < 0) {
d96edb2c 796 log_syntax(unit, LOG_WARNING, filename, line, r,
fd3ef936
YW
797 "Failed to parse DNS server address, ignoring: %s", w);
798 continue;
799 }
ca5ad760 800
fd3ef936 801 if (in_addr_is_null(AF_INET6, &a)) {
d96edb2c 802 log_syntax(unit, LOG_WARNING, filename, line, 0,
fd3ef936
YW
803 "DNS server address is null, ignoring: %s", w);
804 continue;
805 }
806 }
ca5ad760 807
fd3ef936
YW
808 struct in6_addr *m;
809 m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
810 if (!m)
811 return log_oom();
ca5ad760 812
fd3ef936
YW
813 m[n->n_router_dns++] = a.in6;
814 n->router_dns = m;
ca5ad760 815 }
ca5ad760
YW
816}
817
818int config_parse_radv_search_domains(
819 const char *unit,
820 const char *filename,
821 unsigned line,
822 const char *section,
823 unsigned section_line,
824 const char *lvalue,
825 int ltype,
826 const char *rvalue,
827 void *data,
828 void *userdata) {
829
830 Network *n = data;
ca5ad760
YW
831 int r;
832
833 assert(filename);
834 assert(lvalue);
835 assert(rvalue);
836
d96edb2c 837 for (const char *p = rvalue;;) {
ca5ad760
YW
838 _cleanup_free_ char *w = NULL, *idna = NULL;
839
840 r = extract_first_word(&p, &w, NULL, 0);
841 if (r == -ENOMEM)
842 return log_oom();
843 if (r < 0) {
d96edb2c 844 log_syntax(unit, LOG_WARNING, filename, line, r,
ca5ad760
YW
845 "Failed to extract word, ignoring: %s", rvalue);
846 return 0;
847 }
848 if (r == 0)
d96edb2c 849 return 0;
ca5ad760
YW
850
851 r = dns_name_apply_idna(w, &idna);
852 if (r < 0) {
d96edb2c 853 log_syntax(unit, LOG_WARNING, filename, line, r,
ca5ad760
YW
854 "Failed to apply IDNA to domain name '%s', ignoring: %m", w);
855 continue;
856 } else if (r == 0)
857 /* transfer ownership to simplify subsequent operations */
858 idna = TAKE_PTR(w);
859
5e276772 860 r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops_free);
ca5ad760 861 if (r < 0)
d96edb2c 862 return log_oom();
ca5ad760
YW
863
864 r = ordered_set_consume(n->router_search_domains, TAKE_PTR(idna));
865 if (r < 0)
d96edb2c 866 return log_oom();
ca5ad760 867 }
ca5ad760
YW
868}
869
870static const char * const radv_prefix_delegation_table[_RADV_PREFIX_DELEGATION_MAX] = {
a8d4a210 871 [RADV_PREFIX_DELEGATION_NONE] = "no",
ca5ad760 872 [RADV_PREFIX_DELEGATION_STATIC] = "static",
a8d4a210
YW
873 [RADV_PREFIX_DELEGATION_DHCP6] = "dhcpv6",
874 [RADV_PREFIX_DELEGATION_BOTH] = "yes",
ca5ad760
YW
875};
876
877DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(
878 radv_prefix_delegation,
879 RADVPrefixDelegation,
880 RADV_PREFIX_DELEGATION_BOTH);
881
a8d4a210
YW
882DEFINE_CONFIG_PARSE_ENUM(
883 config_parse_router_prefix_delegation,
884 radv_prefix_delegation,
885 RADVPrefixDelegation,
886 "Invalid router prefix delegation");
887
888int config_parse_router_preference(
889 const char *unit,
890 const char *filename,
891 unsigned line,
892 const char *section,
893 unsigned section_line,
894 const char *lvalue,
895 int ltype,
896 const char *rvalue,
897 void *data,
898 void *userdata) {
899
ca5ad760
YW
900 Network *network = userdata;
901
902 assert(filename);
903 assert(section);
904 assert(lvalue);
905 assert(rvalue);
906 assert(data);
907
908 if (streq(rvalue, "high"))
909 network->router_preference = SD_NDISC_PREFERENCE_HIGH;
910 else if (STR_IN_SET(rvalue, "medium", "normal", "default"))
911 network->router_preference = SD_NDISC_PREFERENCE_MEDIUM;
912 else if (streq(rvalue, "low"))
913 network->router_preference = SD_NDISC_PREFERENCE_LOW;
914 else
d96edb2c
YW
915 log_syntax(unit, LOG_WARNING, filename, line, 0,
916 "Invalid router preference, ignoring assignment: %s", rvalue);
ca5ad760
YW
917
918 return 0;
919}