]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-dhcp6.c
Merge pull request #16191 from poettering/repart-spec
[thirdparty/systemd.git] / src / network / networkd-dhcp6.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 Copyright © 2014 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <netinet/in.h>
7 #include <linux/if.h>
8 #include <linux/if_arp.h>
9 #include "sd-radv.h"
10
11 #include "sd-dhcp6-client.h"
12
13 #include "escape.h"
14 #include "hashmap.h"
15 #include "hostname-util.h"
16 #include "missing_network.h"
17 #include "network-internal.h"
18 #include "networkd-dhcp6.h"
19 #include "networkd-link.h"
20 #include "networkd-manager.h"
21 #include "siphash24.h"
22 #include "string-util.h"
23 #include "radv-internal.h"
24 #include "web-util.h"
25
26 static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link);
27 static Link *dhcp6_prefix_get(Manager *m, struct in6_addr *addr);
28 static int dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link);
29 static int dhcp6_prefix_remove_all(Manager *m, Link *link);
30 static bool dhcp6_link_has_dhcpv6_prefix(Link *link);
31 static int dhcp6_assign_delegated_prefix(Link *link, const struct in6_addr *prefix,
32 uint8_t prefix_len,
33 uint32_t lifetime_preferred,
34 uint32_t lifetime_valid);
35
36 static bool dhcp6_get_prefix_delegation(Link *link) {
37 if (!link->network)
38 return false;
39
40 return IN_SET(link->network->router_prefix_delegation,
41 RADV_PREFIX_DELEGATION_DHCP6,
42 RADV_PREFIX_DELEGATION_BOTH);
43 }
44
45 static bool dhcp6_has_preferred_subnet_id(Link *link) {
46 if (!link->network)
47 return false;
48
49 return link->network->router_prefix_subnet_id >= 0;
50 }
51
52 static int dhcp6_get_preferred_delegated_prefix(
53 Manager* manager,
54 Link *link,
55 const struct in6_addr *pd_prefix,
56 uint8_t pd_prefix_len,
57 struct in6_addr *ret_addr) {
58
59 int64_t subnet_id = link->network->router_prefix_subnet_id;
60 uint8_t prefix_bits = 64 - pd_prefix_len;
61 uint64_t n_prefixes = UINT64_C(1) << prefix_bits;
62 _cleanup_free_ char *assigned_buf = NULL;
63 union in_addr_union pd_prefix_union = {
64 .in6 = *pd_prefix,
65 };
66 /* We start off with the original PD prefix we have been assigned and
67 * iterate from there */
68 union in_addr_union prefix = {
69 .in6 = *pd_prefix,
70 };
71 int r;
72
73 assert(pd_prefix_len <= 64);
74 assert(manager);
75 assert(link);
76 assert(link->network);
77
78 if (subnet_id >= 0) {
79 /* If the link has a preference for a particular subnet id try to allocate that */
80 if ((uint64_t)subnet_id >= n_prefixes)
81 return log_link_debug_errno(link,
82 SYNTHETIC_ERRNO(ERANGE),
83 "subnet id %" PRIi64 " is out of range. Only have %" PRIu64 " subnets.",
84 subnet_id,
85 n_prefixes);
86
87 r = in_addr_prefix_nth(AF_INET6, &prefix, 64, subnet_id);
88 if (r < 0)
89 return log_link_debug_errno(link,
90 r,
91 "subnet id %" PRIi64 " is out of range. Only have %" PRIu64 " subnets.",
92 subnet_id,
93 n_prefixes);
94
95 /* Verify that the prefix we did calculate fits in the pd prefix.
96 * This should not fail as we checked the prefix size beforehand */
97 assert_se(in_addr_prefix_covers(AF_INET6, &pd_prefix_union, pd_prefix_len, &prefix) > 0);
98
99 Link* assigned_link = dhcp6_prefix_get(manager, &prefix.in6);
100
101 (void) in_addr_to_string(AF_INET6, &prefix, &assigned_buf);
102
103 if (assigned_link && assigned_link != link)
104 return log_link_error_errno(link, SYNTHETIC_ERRNO(EAGAIN),
105 "The requested prefix %s is already assigned to another link: %s",
106 strnull(assigned_buf),
107 strnull(assigned_link->ifname));
108
109 *ret_addr = prefix.in6;
110
111 log_link_debug(link, "The requested prefix %s is available. Using it.",
112 strnull(assigned_buf));
113 return 0;
114 } else {
115 for (uint64_t n = 0; n < n_prefixes; n++) {
116 /* if we do not have an allocation preference just iterate
117 * through the address space and return the first free prefix. */
118 Link* assigned_link = dhcp6_prefix_get(manager, &prefix.in6);
119
120 if (!assigned_link || assigned_link == link) {
121 *ret_addr = prefix.in6;
122 return 0;
123 }
124
125 r = in_addr_prefix_next(AF_INET6, &prefix, 64);
126 if (r < 0)
127 return log_link_error_errno(link,
128 r,
129 "Can't allocate another prefix. Out of address space?");
130 }
131
132 log_link_warning(link, "Couldn't find a suitable prefix. Ran out of address space.");
133 }
134
135 return -ERANGE;
136 }
137
138 static bool dhcp6_enable_prefix_delegation(Link *dhcp6_link) {
139 Manager *manager;
140 Link *l;
141 Iterator i;
142
143 assert(dhcp6_link);
144
145 manager = dhcp6_link->manager;
146 assert(manager);
147
148 HASHMAP_FOREACH(l, manager->links, i) {
149 if (l == dhcp6_link)
150 continue;
151
152 if (!dhcp6_get_prefix_delegation(l))
153 continue;
154
155 return true;
156 }
157
158 return false;
159 }
160
161 static int dhcp6_lease_information_acquired(sd_dhcp6_client *client,
162 Link *link) {
163 return 0;
164 }
165
166 static int dhcp6_pd_prefix_assign(Link *link, struct in6_addr *prefix,
167 uint8_t prefix_len,
168 uint32_t lifetime_preferred,
169 uint32_t lifetime_valid) {
170 sd_radv *radv = link->radv;
171 int r;
172 _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
173
174 r = sd_radv_prefix_new(&p);
175 if (r < 0)
176 return r;
177
178 r = sd_radv_prefix_set_prefix(p, prefix, prefix_len);
179 if (r < 0)
180 return r;
181
182 r = sd_radv_prefix_set_preferred_lifetime(p, lifetime_preferred);
183 if (r < 0)
184 return r;
185
186 r = sd_radv_prefix_set_valid_lifetime(p, lifetime_valid);
187 if (r < 0)
188 return r;
189
190 r = sd_radv_stop(radv);
191 if (r < 0)
192 return r;
193
194 r = sd_radv_add_prefix(radv, p, true);
195 if (r < 0 && r != -EEXIST)
196 return r;
197
198 r = dhcp6_prefix_add(link->manager, prefix, link);
199 if (r < 0)
200 return r;
201
202 if (link->network->dhcp6_pd_assign_prefix) {
203 r = dhcp6_assign_delegated_prefix(link, prefix, prefix_len, lifetime_preferred, lifetime_valid);
204 if (r < 0)
205 return r;
206 }
207
208 return sd_radv_start(radv);
209 }
210
211 static int dhcp6_route_remove_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) {
212 int r;
213
214 assert(link);
215
216 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
217 return 1;
218
219 r = sd_netlink_message_get_errno(m);
220 if (r < 0)
221 log_link_message_warning_errno(link, m, r, "Received error on unreachable route removal for DHCPv6 delegated subnet");
222
223 return 1;
224 }
225
226 int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client *client, Link* link) {
227 uint32_t lifetime_preferred, lifetime_valid;
228 union in_addr_union pd_prefix;
229 uint8_t pd_prefix_len;
230 sd_dhcp6_lease *lease;
231 int r;
232
233 r = sd_dhcp6_client_get_lease(client, &lease);
234 if (r < 0)
235 return r;
236
237 sd_dhcp6_lease_reset_pd_prefix_iter(lease);
238
239 while (sd_dhcp6_lease_get_pd(lease, &pd_prefix.in6, &pd_prefix_len,
240 &lifetime_preferred,
241 &lifetime_valid) >= 0) {
242 _cleanup_free_ char *buf = NULL;
243 _cleanup_(route_freep) Route *route = NULL;
244
245 if (pd_prefix_len >= 64)
246 continue;
247
248 (void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
249
250 r = route_new(&route);
251 if (r < 0)
252 return r;
253
254 route->family = AF_INET6;
255 route->dst = pd_prefix;
256 route->dst_prefixlen = pd_prefix_len;
257 route->type = RTN_UNREACHABLE;
258
259 r = route_remove(route, link, dhcp6_route_remove_handler);
260 if (r < 0) {
261 log_link_warning_errno(link, r, "Cannot delete unreachable route for DHCPv6 delegated subnet %s/%u: %m",
262 strnull(buf),
263 pd_prefix_len);
264 continue;
265 }
266
267 log_link_debug(link, "Removing unreachable route %s/%u",
268 strnull(buf), pd_prefix_len);
269 }
270
271 return 0;
272 }
273
274 static int dhcp6_pd_prefix_distribute(Link *dhcp6_link,
275 struct in6_addr *pd_prefix,
276 uint8_t pd_prefix_len,
277 uint32_t lifetime_preferred,
278 uint32_t lifetime_valid,
279 bool assign_preferred_subnet_id) {
280
281 _cleanup_free_ char *assigned_buf = NULL, *buf = NULL;
282 Manager *manager = dhcp6_link->manager;
283 union in_addr_union prefix = {
284 .in6 = *pd_prefix,
285 };
286 bool pool_depleted = false;
287 uint64_t n_prefixes;
288 Iterator i;
289 Link *link;
290 int r;
291
292 assert(manager);
293 assert(pd_prefix_len <= 64);
294
295 r = in_addr_mask(AF_INET6, &prefix, pd_prefix_len);
296 if (r < 0)
297 return r;
298
299 n_prefixes = UINT64_C(1) << (64 - pd_prefix_len);
300
301 (void) in_addr_to_string(AF_INET6, &prefix, &buf);
302 log_link_debug(dhcp6_link, "Assigning up to %" PRIu64 " prefixes from %s/%u",
303 n_prefixes, strnull(buf), pd_prefix_len);
304
305 HASHMAP_FOREACH(link, manager->links, i) {
306 union in_addr_union assigned_prefix;
307
308 if (link == dhcp6_link)
309 continue;
310
311 if (!dhcp6_get_prefix_delegation(link))
312 continue;
313
314 if (dhcp6_link_has_dhcpv6_prefix(link))
315 continue;
316
317 if (assign_preferred_subnet_id != dhcp6_has_preferred_subnet_id(link))
318 continue;
319
320 r = dhcp6_get_preferred_delegated_prefix(manager, link, &prefix.in6, pd_prefix_len,
321 &assigned_prefix.in6);
322
323 if (assign_preferred_subnet_id && r == -EAGAIN) {
324 /* A link has a preferred subnet_id but that one is
325 * already taken by another link. Now all the remaining
326 * links will also not obtain a prefix. */
327 pool_depleted = true;
328 continue;
329 } else if (r < 0)
330 return r;
331
332 (void) in_addr_to_string(AF_INET6, &assigned_prefix, &assigned_buf);
333 r = dhcp6_pd_prefix_assign(link, &assigned_prefix.in6, 64,
334 lifetime_preferred, lifetime_valid);
335 if (r < 0) {
336 log_link_error_errno(link, r, "Unable to assign/update prefix %s/64 from %s/%u for link: %m",
337 strnull(assigned_buf),
338 strnull(buf), pd_prefix_len);
339 } else
340 log_link_debug(link, "Assigned prefix %s/64 from %s/%u to link",
341 strnull(assigned_buf),
342 strnull(buf), pd_prefix_len);
343 }
344
345 /* If one of the link requests couldn't be fulfilled, signal that we
346 should try again with another prefix. */
347 if (pool_depleted)
348 return -EAGAIN;
349
350 return 0;
351 }
352
353 static int dhcp6_route_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) {
354 int r;
355
356 assert(link);
357
358 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
359 return 1;
360
361 r = sd_netlink_message_get_errno(m);
362 if (r < 0 && r != -EEXIST)
363 log_link_message_warning_errno(link, m, r, "Received error when adding unreachable route for DHCPv6 delegated subnet");
364
365 return 1;
366 }
367
368 static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) {
369 uint32_t lifetime_preferred, lifetime_valid;
370 union in_addr_union pd_prefix;
371 sd_dhcp6_lease *lease;
372 uint8_t pd_prefix_len;
373 int r;
374
375 r = sd_dhcp6_client_get_lease(client, &lease);
376 if (r < 0)
377 return r;
378
379 sd_dhcp6_lease_reset_pd_prefix_iter(lease);
380
381 while (sd_dhcp6_lease_get_pd(lease, &pd_prefix.in6, &pd_prefix_len,
382 &lifetime_preferred,
383 &lifetime_valid) >= 0) {
384
385 _cleanup_free_ char *buf = NULL;
386
387 (void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
388
389 if (pd_prefix_len > 64) {
390 log_link_debug(link, "PD Prefix length > 64, ignoring prefix %s/%u",
391 strnull(buf), pd_prefix_len);
392 continue;
393 }
394
395 if (pd_prefix_len < 48)
396 log_link_warning(link, "PD Prefix length < 48, looks unusual %s/%u",
397 strnull(buf), pd_prefix_len);
398
399 if (pd_prefix_len < 64) {
400 _cleanup_(route_freep) Route *route = NULL;
401
402 r = route_new(&route);
403 if (r < 0)
404 return r;
405
406 route->family = AF_INET6;
407 route->dst = pd_prefix;
408 route->dst_prefixlen = pd_prefix_len;
409 route->table = link_get_dhcp_route_table(link);
410 route->type = RTN_UNREACHABLE;
411
412 r = route_configure(route, link, dhcp6_route_handler);
413 if (r < 0) {
414 log_link_warning_errno(link, r, "Cannot configure unreachable route for delegated subnet %s/%u: %m",
415 strnull(buf),
416 pd_prefix_len);
417 continue;
418 }
419
420 log_link_debug(link, "Configuring unreachable route for %s/%u",
421 strnull(buf), pd_prefix_len);
422 } else
423 log_link_debug(link, "Not adding a blocking route since distributed prefix is /64");
424
425 /* We are doing prefix allocation in two steps:
426 * 1. all those links that have a preferred subnet id will be assigned their subnet
427 * 2. all those links that remain will receive prefixes in sequential
428 * order. Prefixes that were previously already allocated to another
429 * link will be skipped.
430
431 * If a subnet id request couldn't be fulfilled the failure will be logged (as error)
432 * and no further attempts at obtaining a prefix will be made.
433
434 * The assignment has to be split in two phases since subnet id
435 * preferences should be honored. Meaning that any subnet id should be
436 * handed out to the requesting link and not to some link that didn't
437 * specify any preference. */
438
439 r = dhcp6_pd_prefix_distribute(link, &pd_prefix.in6,
440 pd_prefix_len,
441 lifetime_preferred,
442 lifetime_valid,
443 true);
444 if (r < 0 && r != -EAGAIN)
445 return r;
446
447 /* if r == -EAGAIN then the allocation failed because we ran
448 * out of addresses for the preferred subnet id's. This doesn't
449 * mean we can't fulfill other prefix requests.
450 *
451 * Since we do not have dedicated lists of links that request
452 * specific subnet id's and those that accept any prefix we
453 * *must* reset the iterator to the start as otherwise some
454 * links might not get their requested prefix. */
455
456 r = dhcp6_pd_prefix_distribute(link, &pd_prefix.in6,
457 pd_prefix_len,
458 lifetime_preferred,
459 lifetime_valid,
460 false);
461 if (r < 0 && r != -EAGAIN)
462 return r;
463
464 /* If the prefix distribution did return -EAGAIN we will try to
465 * fulfill those with the next available pd delegated prefix. */
466 }
467
468 return 0;
469 }
470
471 int dhcp6_request_prefix_delegation(Link *link) {
472 Link *l;
473 Iterator i;
474
475 assert_return(link, -EINVAL);
476 assert_return(link->manager, -EOPNOTSUPP);
477
478 if (dhcp6_get_prefix_delegation(link) <= 0)
479 return 0;
480
481 log_link_debug(link, "Requesting DHCPv6 prefixes to be delegated for new link");
482
483 HASHMAP_FOREACH(l, link->manager->links, i) {
484 int r, enabled;
485
486 if (l == link)
487 continue;
488
489 if (!l->dhcp6_client)
490 continue;
491
492 r = sd_dhcp6_client_get_prefix_delegation(l->dhcp6_client, &enabled);
493 if (r < 0) {
494 log_link_warning_errno(l, r, "Cannot get prefix delegation when adding new link");
495 continue;
496 }
497
498 if (enabled == 0) {
499 r = sd_dhcp6_client_set_prefix_delegation(l->dhcp6_client, 1);
500 if (r < 0) {
501 log_link_warning_errno(l, r, "Cannot enable prefix delegation when adding new link");
502 continue;
503 }
504 }
505
506 r = sd_dhcp6_client_is_running(l->dhcp6_client);
507 if (r <= 0)
508 continue;
509
510 if (enabled != 0) {
511 log_link_debug(l, "Requesting re-assignment of delegated prefixes after adding new link");
512 (void) dhcp6_lease_pd_prefix_acquired(l->dhcp6_client, l);
513
514 continue;
515 }
516
517 r = sd_dhcp6_client_stop(l->dhcp6_client);
518 if (r < 0) {
519 log_link_warning_errno(l, r, "Cannot stop DHCPv6 prefix delegation client after adding new link");
520 continue;
521 }
522
523 r = sd_dhcp6_client_start(l->dhcp6_client);
524 if (r < 0) {
525 log_link_warning_errno(l, r, "Cannot restart DHCPv6 prefix delegation client after adding new link");
526 continue;
527 }
528
529 log_link_debug(l, "Restarted DHCPv6 client to acquire prefix delegations after adding new link");
530 }
531
532 return 0;
533 }
534
535 static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
536 int r;
537
538 assert(link);
539
540 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
541 return 1;
542
543 r = sd_netlink_message_get_errno(m);
544 if (r < 0 && r != -EEXIST) {
545 log_link_message_warning_errno(link, m, r, "Could not set DHCPv6 address");
546 link_enter_failed(link);
547 return 1;
548 } else if (r >= 0)
549 (void) manager_rtnl_process_address(rtnl, m, link->manager);
550
551 r = link_request_set_routes(link);
552 if (r < 0) {
553 link_enter_failed(link);
554 return 1;
555 }
556
557 return 1;
558 }
559
560 static int dhcp6_address_change(
561 Link *link,
562 struct in6_addr *ip6_addr,
563 uint32_t lifetime_preferred,
564 uint32_t lifetime_valid) {
565
566 _cleanup_(address_freep) Address *addr = NULL;
567 _cleanup_free_ char *buffer = NULL;
568 int r;
569
570 r = address_new(&addr);
571 if (r < 0)
572 return r;
573
574 addr->family = AF_INET6;
575 addr->in_addr.in6 = *ip6_addr;
576 addr->flags = IFA_F_NOPREFIXROUTE;
577 addr->prefixlen = 128;
578 addr->cinfo.ifa_prefered = lifetime_preferred;
579 addr->cinfo.ifa_valid = lifetime_valid;
580
581 (void) in_addr_to_string(addr->family, &addr->in_addr, &buffer);
582 log_link_info(link,
583 "DHCPv6 address %s/%d timeout preferred %d valid %d",
584 strnull(buffer), addr->prefixlen, lifetime_preferred, lifetime_valid);
585
586 r = address_configure(addr, link, dhcp6_address_handler, true);
587 if (r < 0)
588 return log_link_warning_errno(link, r, "Could not assign DHCPv6 address: %m");
589
590 return 0;
591 }
592
593 static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) {
594 int r;
595 sd_dhcp6_lease *lease;
596 struct in6_addr ip6_addr;
597 uint32_t lifetime_preferred, lifetime_valid;
598
599 r = sd_dhcp6_client_get_lease(client, &lease);
600 if (r < 0)
601 return r;
602
603 sd_dhcp6_lease_reset_address_iter(lease);
604
605 while (sd_dhcp6_lease_get_address(lease, &ip6_addr,
606 &lifetime_preferred,
607 &lifetime_valid) >= 0) {
608
609 r = dhcp6_address_change(link, &ip6_addr, lifetime_preferred, lifetime_valid);
610 if (r < 0)
611 return r;
612 }
613
614 return 0;
615 }
616
617 static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
618 int r;
619 Link *link = userdata;
620
621 assert(link);
622 assert(link->network);
623
624 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
625 return;
626
627 switch(event) {
628 case SD_DHCP6_CLIENT_EVENT_STOP:
629 case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE:
630 case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX:
631 if (sd_dhcp6_client_get_lease(client, NULL) >= 0)
632 log_link_warning(link, "DHCPv6 lease lost");
633
634 (void) dhcp6_lease_pd_prefix_lost(client, link);
635 (void) dhcp6_prefix_remove_all(link->manager, link);
636
637 link_dirty(link);
638 link->dhcp6_configured = false;
639 break;
640
641 case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE:
642 r = dhcp6_lease_address_acquired(client, link);
643 if (r < 0) {
644 link_enter_failed(link);
645 return;
646 }
647
648 r = dhcp6_lease_pd_prefix_acquired(client, link);
649 if (r < 0)
650 log_link_debug(link, "DHCPv6 did not receive prefixes to delegate");
651
652 _fallthrough_;
653 case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST:
654 r = dhcp6_lease_information_acquired(client, link);
655 if (r < 0) {
656 link_enter_failed(link);
657 return;
658 }
659
660 link_dirty(link);
661 link->dhcp6_configured = true;
662 break;
663
664 default:
665 if (event < 0)
666 log_link_warning_errno(link, event, "DHCPv6 error: %m");
667 else
668 log_link_warning(link, "DHCPv6 unknown event: %d", event);
669 return;
670 }
671
672 link_check_ready(link);
673 }
674
675 int dhcp6_request_address(Link *link, int ir) {
676 int r, inf_req, pd;
677 bool running;
678
679 assert(link);
680 assert(link->dhcp6_client);
681 assert(link->network);
682 assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0);
683
684 r = sd_dhcp6_client_is_running(link->dhcp6_client);
685 if (r < 0)
686 return r;
687 running = r;
688
689 r = sd_dhcp6_client_get_prefix_delegation(link->dhcp6_client, &pd);
690 if (r < 0)
691 return r;
692
693 if (pd && ir && link->network->dhcp6_force_pd_other_information) {
694 log_link_debug(link, "Enabling managed mode to request DHCPv6 PD with 'Other Information' set");
695
696 r = sd_dhcp6_client_set_address_request(link->dhcp6_client,
697 false);
698 if (r < 0 )
699 return r;
700
701 ir = false;
702 }
703
704 if (running) {
705 r = sd_dhcp6_client_get_information_request(link->dhcp6_client, &inf_req);
706 if (r < 0)
707 return r;
708
709 if (inf_req == ir)
710 return 0;
711
712 r = sd_dhcp6_client_stop(link->dhcp6_client);
713 if (r < 0)
714 return r;
715 } else {
716 r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address);
717 if (r < 0)
718 return r;
719 }
720
721 r = sd_dhcp6_client_set_information_request(link->dhcp6_client, ir);
722 if (r < 0)
723 return r;
724
725 r = sd_dhcp6_client_start(link->dhcp6_client);
726 if (r < 0)
727 return r;
728
729 return 0;
730 }
731
732 static int dhcp6_set_hostname(sd_dhcp6_client *client, Link *link) {
733 _cleanup_free_ char *hostname = NULL;
734 const char *hn;
735 int r;
736
737 assert(link);
738
739 if (!link->network->dhcp_send_hostname)
740 hn = NULL;
741 else if (link->network->dhcp_hostname)
742 hn = link->network->dhcp_hostname;
743 else {
744 r = gethostname_strict(&hostname);
745 if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
746 return r;
747
748 hn = hostname;
749 }
750
751 r = sd_dhcp6_client_set_fqdn(client, hn);
752 if (r == -EINVAL && hostname)
753 /* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
754 log_link_warning_errno(link, r, "DHCP6 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
755 else if (r < 0)
756 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set hostname: %m");
757
758 return 0;
759 }
760
761 int dhcp6_configure(Link *link) {
762 _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
763 sd_dhcp6_option *vendor_option;
764 sd_dhcp6_option *send_option;
765 void *request_options;
766 const DUID *duid;
767 Iterator i;
768 int r;
769
770 assert(link);
771 assert(link->network);
772
773 if (link->dhcp6_client)
774 return 0;
775
776 r = sd_dhcp6_client_new(&client);
777 if (r == -ENOMEM)
778 return log_oom();
779 if (r < 0)
780 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to create DHCP6 client: %m");
781
782 r = sd_dhcp6_client_attach_event(client, NULL, 0);
783 if (r < 0)
784 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to attach event: %m");
785
786 r = sd_dhcp6_client_set_mac(client,
787 (const uint8_t *) &link->mac,
788 sizeof (link->mac), ARPHRD_ETHER);
789 if (r < 0)
790 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set MAC address: %m");
791
792 if (link->network->iaid_set) {
793 r = sd_dhcp6_client_set_iaid(client, link->network->iaid);
794 if (r < 0)
795 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set IAID: %m");
796 }
797
798 duid = link_get_duid(link);
799 if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0)
800 r = sd_dhcp6_client_set_duid_llt(client, duid->llt_time);
801 else
802 r = sd_dhcp6_client_set_duid(client,
803 duid->type,
804 duid->raw_data_len > 0 ? duid->raw_data : NULL,
805 duid->raw_data_len);
806 if (r < 0)
807 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set DUID: %m");
808
809 ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp6_client_send_options, i) {
810 r = sd_dhcp6_client_add_option(client, send_option);
811 if (r == -EEXIST)
812 continue;
813 if (r < 0)
814 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set option: %m");
815 }
816
817 r = dhcp6_set_hostname(client, link);
818 if (r < 0)
819 return r;
820
821 r = sd_dhcp6_client_set_ifindex(client, link->ifindex);
822 if (r < 0)
823 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set ifindex: %m");
824
825 if (link->network->rapid_commit) {
826 r = sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_RAPID_COMMIT);
827 if (r < 0)
828 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for rapid commit: %m");
829 }
830
831 if (link->network->dhcp6_mudurl) {
832 r = sd_dhcp6_client_set_request_mud_url(client, link->network->dhcp6_mudurl);
833 if (r < 0)
834 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set MUD URL: %m");
835 }
836
837 SET_FOREACH(request_options, link->network->dhcp6_request_options, i) {
838 uint32_t option = PTR_TO_UINT32(request_options);
839
840 r = sd_dhcp6_client_set_request_option(client, option);
841 if (r == -EEXIST) {
842 log_link_debug(link, "DHCP6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option);
843 continue;
844 }
845
846 if (r < 0)
847 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for '%u': %m", option);
848 }
849
850 if (link->network->dhcp6_user_class) {
851 r = sd_dhcp6_client_set_request_user_class(client, link->network->dhcp6_user_class);
852 if (r < 0)
853 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set user class: %m");
854 }
855
856 if (link->network->dhcp6_vendor_class) {
857 r = sd_dhcp6_client_set_request_vendor_class(client, link->network->dhcp6_vendor_class);
858 if (r < 0)
859 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set vendor class: %m");
860 }
861
862 ORDERED_HASHMAP_FOREACH(vendor_option, link->network->dhcp6_client_send_vendor_options, i) {
863 r = sd_dhcp6_client_add_vendor_option(client, vendor_option);
864 if (r == -EEXIST)
865 continue;
866 if (r < 0)
867 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set vendor option: %m");
868 }
869
870 r = sd_dhcp6_client_set_callback(client, dhcp6_handler, link);
871 if (r < 0)
872 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set callback: %m");
873
874 if (dhcp6_enable_prefix_delegation(link)) {
875 r = sd_dhcp6_client_set_prefix_delegation(client, true);
876 if (r < 0)
877 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set prefix delegation: %m");
878 }
879
880 if (link->network->dhcp6_pd_length > 0) {
881 r = sd_dhcp6_client_set_prefix_delegation_hint(client, link->network->dhcp6_pd_length, &link->network->dhcp6_pd_address);
882 if (r < 0)
883 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set prefix hint: %m");
884 }
885
886 link->dhcp6_client = TAKE_PTR(client);
887
888 return 0;
889 }
890
891 static Link *dhcp6_prefix_get(Manager *m, struct in6_addr *addr) {
892 assert_return(m, NULL);
893 assert_return(addr, NULL);
894
895 return hashmap_get(m->dhcp6_prefixes, addr);
896 }
897
898 static int dhcp6_route_add_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) {
899 int r;
900
901 assert(link);
902
903 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
904 return 1;
905
906 r = sd_netlink_message_get_errno(m);
907 if (r < 0 && r != -EEXIST) {
908 log_link_message_warning_errno(link, m, r, "Received error adding DHCPv6 Prefix Delegation route");
909 link_enter_failed(link);
910 return 1;
911 }
912
913 return 1;
914 }
915
916 static int dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) {
917 _cleanup_(route_freep) Route *route = NULL;
918 _cleanup_free_ struct in6_addr *a = NULL;
919 _cleanup_free_ char *buf = NULL;
920 Link *assigned_link;
921 int r;
922
923 assert_return(m, -EINVAL);
924 assert_return(addr, -EINVAL);
925
926 r = route_new(&route);
927 if (r < 0)
928 return r;
929
930 route->family = AF_INET6;
931 route->dst.in6 = *addr;
932 route->dst_prefixlen = 64;
933
934 r = route_configure(route, link, dhcp6_route_add_handler);
935 if (r < 0)
936 return r;
937
938 (void) in_addr_to_string(AF_INET6, (union in_addr_union *) addr, &buf);
939 log_link_debug(link, "Adding prefix route %s/64", strnull(buf));
940
941 assigned_link = hashmap_get(m->dhcp6_prefixes, addr);
942 if (assigned_link) {
943 assert(assigned_link == link);
944 return 0;
945 }
946
947 a = newdup(struct in6_addr, addr, 1);
948 if (!a)
949 return -ENOMEM;
950
951 r = hashmap_ensure_allocated(&m->dhcp6_prefixes, &in6_addr_hash_ops);
952 if (r < 0)
953 return r;
954
955 r = hashmap_put(m->dhcp6_prefixes, a, link);
956 if (r < 0)
957 return r;
958
959 TAKE_PTR(a);
960 link_ref(link);
961 return 0;
962 }
963
964 static int dhcp6_prefix_remove_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) {
965 int r;
966
967 assert(link);
968
969 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
970 return 1;
971
972 r = sd_netlink_message_get_errno(m);
973 if (r < 0) {
974 log_link_message_warning_errno(link, m, r, "Received error on DHCPv6 Prefix Delegation route removal");
975 link_enter_failed(link);
976 return 1;
977 }
978
979 return 1;
980 }
981
982 int dhcp6_prefix_remove(Manager *m, struct in6_addr *addr) {
983 _cleanup_free_ struct in6_addr *a = NULL;
984 _cleanup_(link_unrefp) Link *l = NULL;
985 _cleanup_(route_freep) Route *route = NULL;
986 _cleanup_free_ char *buf = NULL;
987 int r;
988
989 assert_return(m, -EINVAL);
990 assert_return(addr, -EINVAL);
991
992 l = hashmap_remove2(m->dhcp6_prefixes, addr, (void **) &a);
993 if (!l)
994 return -EINVAL;
995
996 (void) sd_radv_remove_prefix(l->radv, addr, 64);
997
998 r = route_new(&route);
999 if (r < 0)
1000 return r;
1001
1002 route->family = AF_INET6;
1003 route->dst.in6 = *addr;
1004 route->dst_prefixlen = 64;
1005
1006 r = route_remove(route, l, dhcp6_prefix_remove_handler);
1007 if (r < 0)
1008 return r;
1009
1010 (void) in_addr_to_string(AF_INET6, (union in_addr_union *) addr, &buf);
1011 log_link_debug(l, "Removing prefix route %s/64", strnull(buf));
1012
1013 return 0;
1014 }
1015
1016 static int dhcp6_prefix_remove_all(Manager *m, Link *link) {
1017 struct in6_addr *addr;
1018 Iterator i;
1019 Link *l;
1020
1021 assert_return(m, -EINVAL);
1022 assert_return(link, -EINVAL);
1023
1024 HASHMAP_FOREACH_KEY(l, addr, m->dhcp6_prefixes, i)
1025 if (l == link)
1026 (void) dhcp6_prefix_remove(m, addr);
1027
1028 return 0;
1029 }
1030
1031 static bool dhcp6_link_has_dhcpv6_prefix(Link *link) {
1032 Iterator i;
1033 Link *l;
1034
1035 assert(link);
1036 assert(link->manager);
1037
1038 HASHMAP_FOREACH(l, link->manager->dhcp6_prefixes, i)
1039 if (link == l)
1040 return true;
1041
1042 return false;
1043 }
1044
1045 static int dhcp6_assign_delegated_prefix(Link *link,
1046 const struct in6_addr *prefix,
1047 uint8_t prefix_len,
1048 uint32_t lifetime_preferred,
1049 uint32_t lifetime_valid) {
1050
1051 _cleanup_(address_freep) Address *address = NULL;
1052 int r;
1053
1054 assert(link);
1055 assert(link->network);
1056 assert(prefix);
1057
1058 if (!link->network->dhcp6_pd_assign_prefix)
1059 return 0;
1060
1061 r = address_new(&address);
1062 if (r < 0)
1063 return log_link_error_errno(link, r, "Failed to allocate address for DHCPv6 delegated prefix: %m");
1064
1065 address->in_addr.in6 = *prefix;
1066
1067 if (!in_addr_is_null(AF_INET6, &link->network->dhcp6_delegation_prefix_token))
1068 memcpy(&address->in_addr.in6.s6_addr + 8, &link->network->dhcp6_delegation_prefix_token.in6.s6_addr + 8, 8);
1069 else {
1070 r = generate_ipv6_eui_64_address(link, &address->in_addr.in6);
1071 if (r < 0)
1072 return log_link_warning_errno(link, r, "Failed to generate EUI64 address for acquired DHCPv6 delegated prefix: %m");
1073 }
1074
1075 address->prefixlen = prefix_len;
1076 address->family = AF_INET6;
1077 address->cinfo.ifa_prefered = lifetime_preferred;
1078 address->cinfo.ifa_valid = lifetime_valid;
1079
1080 link_set_state(link, LINK_STATE_CONFIGURING);
1081
1082 r = address_configure(address, link, address_handler, true);
1083 if (r < 0)
1084 return log_link_warning_errno(link, r, "Failed to set acquired DHCPv6 delegated prefix address: %m");
1085 if (r > 0)
1086 link->address_messages++;
1087
1088 return 0;
1089 }
1090
1091 int config_parse_dhcp6_pd_hint(
1092 const char* unit,
1093 const char *filename,
1094 unsigned line,
1095 const char *section,
1096 unsigned section_line,
1097 const char *lvalue,
1098 int ltype,
1099 const char *rvalue,
1100 void *data,
1101 void *userdata) {
1102
1103 Network *network = data;
1104 int r;
1105
1106 assert(filename);
1107 assert(lvalue);
1108 assert(rvalue);
1109 assert(data);
1110
1111 r = in_addr_prefix_from_string(rvalue, AF_INET6, (union in_addr_union *) &network->dhcp6_pd_address, &network->dhcp6_pd_length);
1112 if (r < 0) {
1113 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse PrefixDelegationHint=%s, ignoring assignment", rvalue);
1114 return 0;
1115 }
1116
1117 if (network->dhcp6_pd_length < 1 || network->dhcp6_pd_length > 128) {
1118 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid prefix length='%d', ignoring assignment", network->dhcp6_pd_length);
1119 network->dhcp6_pd_length = 0;
1120 return 0;
1121 }
1122
1123 return 0;
1124 }
1125
1126 int config_parse_dhcp6_mud_url(
1127 const char *unit,
1128 const char *filename,
1129 unsigned line,
1130 const char *section,
1131 unsigned section_line,
1132 const char *lvalue,
1133 int ltype,
1134 const char *rvalue,
1135 void *data,
1136 void *userdata) {
1137
1138 _cleanup_free_ char *unescaped = NULL;
1139 Network *network = data;
1140 int r;
1141
1142 assert(filename);
1143 assert(lvalue);
1144 assert(rvalue);
1145
1146 if (isempty(rvalue)) {
1147 network->dhcp6_mudurl = mfree(network->dhcp6_mudurl);
1148 return 0;
1149 }
1150
1151 r = cunescape(rvalue, 0, &unescaped);
1152 if (r < 0) {
1153 log_syntax(unit, LOG_ERR, filename, line, r,
1154 "Failed to Failed to unescape MUD URL, ignoring: %s", rvalue);
1155 return 0;
1156 }
1157
1158 if (!http_url_is_valid(unescaped) || strlen(unescaped) > UINT8_MAX) {
1159 log_syntax(unit, LOG_ERR, filename, line, 0,
1160 "Failed to parse MUD URL '%s', ignoring: %m", rvalue);
1161
1162 return 0;
1163 }
1164
1165 return free_and_replace(network->dhcp6_mudurl, unescaped);
1166 }
1167
1168 int config_parse_dhcp6_delegated_prefix_token(
1169 const char *unit,
1170 const char *filename,
1171 unsigned line,
1172 const char *section,
1173 unsigned section_line,
1174 const char *lvalue,
1175 int ltype,
1176 const char *rvalue,
1177 void *data,
1178 void *userdata) {
1179
1180 Network *network = data;
1181 int r;
1182
1183 assert(filename);
1184 assert(lvalue);
1185 assert(rvalue);
1186 assert(data);
1187
1188 if (isempty(rvalue)) {
1189 network->dhcp6_delegation_prefix_token = IN_ADDR_NULL;
1190 return 0;
1191 }
1192
1193 r = in_addr_from_string(AF_INET6, rvalue, &network->dhcp6_delegation_prefix_token);
1194 if (r < 0) {
1195 log_syntax(unit, LOG_ERR, filename, line, r,
1196 "Failed to parse DHCPv6 %s, ignoring: %s", lvalue, rvalue);
1197 return 0;
1198 }
1199
1200 if (in_addr_is_null(AF_INET6, &network->dhcp6_delegation_prefix_token)) {
1201 log_syntax(unit, LOG_ERR, filename, line, 0,
1202 "DHCPv6 %s cannot be the ANY address, ignoring: %s", lvalue, rvalue);
1203 return 0;
1204 }
1205
1206 return 0;
1207 }