]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp6-client.c
update-utmp: do not fail on EROFS
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp6-client.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 Copyright © 2014-2015 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <errno.h>
7 #include <sys/ioctl.h>
8 #include <linux/if_arp.h>
9 #include <linux/if_infiniband.h>
10
11 #include "sd-dhcp6-client.h"
12
13 #include "alloc-util.h"
14 #include "dhcp-identifier.h"
15 #include "dhcp6-internal.h"
16 #include "dhcp6-lease-internal.h"
17 #include "dhcp6-protocol.h"
18 #include "dns-domain.h"
19 #include "event-util.h"
20 #include "fd-util.h"
21 #include "hexdecoct.h"
22 #include "hostname-util.h"
23 #include "in-addr-util.h"
24 #include "network-internal.h"
25 #include "random-util.h"
26 #include "socket-util.h"
27 #include "string-table.h"
28 #include "util.h"
29 #include "web-util.h"
30
31 #define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
32
33 #define IRT_DEFAULT (1 * USEC_PER_DAY)
34 #define IRT_MINIMUM (600 * USEC_PER_SEC)
35
36 /* what to request from the server, addresses (IA_NA) and/or prefixes (IA_PD) */
37 enum {
38 DHCP6_REQUEST_IA_NA = 1,
39 DHCP6_REQUEST_IA_TA = 2, /* currently not used */
40 DHCP6_REQUEST_IA_PD = 4,
41 };
42
43 struct sd_dhcp6_client {
44 unsigned n_ref;
45
46 enum DHCP6State state;
47 sd_event *event;
48 int event_priority;
49 int ifindex;
50 DHCP6Address hint_pd_prefix;
51 struct in6_addr local_address;
52 uint8_t mac_addr[MAX_MAC_ADDR_LEN];
53 size_t mac_addr_len;
54 uint16_t arp_type;
55 DHCP6IA ia_na;
56 DHCP6IA ia_pd;
57 sd_event_source *timeout_t1;
58 sd_event_source *timeout_t2;
59 unsigned request;
60 be32_t transaction_id;
61 usec_t transaction_start;
62 struct sd_dhcp6_lease *lease;
63 int fd;
64 bool information_request;
65 bool iaid_set;
66 be16_t *req_opts;
67 size_t req_opts_allocated;
68 size_t req_opts_len;
69 char *fqdn;
70 char *mudurl;
71 char **user_class;
72 char **vendor_class;
73 sd_event_source *receive_message;
74 usec_t retransmit_time;
75 uint8_t retransmit_count;
76 sd_event_source *timeout_resend;
77 sd_event_source *timeout_resend_expire;
78 sd_dhcp6_client_callback_t callback;
79 void *userdata;
80 struct duid duid;
81 size_t duid_len;
82 usec_t information_request_time_usec;
83 usec_t information_refresh_time_usec;
84 OrderedHashmap *extra_options;
85 OrderedHashmap *vendor_options;
86 };
87
88 static const uint16_t default_req_opts[] = {
89 SD_DHCP6_OPTION_DNS_SERVERS,
90 SD_DHCP6_OPTION_DOMAIN_LIST,
91 SD_DHCP6_OPTION_NTP_SERVER,
92 SD_DHCP6_OPTION_SNTP_SERVERS,
93 };
94
95 const char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] = {
96 [DHCP6_SOLICIT] = "SOLICIT",
97 [DHCP6_ADVERTISE] = "ADVERTISE",
98 [DHCP6_REQUEST] = "REQUEST",
99 [DHCP6_CONFIRM] = "CONFIRM",
100 [DHCP6_RENEW] = "RENEW",
101 [DHCP6_REBIND] = "REBIND",
102 [DHCP6_REPLY] = "REPLY",
103 [DHCP6_RELEASE] = "RELEASE",
104 [DHCP6_DECLINE] = "DECLINE",
105 [DHCP6_RECONFIGURE] = "RECONFIGURE",
106 [DHCP6_INFORMATION_REQUEST] = "INFORMATION-REQUEST",
107 [DHCP6_RELAY_FORW] = "RELAY-FORW",
108 [DHCP6_RELAY_REPL] = "RELAY-REPL",
109 };
110
111 DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_type, int);
112
113 const char * dhcp6_message_status_table[_DHCP6_STATUS_MAX] = {
114 [DHCP6_STATUS_SUCCESS] = "Success",
115 [DHCP6_STATUS_UNSPEC_FAIL] = "Unspecified failure",
116 [DHCP6_STATUS_NO_ADDRS_AVAIL] = "No addresses available",
117 [DHCP6_STATUS_NO_BINDING] = "Binding unavailable",
118 [DHCP6_STATUS_NOT_ON_LINK] = "Not on link",
119 [DHCP6_STATUS_USE_MULTICAST] = "Use multicast",
120 [DHCP6_STATUS_NO_PREFIX_AVAIL] = "No prefix available",
121 [DHCP6_STATUS_UNKNOWN_QUERY_TYPE] = "Unknown query type",
122 [DHCP6_STATUS_MALFORMED_QUERY] = "Malformed query",
123 [DHCP6_STATUS_NOT_CONFIGURED] = "Not configured",
124 [DHCP6_STATUS_NOT_ALLOWED] = "Not allowed",
125 [DHCP6_STATUS_QUERY_TERMINATED] = "Query terminated",
126 [DHCP6_STATUS_DATA_MISSING] = "Data missing",
127 [DHCP6_STATUS_CATCHUP_COMPLETE] = "Catch up complete",
128 [DHCP6_STATUS_NOT_SUPPORTED] = "Not supported",
129 [DHCP6_STATUS_TLS_CONNECTION_REFUSED] = "TLS connection refused",
130 [DHCP6_STATUS_ADDRESS_IN_USE] = "Address in use",
131 [DHCP6_STATUS_CONFIGURATION_CONFLICT] = "Configuration conflict",
132 [DHCP6_STATUS_MISSING_BINDING_INFORMATION] = "Missing binding information",
133 [DHCP6_STATUS_OUTDATED_BINDING_INFORMATION] = "Outdated binding information",
134 [DHCP6_STATUS_SERVER_SHUTTING_DOWN] = "Server shutting down",
135 [DHCP6_STATUS_DNS_UPDATE_NOT_SUPPORTED] = "DNS update not supported",
136 [DHCP6_STATUS_EXCESSIVE_TIME_SKEW] = "Excessive time skew",
137 };
138
139 DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int);
140
141 #define DHCP6_CLIENT_DONT_DESTROY(client) \
142 _cleanup_(sd_dhcp6_client_unrefp) _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client)
143
144 static int client_start(sd_dhcp6_client *client, enum DHCP6State state);
145
146 int sd_dhcp6_client_set_callback(
147 sd_dhcp6_client *client,
148 sd_dhcp6_client_callback_t cb,
149 void *userdata) {
150
151 assert_return(client, -EINVAL);
152
153 client->callback = cb;
154 client->userdata = userdata;
155
156 return 0;
157 }
158
159 int sd_dhcp6_client_set_ifindex(sd_dhcp6_client *client, int ifindex) {
160
161 assert_return(client, -EINVAL);
162 assert_return(ifindex >= -1, -EINVAL);
163 assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
164
165 client->ifindex = ifindex;
166 return 0;
167 }
168
169 int sd_dhcp6_client_set_local_address(
170 sd_dhcp6_client *client,
171 const struct in6_addr *local_address) {
172
173 assert_return(client, -EINVAL);
174 assert_return(local_address, -EINVAL);
175 assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) local_address) > 0, -EINVAL);
176
177 assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
178
179 client->local_address = *local_address;
180
181 return 0;
182 }
183
184 int sd_dhcp6_client_set_mac(
185 sd_dhcp6_client *client,
186 const uint8_t *addr, size_t addr_len,
187 uint16_t arp_type) {
188
189 assert_return(client, -EINVAL);
190 assert_return(addr, -EINVAL);
191 assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
192 assert_return(arp_type > 0, -EINVAL);
193
194 assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
195
196 if (arp_type == ARPHRD_ETHER)
197 assert_return(addr_len == ETH_ALEN, -EINVAL);
198 else if (arp_type == ARPHRD_INFINIBAND)
199 assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
200 else
201 return -EINVAL;
202
203 if (client->mac_addr_len == addr_len &&
204 memcmp(&client->mac_addr, addr, addr_len) == 0)
205 return 0;
206
207 memcpy(&client->mac_addr, addr, addr_len);
208 client->mac_addr_len = addr_len;
209 client->arp_type = arp_type;
210
211 return 0;
212 }
213
214 int sd_dhcp6_client_set_prefix_delegation_hint(
215 sd_dhcp6_client *client,
216 uint8_t prefixlen,
217 const struct in6_addr *pd_address) {
218
219 assert_return(client, -EINVAL);
220 assert_return(pd_address, -EINVAL);
221
222 assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
223
224 client->hint_pd_prefix.iapdprefix.address = *pd_address;
225 client->hint_pd_prefix.iapdprefix.prefixlen = prefixlen;
226
227 return 0;
228 }
229
230 int sd_dhcp6_client_add_vendor_option(sd_dhcp6_client *client, sd_dhcp6_option *v) {
231 int r;
232
233 assert_return(client, -EINVAL);
234 assert_return(v, -EINVAL);
235
236 r = ordered_hashmap_ensure_allocated(&client->vendor_options, &dhcp6_option_hash_ops);
237 if (r < 0)
238 return r;
239
240 r = ordered_hashmap_put(client->vendor_options, v, v);
241 if (r < 0)
242 return r;
243
244 sd_dhcp6_option_ref(v);
245
246 return 1;
247 }
248
249 static int client_ensure_duid(sd_dhcp6_client *client) {
250 if (client->duid_len != 0)
251 return 0;
252
253 return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
254 }
255
256 /**
257 * Sets DUID. If duid is non-null, the DUID is set to duid_type + duid
258 * without further modification. Otherwise, if duid_type is supported, DUID
259 * is set based on that type. Otherwise, an error is returned.
260 */
261 static int dhcp6_client_set_duid_internal(
262 sd_dhcp6_client *client,
263 uint16_t duid_type,
264 const void *duid,
265 size_t duid_len,
266 usec_t llt_time) {
267 int r;
268
269 assert_return(client, -EINVAL);
270 assert_return(duid_len == 0 || duid != NULL, -EINVAL);
271 assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
272
273 if (duid != NULL) {
274 r = dhcp_validate_duid_len(duid_type, duid_len, true);
275 if (r < 0) {
276 r = dhcp_validate_duid_len(duid_type, duid_len, false);
277 if (r < 0)
278 return log_dhcp6_client_errno(client, r, "Failed to validate length of DUID: %m");
279
280 log_dhcp6_client(client, "Using DUID of type %u of incorrect length, proceeding.", duid_type);
281 }
282
283 client->duid.type = htobe16(duid_type);
284 memcpy(&client->duid.raw.data, duid, duid_len);
285 client->duid_len = sizeof(client->duid.type) + duid_len;
286 } else
287 switch (duid_type) {
288 case DUID_TYPE_LLT:
289 if (client->mac_addr_len == 0)
290 return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to set DUID-LLT, MAC address is not set.");
291
292 r = dhcp_identifier_set_duid_llt(&client->duid, llt_time, client->mac_addr, client->mac_addr_len, client->arp_type, &client->duid_len);
293 if (r < 0)
294 return log_dhcp6_client_errno(client, r, "Failed to set DUID-LLT: %m");
295 break;
296 case DUID_TYPE_EN:
297 r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
298 if (r < 0)
299 return log_dhcp6_client_errno(client, r, "Failed to set DUID-EN: %m");
300 break;
301 case DUID_TYPE_LL:
302 if (client->mac_addr_len == 0)
303 return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to set DUID-LL, MAC address is not set.");
304
305 r = dhcp_identifier_set_duid_ll(&client->duid, client->mac_addr, client->mac_addr_len, client->arp_type, &client->duid_len);
306 if (r < 0)
307 return log_dhcp6_client_errno(client, r, "Failed to set DUID-LL: %m");
308 break;
309 case DUID_TYPE_UUID:
310 r = dhcp_identifier_set_duid_uuid(&client->duid, &client->duid_len);
311 if (r < 0)
312 return log_dhcp6_client_errno(client, r, "Failed to set DUID-UUID: %m");
313 break;
314 default:
315 return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "Invalid DUID type");
316 }
317
318 return 0;
319 }
320
321 int sd_dhcp6_client_set_duid(
322 sd_dhcp6_client *client,
323 uint16_t duid_type,
324 const void *duid,
325 size_t duid_len) {
326 return dhcp6_client_set_duid_internal(client, duid_type, duid, duid_len, 0);
327 }
328
329 int sd_dhcp6_client_set_duid_llt(
330 sd_dhcp6_client *client,
331 usec_t llt_time) {
332 return dhcp6_client_set_duid_internal(client, DUID_TYPE_LLT, NULL, 0, llt_time);
333 }
334
335 static const char* const dhcp6_duid_type_table[_DUID_TYPE_MAX] = {
336 [DUID_TYPE_LLT] = "DUID-LLT",
337 [DUID_TYPE_EN] = "DUID-EN/Vendor",
338 [DUID_TYPE_LL] = "DUID-LL",
339 [DUID_TYPE_UUID] = "UUID",
340 };
341 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(dhcp6_duid_type, DUIDType);
342
343 int sd_dhcp6_client_duid_as_string(
344 sd_dhcp6_client *client,
345 char **duid) {
346 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
347 const char *v;
348 int r;
349
350 assert_return(client, -EINVAL);
351 assert_return(client->duid_len > 0, -ENODATA);
352
353 v = dhcp6_duid_type_to_string(be16toh(client->duid.type));
354 if (v) {
355 s = strdup(v);
356 if (!s)
357 return -ENOMEM;
358 } else {
359 r = asprintf(&s, "%0x", client->duid.type);
360 if (r < 0)
361 return -ENOMEM;
362 }
363
364 t = hexmem(&client->duid.raw.data, client->duid_len);
365 if (!t)
366 return -ENOMEM;
367
368 p = strjoin(s, ":", t);
369 if (!p)
370 return -ENOMEM;
371
372 *duid = TAKE_PTR(p);
373
374 return 0;
375 }
376
377 int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) {
378 assert_return(client, -EINVAL);
379 assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
380
381 client->ia_na.ia_na.id = htobe32(iaid);
382 client->ia_pd.ia_pd.id = htobe32(iaid);
383 client->iaid_set = true;
384
385 return 0;
386 }
387
388 int sd_dhcp6_client_get_iaid(sd_dhcp6_client *client, uint32_t *iaid) {
389 assert_return(client, -EINVAL);
390 assert_return(iaid, -EINVAL);
391
392 if (!client->iaid_set)
393 return -ENODATA;
394
395 *iaid = be32toh(client->ia_na.ia_na.id);
396
397 return 0;
398 }
399
400 int sd_dhcp6_client_set_fqdn(
401 sd_dhcp6_client *client,
402 const char *fqdn) {
403
404 assert_return(client, -EINVAL);
405
406 /* Make sure FQDN qualifies as DNS and as Linux hostname */
407 if (fqdn &&
408 !(hostname_is_valid(fqdn, false) && dns_name_is_valid(fqdn) > 0))
409 return -EINVAL;
410
411 return free_and_strdup(&client->fqdn, fqdn);
412 }
413
414 int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled) {
415 assert_return(client, -EINVAL);
416 assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
417
418 client->information_request = enabled;
419
420 return 0;
421 }
422
423 int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled) {
424 assert_return(client, -EINVAL);
425 assert_return(enabled, -EINVAL);
426
427 *enabled = client->information_request;
428
429 return 0;
430 }
431
432 int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) {
433 size_t t;
434
435 assert_return(client, -EINVAL);
436 assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
437
438 if (option <= 0 || option >= UINT8_MAX)
439 return -EINVAL;
440
441 for (t = 0; t < client->req_opts_len; t++)
442 if (client->req_opts[t] == htobe16(option))
443 return -EEXIST;
444
445 if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
446 client->req_opts_len + 1))
447 return -ENOMEM;
448
449 client->req_opts[client->req_opts_len++] = htobe16(option);
450
451 return 0;
452 }
453
454 int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, const char *mudurl) {
455
456 assert_return(client, -EINVAL);
457 assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
458 assert_return(mudurl, -EINVAL);
459 assert_return(strlen(mudurl) <= UINT8_MAX, -EINVAL);
460 assert_return(http_url_is_valid(mudurl), -EINVAL);
461
462 return free_and_strdup(&client->mudurl, mudurl);
463 }
464
465 int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client *client, char **user_class) {
466 _cleanup_strv_free_ char **s = NULL;
467 char **p;
468
469 assert_return(client, -EINVAL);
470 assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
471
472 assert_return(user_class, -EINVAL);
473
474 STRV_FOREACH(p, user_class)
475 if (strlen(*p) > UINT16_MAX)
476 return -ENAMETOOLONG;
477
478 s = strv_copy(user_class);
479 if (!s)
480 return -ENOMEM;
481
482 client->user_class = TAKE_PTR(s);
483
484 return 0;
485 }
486
487 int sd_dhcp6_client_set_request_vendor_class(sd_dhcp6_client *client, char **vendor_class) {
488 _cleanup_strv_free_ char **s = NULL;
489 char **p;
490
491 assert_return(client, -EINVAL);
492 assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
493 assert_return(vendor_class, -EINVAL);
494
495 STRV_FOREACH(p, vendor_class)
496 if (strlen(*p) > UINT8_MAX)
497 return -ENAMETOOLONG;
498
499 s = strv_copy(vendor_class);
500 if (!s)
501 return -ENOMEM;
502
503 client->vendor_class = TAKE_PTR(s);
504
505 return 0;
506 }
507
508 int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation) {
509 assert_return(client, -EINVAL);
510 assert_return(delegation, -EINVAL);
511
512 *delegation = FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD);
513
514 return 0;
515 }
516
517 int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, int delegation) {
518 assert_return(client, -EINVAL);
519
520 SET_FLAG(client->request, DHCP6_REQUEST_IA_PD, delegation);
521
522 return 0;
523 }
524
525 int sd_dhcp6_client_get_address_request(sd_dhcp6_client *client, int *request) {
526 assert_return(client, -EINVAL);
527 assert_return(request, -EINVAL);
528
529 *request = FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA);
530
531 return 0;
532 }
533
534 int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client, int request) {
535 assert_return(client, -EINVAL);
536
537 SET_FLAG(client->request, DHCP6_REQUEST_IA_NA, request);
538
539 return 0;
540 }
541
542 int sd_dhcp6_client_set_transaction_id(sd_dhcp6_client *client, uint32_t transaction_id) {
543 assert_return(client, -EINVAL);
544
545 client->transaction_id = transaction_id;
546
547 return 0;
548 }
549
550 int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
551 assert_return(client, -EINVAL);
552
553 if (!client->lease)
554 return -ENOMSG;
555
556 if (ret)
557 *ret = client->lease;
558
559 return 0;
560 }
561
562 int sd_dhcp6_client_add_option(sd_dhcp6_client *client, sd_dhcp6_option *v) {
563 int r;
564
565 assert_return(client, -EINVAL);
566 assert_return(v, -EINVAL);
567
568 r = ordered_hashmap_ensure_allocated(&client->extra_options, &dhcp6_option_hash_ops);
569 if (r < 0)
570 return r;
571
572 r = ordered_hashmap_put(client->extra_options, UINT_TO_PTR(v->option), v);
573 if (r < 0)
574 return r;
575
576 sd_dhcp6_option_ref(v);
577 return 0;
578 }
579
580 static void client_notify(sd_dhcp6_client *client, int event) {
581 assert(client);
582
583 if (client->callback)
584 client->callback(client, event, client->userdata);
585 }
586
587 static int client_reset(sd_dhcp6_client *client) {
588 assert(client);
589
590 client->lease = sd_dhcp6_lease_unref(client->lease);
591
592 client->receive_message =
593 sd_event_source_unref(client->receive_message);
594
595 client->transaction_id = 0;
596 client->transaction_start = 0;
597
598 client->retransmit_time = 0;
599 client->retransmit_count = 0;
600
601 (void) event_source_disable(client->timeout_resend);
602 (void) event_source_disable(client->timeout_resend_expire);
603 (void) event_source_disable(client->timeout_t1);
604 (void) event_source_disable(client->timeout_t2);
605
606 client->state = DHCP6_STATE_STOPPED;
607
608 return 0;
609 }
610
611 static void client_stop(sd_dhcp6_client *client, int error) {
612 DHCP6_CLIENT_DONT_DESTROY(client);
613
614 assert(client);
615
616 client_notify(client, error);
617
618 client_reset(client);
619 }
620
621 static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
622 _cleanup_free_ DHCP6Message *message = NULL;
623 struct in6_addr all_servers =
624 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
625 struct sd_dhcp6_option *j;
626 size_t len, optlen = 512;
627 Iterator i;
628 uint8_t *opt;
629 int r;
630 usec_t elapsed_usec;
631 be16_t elapsed_time;
632
633 assert(client);
634
635 len = sizeof(DHCP6Message) + optlen;
636
637 message = malloc0(len);
638 if (!message)
639 return -ENOMEM;
640
641 opt = (uint8_t *)(message + 1);
642
643 message->transaction_id = client->transaction_id;
644
645 switch(client->state) {
646 case DHCP6_STATE_INFORMATION_REQUEST:
647 message->type = DHCP6_INFORMATION_REQUEST;
648
649 if (client->mudurl) {
650 r = dhcp6_option_append(&opt, &optlen,
651 SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
652 client->mudurl);
653 if (r < 0)
654 return r;
655 }
656
657 break;
658
659 case DHCP6_STATE_SOLICITATION:
660 message->type = DHCP6_SOLICIT;
661
662 r = dhcp6_option_append(&opt, &optlen,
663 SD_DHCP6_OPTION_RAPID_COMMIT, 0, NULL);
664 if (r < 0)
665 return r;
666
667 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
668 r = dhcp6_option_append_ia(&opt, &optlen,
669 &client->ia_na);
670 if (r < 0)
671 return r;
672 }
673
674 if (client->fqdn) {
675 r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
676 if (r < 0)
677 return r;
678 }
679
680 if (client->mudurl) {
681 r = dhcp6_option_append(&opt, &optlen,
682 SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
683 client->mudurl);
684 if (r < 0)
685 return r;
686 }
687
688 if (client->user_class) {
689 r = dhcp6_option_append_user_class(&opt, &optlen, client->user_class);
690 if (r < 0)
691 return r;
692 }
693
694 if (client->vendor_class) {
695 r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class);
696 if (r < 0)
697 return r;
698 }
699
700 if (!ordered_hashmap_isempty(client->vendor_options)) {
701 r = dhcp6_option_append_vendor_option(&opt, &optlen,
702 client->vendor_options);
703 if (r < 0)
704 return r;
705 }
706
707 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
708 r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd, &client->hint_pd_prefix);
709 if (r < 0)
710 return r;
711
712 opt += r;
713 optlen -= r;
714 }
715
716 break;
717
718 case DHCP6_STATE_REQUEST:
719 case DHCP6_STATE_RENEW:
720
721 if (client->state == DHCP6_STATE_REQUEST)
722 message->type = DHCP6_REQUEST;
723 else
724 message->type = DHCP6_RENEW;
725
726 r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_SERVERID,
727 client->lease->serverid_len,
728 client->lease->serverid);
729 if (r < 0)
730 return r;
731
732 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
733 r = dhcp6_option_append_ia(&opt, &optlen,
734 &client->lease->ia);
735 if (r < 0)
736 return r;
737 }
738
739 if (client->fqdn) {
740 r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
741 if (r < 0)
742 return r;
743 }
744
745 if (client->mudurl) {
746 r = dhcp6_option_append(&opt, &optlen,
747 SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
748 client->mudurl);
749 if (r < 0)
750 return r;
751 }
752
753 if (client->user_class) {
754 r = dhcp6_option_append_user_class(&opt, &optlen, client->user_class);
755 if (r < 0)
756 return r;
757 }
758
759 if (client->vendor_class) {
760 r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class);
761 if (r < 0)
762 return r;
763 }
764
765 if (!ordered_hashmap_isempty(client->vendor_options)) {
766 r = dhcp6_option_append_vendor_option(&opt, &optlen, client->vendor_options);
767 if (r < 0)
768 return r;
769 }
770
771 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
772 r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
773 if (r < 0)
774 return r;
775
776 opt += r;
777 optlen -= r;
778 }
779
780 break;
781
782 case DHCP6_STATE_REBIND:
783 message->type = DHCP6_REBIND;
784
785 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
786 r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
787 if (r < 0)
788 return r;
789 }
790
791 if (client->fqdn) {
792 r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
793 if (r < 0)
794 return r;
795 }
796
797 if (client->mudurl) {
798 r = dhcp6_option_append(&opt, &optlen,
799 SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
800 client->mudurl);
801 if (r < 0)
802 return r;
803 }
804
805 if (client->user_class) {
806 r = dhcp6_option_append_user_class(&opt, &optlen, client->user_class);
807 if (r < 0)
808 return r;
809 }
810
811 if (client->vendor_class) {
812 r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class);
813 if (r < 0)
814 return r;
815 }
816
817 if (!ordered_hashmap_isempty(client->vendor_options)) {
818 r = dhcp6_option_append_vendor_option(&opt, &optlen, client->vendor_options);
819 if (r < 0)
820 return r;
821 }
822
823 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
824 r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
825 if (r < 0)
826 return r;
827
828 opt += r;
829 optlen -= r;
830 }
831
832 break;
833
834 case DHCP6_STATE_STOPPED:
835 case DHCP6_STATE_BOUND:
836 return -EINVAL;
837 }
838
839 r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ORO,
840 client->req_opts_len * sizeof(be16_t),
841 client->req_opts);
842 if (r < 0)
843 return r;
844
845 assert(client->duid_len);
846 r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_CLIENTID,
847 client->duid_len, &client->duid);
848 if (r < 0)
849 return r;
850
851 elapsed_usec = time_now - client->transaction_start;
852 if (elapsed_usec < 0xffff * USEC_PER_MSEC * 10)
853 elapsed_time = htobe16(elapsed_usec / USEC_PER_MSEC / 10);
854 else
855 elapsed_time = 0xffff;
856
857 r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ELAPSED_TIME,
858 sizeof(elapsed_time), &elapsed_time);
859 if (r < 0)
860 return r;
861
862 ORDERED_HASHMAP_FOREACH(j, client->extra_options, i) {
863 r = dhcp6_option_append(&opt, &optlen, j->option, j->length, j->data);
864 if (r < 0)
865 return r;
866 }
867
868 r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message,
869 len - optlen);
870 if (r < 0)
871 return r;
872
873 log_dhcp6_client(client, "Sent %s",
874 dhcp6_message_type_to_string(message->type));
875
876 return 0;
877 }
878
879 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
880 sd_dhcp6_client *client = userdata;
881
882 assert(s);
883 assert(client);
884 assert(client->lease);
885
886 (void) event_source_disable(client->timeout_t2);
887
888 log_dhcp6_client(client, "Timeout T2");
889
890 client_start(client, DHCP6_STATE_REBIND);
891
892 return 0;
893 }
894
895 static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) {
896 sd_dhcp6_client *client = userdata;
897
898 assert(s);
899 assert(client);
900 assert(client->lease);
901
902 (void) event_source_disable(client->timeout_t1);
903
904 log_dhcp6_client(client, "Timeout T1");
905
906 client_start(client, DHCP6_STATE_RENEW);
907
908 return 0;
909 }
910
911 static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec, void *userdata) {
912 sd_dhcp6_client *client = userdata;
913 DHCP6_CLIENT_DONT_DESTROY(client);
914 enum DHCP6State state;
915
916 assert(s);
917 assert(client);
918 assert(client->event);
919
920 state = client->state;
921
922 client_stop(client, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE);
923
924 /* RFC 3315, section 18.1.4., says that "...the client may choose to
925 use a Solicit message to locate a new DHCP server..." */
926 if (state == DHCP6_STATE_REBIND)
927 client_start(client, DHCP6_STATE_SOLICITATION);
928
929 return 0;
930 }
931
932 static usec_t client_timeout_compute_random(usec_t val) {
933 return val - (random_u32() % USEC_PER_SEC) * val / 10 / USEC_PER_SEC;
934 }
935
936 static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userdata) {
937 int r = 0;
938 sd_dhcp6_client *client = userdata;
939 usec_t time_now, init_retransmit_time = 0, max_retransmit_time = 0;
940 usec_t max_retransmit_duration = 0;
941 uint8_t max_retransmit_count = 0;
942 char time_string[FORMAT_TIMESPAN_MAX];
943
944 assert(s);
945 assert(client);
946 assert(client->event);
947
948 (void) event_source_disable(client->timeout_resend);
949
950 switch (client->state) {
951 case DHCP6_STATE_INFORMATION_REQUEST:
952 init_retransmit_time = DHCP6_INF_TIMEOUT;
953 max_retransmit_time = DHCP6_INF_MAX_RT;
954
955 break;
956
957 case DHCP6_STATE_SOLICITATION:
958
959 if (client->retransmit_count && client->lease) {
960 client_start(client, DHCP6_STATE_REQUEST);
961 return 0;
962 }
963
964 init_retransmit_time = DHCP6_SOL_TIMEOUT;
965 max_retransmit_time = DHCP6_SOL_MAX_RT;
966
967 break;
968
969 case DHCP6_STATE_REQUEST:
970 init_retransmit_time = DHCP6_REQ_TIMEOUT;
971 max_retransmit_time = DHCP6_REQ_MAX_RT;
972 max_retransmit_count = DHCP6_REQ_MAX_RC;
973
974 break;
975
976 case DHCP6_STATE_RENEW:
977 init_retransmit_time = DHCP6_REN_TIMEOUT;
978 max_retransmit_time = DHCP6_REN_MAX_RT;
979
980 /* RFC 3315, section 18.1.3. says max retransmit duration will
981 be the remaining time until T2. Instead of setting MRD,
982 wait for T2 to trigger with the same end result */
983
984 break;
985
986 case DHCP6_STATE_REBIND:
987 init_retransmit_time = DHCP6_REB_TIMEOUT;
988 max_retransmit_time = DHCP6_REB_MAX_RT;
989
990 if (event_source_is_enabled(client->timeout_resend_expire) <= 0) {
991 uint32_t expire = 0;
992
993 r = dhcp6_lease_ia_rebind_expire(&client->lease->ia, &expire);
994 if (r < 0) {
995 client_stop(client, r);
996 return 0;
997 }
998 max_retransmit_duration = expire * USEC_PER_SEC;
999 }
1000
1001 break;
1002
1003 case DHCP6_STATE_STOPPED:
1004 case DHCP6_STATE_BOUND:
1005 return 0;
1006 }
1007
1008 if (max_retransmit_count > 0 &&
1009 client->retransmit_count >= max_retransmit_count) {
1010 client_stop(client, SD_DHCP6_CLIENT_EVENT_RETRANS_MAX);
1011 return 0;
1012 }
1013
1014 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
1015 if (r < 0)
1016 goto error;
1017
1018 r = client_send_message(client, time_now);
1019 if (r >= 0)
1020 client->retransmit_count++;
1021
1022 if (client->retransmit_time == 0) {
1023 client->retransmit_time =
1024 client_timeout_compute_random(init_retransmit_time);
1025
1026 if (client->state == DHCP6_STATE_SOLICITATION)
1027 client->retransmit_time += init_retransmit_time / 10;
1028
1029 } else {
1030 if (max_retransmit_time > 0 &&
1031 client->retransmit_time > max_retransmit_time / 2)
1032 client->retransmit_time = client_timeout_compute_random(max_retransmit_time);
1033 else
1034 client->retransmit_time += client_timeout_compute_random(client->retransmit_time);
1035 }
1036
1037 log_dhcp6_client(client, "Next retransmission in %s",
1038 format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC));
1039
1040 r = event_reset_time(client->event, &client->timeout_resend,
1041 clock_boottime_or_monotonic(),
1042 time_now + client->retransmit_time, 10 * USEC_PER_MSEC,
1043 client_timeout_resend, client,
1044 client->event_priority, "dhcp6-resend-timer", true);
1045 if (r < 0)
1046 goto error;
1047
1048 if (max_retransmit_duration > 0 && event_source_is_enabled(client->timeout_resend_expire) <= 0) {
1049
1050 log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs",
1051 max_retransmit_duration / USEC_PER_SEC);
1052
1053 r = event_reset_time(client->event, &client->timeout_resend_expire,
1054 clock_boottime_or_monotonic(),
1055 time_now + max_retransmit_duration, USEC_PER_SEC,
1056 client_timeout_resend_expire, client,
1057 client->event_priority, "dhcp6-resend-expire-timer", true);
1058 if (r < 0)
1059 goto error;
1060 }
1061
1062 error:
1063 if (r < 0)
1064 client_stop(client, r);
1065
1066 return 0;
1067 }
1068
1069 static int client_ensure_iaid(sd_dhcp6_client *client) {
1070 int r;
1071 uint32_t iaid;
1072
1073 assert(client);
1074
1075 if (client->iaid_set)
1076 return 0;
1077
1078 r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, true, &iaid);
1079 if (r < 0)
1080 return r;
1081
1082 client->ia_na.ia_na.id = iaid;
1083 client->ia_pd.ia_pd.id = iaid;
1084 client->iaid_set = true;
1085
1086 return 0;
1087 }
1088
1089 static int client_parse_message(
1090 sd_dhcp6_client *client,
1091 DHCP6Message *message,
1092 size_t len,
1093 sd_dhcp6_lease *lease) {
1094
1095 uint16_t ia_na_status = 0, ia_pd_status = 0;
1096 uint32_t lt_t1 = ~0, lt_t2 = ~0;
1097 usec_t irt = IRT_DEFAULT;
1098 bool clientid = false;
1099 size_t pos = 0;
1100 int r;
1101
1102 assert(client);
1103 assert(message);
1104 assert(len >= sizeof(DHCP6Message));
1105 assert(lease);
1106
1107 len -= sizeof(DHCP6Message);
1108
1109 while (pos < len) {
1110 DHCP6Option *option = (DHCP6Option *) &message->options[pos];
1111 uint16_t optcode, optlen;
1112 be32_t iaid_lease;
1113 int status;
1114 uint8_t *optval;
1115
1116 if (len < pos + offsetof(DHCP6Option, data))
1117 return -ENOBUFS;
1118
1119 optcode = be16toh(option->code);
1120 optlen = be16toh(option->len);
1121 optval = option->data;
1122
1123 if (len < pos + offsetof(DHCP6Option, data) + optlen)
1124 return -ENOBUFS;
1125
1126 switch (optcode) {
1127 case SD_DHCP6_OPTION_CLIENTID:
1128 if (clientid) {
1129 log_dhcp6_client(client, "%s contains multiple clientids",
1130 dhcp6_message_type_to_string(message->type));
1131 return -EINVAL;
1132 }
1133
1134 if (optlen != client->duid_len ||
1135 memcmp(&client->duid, optval, optlen) != 0) {
1136 log_dhcp6_client(client, "%s DUID does not match",
1137 dhcp6_message_type_to_string(message->type));
1138
1139 return -EINVAL;
1140 }
1141 clientid = true;
1142
1143 break;
1144
1145 case SD_DHCP6_OPTION_SERVERID:
1146 r = dhcp6_lease_get_serverid(lease, NULL, NULL);
1147 if (r >= 0) {
1148 log_dhcp6_client(client, "%s contains multiple serverids",
1149 dhcp6_message_type_to_string(message->type));
1150 return -EINVAL;
1151 }
1152
1153 r = dhcp6_lease_set_serverid(lease, optval, optlen);
1154 if (r < 0)
1155 return r;
1156
1157 break;
1158
1159 case SD_DHCP6_OPTION_PREFERENCE:
1160 if (optlen != 1)
1161 return -EINVAL;
1162
1163 r = dhcp6_lease_set_preference(lease, optval[0]);
1164 if (r < 0)
1165 return r;
1166
1167 break;
1168
1169 case SD_DHCP6_OPTION_STATUS_CODE:
1170 status = dhcp6_option_parse_status(option, optlen + sizeof(DHCP6Option));
1171 if (status < 0)
1172 return status;
1173
1174 if (status > 0) {
1175 log_dhcp6_client(client, "%s Status %s",
1176 dhcp6_message_type_to_string(message->type),
1177 dhcp6_message_status_to_string(status));
1178
1179 return -EINVAL;
1180 }
1181
1182 break;
1183
1184 case SD_DHCP6_OPTION_IA_NA:
1185 if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
1186 log_dhcp6_client(client, "Information request ignoring IA NA option");
1187
1188 break;
1189 }
1190
1191 r = dhcp6_option_parse_ia(option, &lease->ia, &ia_na_status);
1192 if (r < 0 && r != -ENOMSG)
1193 return r;
1194
1195 if (ia_na_status == DHCP6_STATUS_NO_ADDRS_AVAIL) {
1196 pos += offsetof(DHCP6Option, data) + optlen;
1197 continue;
1198 }
1199
1200 r = dhcp6_lease_get_iaid(lease, &iaid_lease);
1201 if (r < 0)
1202 return r;
1203
1204 if (client->ia_na.ia_na.id != iaid_lease) {
1205 log_dhcp6_client(client, "%s has wrong IAID for IA NA",
1206 dhcp6_message_type_to_string(message->type));
1207 return -EINVAL;
1208 }
1209
1210 if (lease->ia.addresses) {
1211 lt_t1 = MIN(lt_t1, be32toh(lease->ia.ia_na.lifetime_t1));
1212 lt_t2 = MIN(lt_t2, be32toh(lease->ia.ia_na.lifetime_t1));
1213 }
1214
1215 break;
1216
1217 case SD_DHCP6_OPTION_IA_PD:
1218 if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
1219 log_dhcp6_client(client, "Information request ignoring IA PD option");
1220
1221 break;
1222 }
1223
1224 r = dhcp6_option_parse_ia(option, &lease->pd, &ia_pd_status);
1225 if (r < 0 && r != -ENOMSG)
1226 return r;
1227
1228 if (ia_pd_status == DHCP6_STATUS_NO_PREFIX_AVAIL) {
1229 pos += offsetof(DHCP6Option, data) + optlen;
1230 continue;
1231 }
1232
1233 r = dhcp6_lease_get_pd_iaid(lease, &iaid_lease);
1234 if (r < 0)
1235 return r;
1236
1237 if (client->ia_pd.ia_pd.id != iaid_lease) {
1238 log_dhcp6_client(client, "%s has wrong IAID for IA PD",
1239 dhcp6_message_type_to_string(message->type));
1240 return -EINVAL;
1241 }
1242
1243 if (lease->pd.addresses) {
1244 lt_t1 = MIN(lt_t1, be32toh(lease->pd.ia_pd.lifetime_t1));
1245 lt_t2 = MIN(lt_t2, be32toh(lease->pd.ia_pd.lifetime_t2));
1246 }
1247
1248 break;
1249
1250 case SD_DHCP6_OPTION_RAPID_COMMIT:
1251 r = dhcp6_lease_set_rapid_commit(lease);
1252 if (r < 0)
1253 return r;
1254
1255 break;
1256
1257 case SD_DHCP6_OPTION_DNS_SERVERS:
1258 r = dhcp6_lease_set_dns(lease, optval, optlen);
1259 if (r < 0)
1260 return r;
1261
1262 break;
1263
1264 case SD_DHCP6_OPTION_DOMAIN_LIST:
1265 r = dhcp6_lease_set_domains(lease, optval, optlen);
1266 if (r < 0)
1267 return r;
1268
1269 break;
1270
1271 case SD_DHCP6_OPTION_NTP_SERVER:
1272 r = dhcp6_lease_set_ntp(lease, optval, optlen);
1273 if (r < 0)
1274 return r;
1275
1276 break;
1277
1278 case SD_DHCP6_OPTION_SNTP_SERVERS:
1279 r = dhcp6_lease_set_sntp(lease, optval, optlen);
1280 if (r < 0)
1281 return r;
1282
1283 break;
1284
1285 case SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME:
1286 if (optlen != 4)
1287 return -EINVAL;
1288
1289 irt = unaligned_read_be32((be32_t *) optval) * USEC_PER_SEC;
1290 break;
1291 }
1292
1293 pos += offsetof(DHCP6Option, data) + optlen;
1294 }
1295
1296 if (ia_na_status > 0 && ia_pd_status > 0) {
1297 log_dhcp6_client(client, "No IA_PD prefix or IA_NA address received. Ignoring.");
1298 return -EINVAL;
1299 }
1300
1301 if (!clientid) {
1302 log_dhcp6_client(client, "%s has incomplete options",
1303 dhcp6_message_type_to_string(message->type));
1304 return -EINVAL;
1305 }
1306
1307 if (client->state != DHCP6_STATE_INFORMATION_REQUEST) {
1308 r = dhcp6_lease_get_serverid(lease, NULL, NULL);
1309 if (r < 0) {
1310 log_dhcp6_client(client, "%s has no server id",
1311 dhcp6_message_type_to_string(message->type));
1312 return -EINVAL;
1313 }
1314
1315 } else {
1316 if (lease->ia.addresses) {
1317 lease->ia.ia_na.lifetime_t1 = htobe32(lt_t1);
1318 lease->ia.ia_na.lifetime_t2 = htobe32(lt_t2);
1319 }
1320
1321 if (lease->pd.addresses) {
1322 lease->pd.ia_pd.lifetime_t1 = htobe32(lt_t1);
1323 lease->pd.ia_pd.lifetime_t2 = htobe32(lt_t2);
1324 }
1325 }
1326
1327 client->information_refresh_time_usec = MAX(irt, IRT_MINIMUM);
1328
1329 return 0;
1330 }
1331
1332 static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len) {
1333 _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
1334 bool rapid_commit;
1335 int r;
1336
1337 assert(client);
1338 assert(reply);
1339
1340 if (reply->type != DHCP6_REPLY)
1341 return 0;
1342
1343 r = dhcp6_lease_new(&lease);
1344 if (r < 0)
1345 return -ENOMEM;
1346
1347 r = client_parse_message(client, reply, len, lease);
1348 if (r < 0)
1349 return r;
1350
1351 if (client->state == DHCP6_STATE_SOLICITATION) {
1352 r = dhcp6_lease_get_rapid_commit(lease, &rapid_commit);
1353 if (r < 0)
1354 return r;
1355
1356 if (!rapid_commit)
1357 return 0;
1358 }
1359
1360 sd_dhcp6_lease_unref(client->lease);
1361 client->lease = TAKE_PTR(lease);
1362
1363 return DHCP6_STATE_BOUND;
1364 }
1365
1366 static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len) {
1367 _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
1368 uint8_t pref_advertise = 0, pref_lease = 0;
1369 int r;
1370
1371 if (advertise->type != DHCP6_ADVERTISE)
1372 return 0;
1373
1374 r = dhcp6_lease_new(&lease);
1375 if (r < 0)
1376 return r;
1377
1378 r = client_parse_message(client, advertise, len, lease);
1379 if (r < 0)
1380 return r;
1381
1382 r = dhcp6_lease_get_preference(lease, &pref_advertise);
1383 if (r < 0)
1384 return r;
1385
1386 r = dhcp6_lease_get_preference(client->lease, &pref_lease);
1387
1388 if (r < 0 || pref_advertise > pref_lease) {
1389 sd_dhcp6_lease_unref(client->lease);
1390 client->lease = TAKE_PTR(lease);
1391 r = 0;
1392 }
1393
1394 if (pref_advertise == 255 || client->retransmit_count > 1)
1395 r = DHCP6_STATE_REQUEST;
1396
1397 return r;
1398 }
1399
1400 static int client_receive_message(
1401 sd_event_source *s,
1402 int fd, uint32_t
1403 revents,
1404 void *userdata) {
1405
1406 sd_dhcp6_client *client = userdata;
1407 DHCP6_CLIENT_DONT_DESTROY(client);
1408 _cleanup_free_ DHCP6Message *message = NULL;
1409 ssize_t buflen, len;
1410 int r = 0;
1411
1412 assert(s);
1413 assert(client);
1414 assert(client->event);
1415
1416 buflen = next_datagram_size_fd(fd);
1417 if (buflen == -ENETDOWN) {
1418 /* the link is down. Don't return an error or the I/O event
1419 source will be disconnected and we won't be able to receive
1420 packets again when the link comes back. */
1421 return 0;
1422 }
1423 if (buflen < 0)
1424 return buflen;
1425
1426 message = malloc(buflen);
1427 if (!message)
1428 return -ENOMEM;
1429
1430 len = recv(fd, message, buflen, 0);
1431 if (len < 0) {
1432 /* see comment above for why we shouldn't error out on ENETDOWN. */
1433 if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
1434 return 0;
1435
1436 return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m");
1437
1438 }
1439 if ((size_t) len < sizeof(DHCP6Message)) {
1440 log_dhcp6_client(client, "Too small to be DHCP6 message: ignoring");
1441 return 0;
1442 }
1443
1444 switch(message->type) {
1445 case DHCP6_SOLICIT:
1446 case DHCP6_REQUEST:
1447 case DHCP6_CONFIRM:
1448 case DHCP6_RENEW:
1449 case DHCP6_REBIND:
1450 case DHCP6_RELEASE:
1451 case DHCP6_DECLINE:
1452 case DHCP6_INFORMATION_REQUEST:
1453 case DHCP6_RELAY_FORW:
1454 case DHCP6_RELAY_REPL:
1455 return 0;
1456
1457 case DHCP6_ADVERTISE:
1458 case DHCP6_REPLY:
1459 case DHCP6_RECONFIGURE:
1460 break;
1461
1462 default:
1463 log_dhcp6_client(client, "Unknown message type %d", message->type);
1464 return 0;
1465 }
1466
1467 if (client->transaction_id != (message->transaction_id &
1468 htobe32(0x00ffffff)))
1469 return 0;
1470
1471 switch (client->state) {
1472 case DHCP6_STATE_INFORMATION_REQUEST:
1473 r = client_receive_reply(client, message, len);
1474 if (r < 0)
1475 return 0;
1476
1477 client_notify(client, SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST);
1478
1479 client_start(client, DHCP6_STATE_STOPPED);
1480
1481 break;
1482
1483 case DHCP6_STATE_SOLICITATION:
1484 r = client_receive_advertise(client, message, len);
1485
1486 if (r == DHCP6_STATE_REQUEST) {
1487 client_start(client, r);
1488
1489 break;
1490 }
1491
1492 _fallthrough_; /* for Soliciation Rapid Commit option check */
1493 case DHCP6_STATE_REQUEST:
1494 case DHCP6_STATE_RENEW:
1495 case DHCP6_STATE_REBIND:
1496
1497 r = client_receive_reply(client, message, len);
1498 if (r < 0)
1499 return 0;
1500
1501 if (r == DHCP6_STATE_BOUND) {
1502
1503 r = client_start(client, DHCP6_STATE_BOUND);
1504 if (r < 0) {
1505 client_stop(client, r);
1506 return 0;
1507 }
1508
1509 client_notify(client, SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE);
1510 }
1511
1512 break;
1513
1514 case DHCP6_STATE_BOUND:
1515
1516 break;
1517
1518 case DHCP6_STATE_STOPPED:
1519 return 0;
1520 }
1521
1522 log_dhcp6_client(client, "Recv %s",
1523 dhcp6_message_type_to_string(message->type));
1524
1525 return 0;
1526 }
1527
1528 static int client_get_lifetime(sd_dhcp6_client *client, uint32_t *lifetime_t1,
1529 uint32_t *lifetime_t2) {
1530 assert_return(client, -EINVAL);
1531 assert_return(client->lease, -EINVAL);
1532
1533 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA) && client->lease->ia.addresses) {
1534 *lifetime_t1 = be32toh(client->lease->ia.ia_na.lifetime_t1);
1535 *lifetime_t2 = be32toh(client->lease->ia.ia_na.lifetime_t2);
1536
1537 return 0;
1538 }
1539
1540 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) {
1541 *lifetime_t1 = be32toh(client->lease->pd.ia_pd.lifetime_t1);
1542 *lifetime_t2 = be32toh(client->lease->pd.ia_pd.lifetime_t2);
1543
1544 return 0;
1545 }
1546
1547 return -ENOMSG;
1548 }
1549
1550 static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
1551 int r;
1552 usec_t timeout, time_now;
1553 char time_string[FORMAT_TIMESPAN_MAX];
1554 uint32_t lifetime_t1, lifetime_t2;
1555
1556 assert_return(client, -EINVAL);
1557 assert_return(client->event, -EINVAL);
1558 assert_return(client->ifindex > 0, -EINVAL);
1559 assert_return(client->state != state, -EINVAL);
1560
1561 (void) event_source_disable(client->timeout_resend_expire);
1562 (void) event_source_disable(client->timeout_resend);
1563 client->retransmit_time = 0;
1564 client->retransmit_count = 0;
1565
1566 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
1567 if (r < 0)
1568 return r;
1569
1570 if (!client->receive_message) {
1571 r = sd_event_add_io(client->event, &client->receive_message,
1572 client->fd, EPOLLIN, client_receive_message,
1573 client);
1574 if (r < 0)
1575 goto error;
1576
1577 r = sd_event_source_set_priority(client->receive_message,
1578 client->event_priority);
1579 if (r < 0)
1580 goto error;
1581
1582 r = sd_event_source_set_description(client->receive_message,
1583 "dhcp6-receive-message");
1584 if (r < 0)
1585 goto error;
1586 }
1587
1588 switch (state) {
1589 case DHCP6_STATE_STOPPED:
1590 if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
1591 client->state = DHCP6_STATE_STOPPED;
1592
1593 return 0;
1594 }
1595
1596 _fallthrough_;
1597 case DHCP6_STATE_SOLICITATION:
1598 client->state = DHCP6_STATE_SOLICITATION;
1599
1600 break;
1601
1602 case DHCP6_STATE_INFORMATION_REQUEST:
1603 case DHCP6_STATE_REQUEST:
1604 case DHCP6_STATE_RENEW:
1605 case DHCP6_STATE_REBIND:
1606
1607 client->state = state;
1608
1609 break;
1610
1611 case DHCP6_STATE_BOUND:
1612
1613 r = client_get_lifetime(client, &lifetime_t1, &lifetime_t2);
1614 if (r < 0)
1615 goto error;
1616
1617 if (lifetime_t1 == 0xffffffff || lifetime_t2 == 0xffffffff) {
1618 log_dhcp6_client(client, "Infinite T1 0x%08x or T2 0x%08x",
1619 lifetime_t1, lifetime_t2);
1620
1621 return 0;
1622 }
1623
1624 timeout = client_timeout_compute_random(lifetime_t1 * USEC_PER_SEC);
1625
1626 log_dhcp6_client(client, "T1 expires in %s",
1627 format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
1628
1629 r = event_reset_time(client->event, &client->timeout_t1,
1630 clock_boottime_or_monotonic(),
1631 time_now + timeout, 10 * USEC_PER_SEC,
1632 client_timeout_t1, client,
1633 client->event_priority, "dhcp6-t1-timeout", true);
1634 if (r < 0)
1635 goto error;
1636
1637 timeout = client_timeout_compute_random(lifetime_t2 * USEC_PER_SEC);
1638
1639 log_dhcp6_client(client, "T2 expires in %s",
1640 format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
1641
1642 r = event_reset_time(client->event, &client->timeout_t2,
1643 clock_boottime_or_monotonic(),
1644 time_now + timeout, 10 * USEC_PER_SEC,
1645 client_timeout_t2, client,
1646 client->event_priority, "dhcp6-t2-timeout", true);
1647 if (r < 0)
1648 goto error;
1649
1650 client->state = state;
1651
1652 return 0;
1653 }
1654
1655 client->transaction_id = random_u32() & htobe32(0x00ffffff);
1656 client->transaction_start = time_now;
1657
1658 r = event_reset_time(client->event, &client->timeout_resend,
1659 clock_boottime_or_monotonic(),
1660 0, 0,
1661 client_timeout_resend, client,
1662 client->event_priority, "dhcp6-resend-timeout", true);
1663 if (r < 0)
1664 goto error;
1665
1666 return 0;
1667
1668 error:
1669 client_reset(client);
1670 return r;
1671 }
1672
1673 int sd_dhcp6_client_stop(sd_dhcp6_client *client) {
1674 assert_return(client, -EINVAL);
1675
1676 client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP);
1677
1678 client->fd = safe_close(client->fd);
1679
1680 return 0;
1681 }
1682
1683 int sd_dhcp6_client_is_running(sd_dhcp6_client *client) {
1684 assert_return(client, -EINVAL);
1685
1686 return client->state != DHCP6_STATE_STOPPED;
1687 }
1688
1689 int sd_dhcp6_client_start(sd_dhcp6_client *client) {
1690 enum DHCP6State state = DHCP6_STATE_SOLICITATION;
1691 int r = 0;
1692
1693 assert_return(client, -EINVAL);
1694 assert_return(client->event, -EINVAL);
1695 assert_return(client->ifindex > 0, -EINVAL);
1696 assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &client->local_address) > 0, -EINVAL);
1697
1698 if (!IN_SET(client->state, DHCP6_STATE_STOPPED))
1699 return -EBUSY;
1700
1701 if (!client->information_request && !client->request)
1702 return -EINVAL;
1703
1704 r = client_reset(client);
1705 if (r < 0)
1706 return r;
1707
1708 r = client_ensure_iaid(client);
1709 if (r < 0)
1710 return r;
1711
1712 r = client_ensure_duid(client);
1713 if (r < 0)
1714 return r;
1715
1716 if (client->fd < 0) {
1717 r = dhcp6_network_bind_udp_socket(client->ifindex, &client->local_address);
1718 if (r < 0) {
1719 _cleanup_free_ char *p = NULL;
1720
1721 (void) in_addr_to_string(AF_INET6, (const union in_addr_union*) &client->local_address, &p);
1722 return log_dhcp6_client_errno(client, r,
1723 "Failed to bind to UDP socket at address %s: %m", strna(p));
1724 }
1725
1726 client->fd = r;
1727 }
1728
1729 if (client->information_request) {
1730 usec_t t = now(CLOCK_MONOTONIC);
1731
1732 if (t < usec_add(client->information_request_time_usec, client->information_refresh_time_usec))
1733 return 0;
1734
1735 client->information_request_time_usec = t;
1736 state = DHCP6_STATE_INFORMATION_REQUEST;
1737 }
1738
1739 log_dhcp6_client(client, "Started in %s mode",
1740 client->information_request? "Information request":
1741 "Managed");
1742
1743 return client_start(client, state);
1744 }
1745
1746 int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int64_t priority) {
1747 int r;
1748
1749 assert_return(client, -EINVAL);
1750 assert_return(!client->event, -EBUSY);
1751
1752 if (event)
1753 client->event = sd_event_ref(event);
1754 else {
1755 r = sd_event_default(&client->event);
1756 if (r < 0)
1757 return 0;
1758 }
1759
1760 client->event_priority = priority;
1761
1762 return 0;
1763 }
1764
1765 int sd_dhcp6_client_detach_event(sd_dhcp6_client *client) {
1766 assert_return(client, -EINVAL);
1767
1768 client->event = sd_event_unref(client->event);
1769
1770 return 0;
1771 }
1772
1773 sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) {
1774 assert_return(client, NULL);
1775
1776 return client->event;
1777 }
1778
1779 static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) {
1780 assert(client);
1781
1782 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
1783 client->timeout_resend_expire = sd_event_source_unref(client->timeout_resend_expire);
1784 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
1785 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
1786
1787 client_reset(client);
1788
1789 client->fd = safe_close(client->fd);
1790
1791 sd_dhcp6_client_detach_event(client);
1792
1793 free(client->req_opts);
1794 free(client->fqdn);
1795 free(client->mudurl);
1796
1797 ordered_hashmap_free(client->extra_options);
1798 strv_free(client->user_class);
1799 strv_free(client->vendor_class);
1800
1801 return mfree(client);
1802 }
1803
1804 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_client, sd_dhcp6_client, dhcp6_client_free);
1805
1806 int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
1807 _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
1808 _cleanup_free_ be16_t *req_opts = NULL;
1809 size_t t;
1810
1811 assert_return(ret, -EINVAL);
1812
1813 req_opts = new(be16_t, ELEMENTSOF(default_req_opts));
1814 if (!req_opts)
1815 return -ENOMEM;
1816
1817 for (t = 0; t < ELEMENTSOF(default_req_opts); t++)
1818 req_opts[t] = htobe16(default_req_opts[t]);
1819
1820 client = new(sd_dhcp6_client, 1);
1821 if (!client)
1822 return -ENOMEM;
1823
1824 *client = (sd_dhcp6_client) {
1825 .n_ref = 1,
1826 .ia_na.type = SD_DHCP6_OPTION_IA_NA,
1827 .ia_pd.type = SD_DHCP6_OPTION_IA_PD,
1828 .ifindex = -1,
1829 .request = DHCP6_REQUEST_IA_NA,
1830 .fd = -1,
1831 .req_opts_len = ELEMENTSOF(default_req_opts),
1832 .hint_pd_prefix.iapdprefix.lifetime_preferred = (be32_t) -1,
1833 .hint_pd_prefix.iapdprefix.lifetime_valid = (be32_t) -1,
1834 .req_opts = TAKE_PTR(req_opts),
1835 };
1836
1837 *ret = TAKE_PTR(client);
1838
1839 return 0;
1840 }