]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp6-client.c
tree-wide: define iterator inside of the macro
[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 > 0, -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 uint8_t *opt;
628 int r;
629 usec_t elapsed_usec;
630 be16_t elapsed_time;
631
632 assert(client);
633
634 len = sizeof(DHCP6Message) + optlen;
635
636 message = malloc0(len);
637 if (!message)
638 return -ENOMEM;
639
640 opt = (uint8_t *)(message + 1);
641
642 message->transaction_id = client->transaction_id;
643
644 switch(client->state) {
645 case DHCP6_STATE_INFORMATION_REQUEST:
646 message->type = DHCP6_INFORMATION_REQUEST;
647
648 if (client->mudurl) {
649 r = dhcp6_option_append(&opt, &optlen,
650 SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
651 client->mudurl);
652 if (r < 0)
653 return r;
654 }
655
656 break;
657
658 case DHCP6_STATE_SOLICITATION:
659 message->type = DHCP6_SOLICIT;
660
661 r = dhcp6_option_append(&opt, &optlen,
662 SD_DHCP6_OPTION_RAPID_COMMIT, 0, NULL);
663 if (r < 0)
664 return r;
665
666 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
667 r = dhcp6_option_append_ia(&opt, &optlen,
668 &client->ia_na);
669 if (r < 0)
670 return r;
671 }
672
673 if (client->fqdn) {
674 r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
675 if (r < 0)
676 return r;
677 }
678
679 if (client->mudurl) {
680 r = dhcp6_option_append(&opt, &optlen,
681 SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
682 client->mudurl);
683 if (r < 0)
684 return r;
685 }
686
687 if (client->user_class) {
688 r = dhcp6_option_append_user_class(&opt, &optlen, client->user_class);
689 if (r < 0)
690 return r;
691 }
692
693 if (client->vendor_class) {
694 r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class);
695 if (r < 0)
696 return r;
697 }
698
699 if (!ordered_hashmap_isempty(client->vendor_options)) {
700 r = dhcp6_option_append_vendor_option(&opt, &optlen,
701 client->vendor_options);
702 if (r < 0)
703 return r;
704 }
705
706 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
707 r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd, &client->hint_pd_prefix);
708 if (r < 0)
709 return r;
710
711 opt += r;
712 optlen -= r;
713 }
714
715 break;
716
717 case DHCP6_STATE_REQUEST:
718 case DHCP6_STATE_RENEW:
719
720 if (client->state == DHCP6_STATE_REQUEST)
721 message->type = DHCP6_REQUEST;
722 else
723 message->type = DHCP6_RENEW;
724
725 r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_SERVERID,
726 client->lease->serverid_len,
727 client->lease->serverid);
728 if (r < 0)
729 return r;
730
731 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
732 r = dhcp6_option_append_ia(&opt, &optlen,
733 &client->lease->ia);
734 if (r < 0)
735 return r;
736 }
737
738 if (client->fqdn) {
739 r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
740 if (r < 0)
741 return r;
742 }
743
744 if (client->mudurl) {
745 r = dhcp6_option_append(&opt, &optlen,
746 SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
747 client->mudurl);
748 if (r < 0)
749 return r;
750 }
751
752 if (client->user_class) {
753 r = dhcp6_option_append_user_class(&opt, &optlen, client->user_class);
754 if (r < 0)
755 return r;
756 }
757
758 if (client->vendor_class) {
759 r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class);
760 if (r < 0)
761 return r;
762 }
763
764 if (!ordered_hashmap_isempty(client->vendor_options)) {
765 r = dhcp6_option_append_vendor_option(&opt, &optlen, client->vendor_options);
766 if (r < 0)
767 return r;
768 }
769
770 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
771 r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
772 if (r < 0)
773 return r;
774
775 opt += r;
776 optlen -= r;
777 }
778
779 break;
780
781 case DHCP6_STATE_REBIND:
782 message->type = DHCP6_REBIND;
783
784 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
785 r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
786 if (r < 0)
787 return r;
788 }
789
790 if (client->fqdn) {
791 r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
792 if (r < 0)
793 return r;
794 }
795
796 if (client->mudurl) {
797 r = dhcp6_option_append(&opt, &optlen,
798 SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
799 client->mudurl);
800 if (r < 0)
801 return r;
802 }
803
804 if (client->user_class) {
805 r = dhcp6_option_append_user_class(&opt, &optlen, client->user_class);
806 if (r < 0)
807 return r;
808 }
809
810 if (client->vendor_class) {
811 r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class);
812 if (r < 0)
813 return r;
814 }
815
816 if (!ordered_hashmap_isempty(client->vendor_options)) {
817 r = dhcp6_option_append_vendor_option(&opt, &optlen, client->vendor_options);
818 if (r < 0)
819 return r;
820 }
821
822 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
823 r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
824 if (r < 0)
825 return r;
826
827 opt += r;
828 optlen -= r;
829 }
830
831 break;
832
833 case DHCP6_STATE_STOPPED:
834 case DHCP6_STATE_BOUND:
835 return -EINVAL;
836 }
837
838 r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ORO,
839 client->req_opts_len * sizeof(be16_t),
840 client->req_opts);
841 if (r < 0)
842 return r;
843
844 assert(client->duid_len);
845 r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_CLIENTID,
846 client->duid_len, &client->duid);
847 if (r < 0)
848 return r;
849
850 elapsed_usec = time_now - client->transaction_start;
851 if (elapsed_usec < 0xffff * USEC_PER_MSEC * 10)
852 elapsed_time = htobe16(elapsed_usec / USEC_PER_MSEC / 10);
853 else
854 elapsed_time = 0xffff;
855
856 r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ELAPSED_TIME,
857 sizeof(elapsed_time), &elapsed_time);
858 if (r < 0)
859 return r;
860
861 ORDERED_HASHMAP_FOREACH(j, client->extra_options) {
862 r = dhcp6_option_append(&opt, &optlen, j->option, j->length, j->data);
863 if (r < 0)
864 return r;
865 }
866
867 r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message,
868 len - optlen);
869 if (r < 0)
870 return r;
871
872 log_dhcp6_client(client, "Sent %s",
873 dhcp6_message_type_to_string(message->type));
874
875 return 0;
876 }
877
878 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
879 sd_dhcp6_client *client = userdata;
880
881 assert(s);
882 assert(client);
883 assert(client->lease);
884
885 (void) event_source_disable(client->timeout_t2);
886
887 log_dhcp6_client(client, "Timeout T2");
888
889 client_start(client, DHCP6_STATE_REBIND);
890
891 return 0;
892 }
893
894 static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) {
895 sd_dhcp6_client *client = userdata;
896
897 assert(s);
898 assert(client);
899 assert(client->lease);
900
901 (void) event_source_disable(client->timeout_t1);
902
903 log_dhcp6_client(client, "Timeout T1");
904
905 client_start(client, DHCP6_STATE_RENEW);
906
907 return 0;
908 }
909
910 static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec, void *userdata) {
911 sd_dhcp6_client *client = userdata;
912 DHCP6_CLIENT_DONT_DESTROY(client);
913 enum DHCP6State state;
914
915 assert(s);
916 assert(client);
917 assert(client->event);
918
919 state = client->state;
920
921 client_stop(client, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE);
922
923 /* RFC 3315, section 18.1.4., says that "...the client may choose to
924 use a Solicit message to locate a new DHCP server..." */
925 if (state == DHCP6_STATE_REBIND)
926 client_start(client, DHCP6_STATE_SOLICITATION);
927
928 return 0;
929 }
930
931 static usec_t client_timeout_compute_random(usec_t val) {
932 return val - (random_u32() % USEC_PER_SEC) * val / 10 / USEC_PER_SEC;
933 }
934
935 static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userdata) {
936 int r = 0;
937 sd_dhcp6_client *client = userdata;
938 usec_t time_now, init_retransmit_time = 0, max_retransmit_time = 0;
939 usec_t max_retransmit_duration = 0;
940 uint8_t max_retransmit_count = 0;
941 char time_string[FORMAT_TIMESPAN_MAX];
942
943 assert(s);
944 assert(client);
945 assert(client->event);
946
947 (void) event_source_disable(client->timeout_resend);
948
949 switch (client->state) {
950 case DHCP6_STATE_INFORMATION_REQUEST:
951 init_retransmit_time = DHCP6_INF_TIMEOUT;
952 max_retransmit_time = DHCP6_INF_MAX_RT;
953
954 break;
955
956 case DHCP6_STATE_SOLICITATION:
957
958 if (client->retransmit_count && client->lease) {
959 client_start(client, DHCP6_STATE_REQUEST);
960 return 0;
961 }
962
963 init_retransmit_time = DHCP6_SOL_TIMEOUT;
964 max_retransmit_time = DHCP6_SOL_MAX_RT;
965
966 break;
967
968 case DHCP6_STATE_REQUEST:
969 init_retransmit_time = DHCP6_REQ_TIMEOUT;
970 max_retransmit_time = DHCP6_REQ_MAX_RT;
971 max_retransmit_count = DHCP6_REQ_MAX_RC;
972
973 break;
974
975 case DHCP6_STATE_RENEW:
976 init_retransmit_time = DHCP6_REN_TIMEOUT;
977 max_retransmit_time = DHCP6_REN_MAX_RT;
978
979 /* RFC 3315, section 18.1.3. says max retransmit duration will
980 be the remaining time until T2. Instead of setting MRD,
981 wait for T2 to trigger with the same end result */
982
983 break;
984
985 case DHCP6_STATE_REBIND:
986 init_retransmit_time = DHCP6_REB_TIMEOUT;
987 max_retransmit_time = DHCP6_REB_MAX_RT;
988
989 if (event_source_is_enabled(client->timeout_resend_expire) <= 0) {
990 uint32_t expire = 0;
991
992 r = dhcp6_lease_ia_rebind_expire(&client->lease->ia, &expire);
993 if (r < 0) {
994 client_stop(client, r);
995 return 0;
996 }
997 max_retransmit_duration = expire * USEC_PER_SEC;
998 }
999
1000 break;
1001
1002 case DHCP6_STATE_STOPPED:
1003 case DHCP6_STATE_BOUND:
1004 return 0;
1005 }
1006
1007 if (max_retransmit_count > 0 &&
1008 client->retransmit_count >= max_retransmit_count) {
1009 client_stop(client, SD_DHCP6_CLIENT_EVENT_RETRANS_MAX);
1010 return 0;
1011 }
1012
1013 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
1014 if (r < 0)
1015 goto error;
1016
1017 r = client_send_message(client, time_now);
1018 if (r >= 0)
1019 client->retransmit_count++;
1020
1021 if (client->retransmit_time == 0) {
1022 client->retransmit_time =
1023 client_timeout_compute_random(init_retransmit_time);
1024
1025 if (client->state == DHCP6_STATE_SOLICITATION)
1026 client->retransmit_time += init_retransmit_time / 10;
1027
1028 } else {
1029 if (max_retransmit_time > 0 &&
1030 client->retransmit_time > max_retransmit_time / 2)
1031 client->retransmit_time = client_timeout_compute_random(max_retransmit_time);
1032 else
1033 client->retransmit_time += client_timeout_compute_random(client->retransmit_time);
1034 }
1035
1036 log_dhcp6_client(client, "Next retransmission in %s",
1037 format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC));
1038
1039 r = event_reset_time(client->event, &client->timeout_resend,
1040 clock_boottime_or_monotonic(),
1041 time_now + client->retransmit_time, 10 * USEC_PER_MSEC,
1042 client_timeout_resend, client,
1043 client->event_priority, "dhcp6-resend-timer", true);
1044 if (r < 0)
1045 goto error;
1046
1047 if (max_retransmit_duration > 0 && event_source_is_enabled(client->timeout_resend_expire) <= 0) {
1048
1049 log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs",
1050 max_retransmit_duration / USEC_PER_SEC);
1051
1052 r = event_reset_time(client->event, &client->timeout_resend_expire,
1053 clock_boottime_or_monotonic(),
1054 time_now + max_retransmit_duration, USEC_PER_SEC,
1055 client_timeout_resend_expire, client,
1056 client->event_priority, "dhcp6-resend-expire-timer", true);
1057 if (r < 0)
1058 goto error;
1059 }
1060
1061 error:
1062 if (r < 0)
1063 client_stop(client, r);
1064
1065 return 0;
1066 }
1067
1068 static int client_ensure_iaid(sd_dhcp6_client *client) {
1069 int r;
1070 uint32_t iaid;
1071
1072 assert(client);
1073
1074 if (client->iaid_set)
1075 return 0;
1076
1077 r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, true, &iaid);
1078 if (r < 0)
1079 return r;
1080
1081 client->ia_na.ia_na.id = iaid;
1082 client->ia_pd.ia_pd.id = iaid;
1083 client->iaid_set = true;
1084
1085 return 0;
1086 }
1087
1088 static int client_parse_message(
1089 sd_dhcp6_client *client,
1090 DHCP6Message *message,
1091 size_t len,
1092 sd_dhcp6_lease *lease) {
1093
1094 uint16_t ia_na_status = 0, ia_pd_status = 0;
1095 uint32_t lt_t1 = ~0, lt_t2 = ~0;
1096 usec_t irt = IRT_DEFAULT;
1097 bool clientid = false;
1098 size_t pos = 0;
1099 int r;
1100
1101 assert(client);
1102 assert(message);
1103 assert(len >= sizeof(DHCP6Message));
1104 assert(lease);
1105
1106 len -= sizeof(DHCP6Message);
1107
1108 while (pos < len) {
1109 DHCP6Option *option = (DHCP6Option *) &message->options[pos];
1110 uint16_t optcode, optlen;
1111 be32_t iaid_lease;
1112 int status;
1113 uint8_t *optval;
1114
1115 if (len < pos + offsetof(DHCP6Option, data))
1116 return -ENOBUFS;
1117
1118 optcode = be16toh(option->code);
1119 optlen = be16toh(option->len);
1120 optval = option->data;
1121
1122 if (len < pos + offsetof(DHCP6Option, data) + optlen)
1123 return -ENOBUFS;
1124
1125 switch (optcode) {
1126 case SD_DHCP6_OPTION_CLIENTID:
1127 if (clientid) {
1128 log_dhcp6_client(client, "%s contains multiple clientids",
1129 dhcp6_message_type_to_string(message->type));
1130 return -EINVAL;
1131 }
1132
1133 if (optlen != client->duid_len ||
1134 memcmp(&client->duid, optval, optlen) != 0) {
1135 log_dhcp6_client(client, "%s DUID does not match",
1136 dhcp6_message_type_to_string(message->type));
1137
1138 return -EINVAL;
1139 }
1140 clientid = true;
1141
1142 break;
1143
1144 case SD_DHCP6_OPTION_SERVERID:
1145 r = dhcp6_lease_get_serverid(lease, NULL, NULL);
1146 if (r >= 0) {
1147 log_dhcp6_client(client, "%s contains multiple serverids",
1148 dhcp6_message_type_to_string(message->type));
1149 return -EINVAL;
1150 }
1151
1152 r = dhcp6_lease_set_serverid(lease, optval, optlen);
1153 if (r < 0)
1154 return r;
1155
1156 break;
1157
1158 case SD_DHCP6_OPTION_PREFERENCE:
1159 if (optlen != 1)
1160 return -EINVAL;
1161
1162 r = dhcp6_lease_set_preference(lease, optval[0]);
1163 if (r < 0)
1164 return r;
1165
1166 break;
1167
1168 case SD_DHCP6_OPTION_STATUS_CODE:
1169 status = dhcp6_option_parse_status(option, optlen + sizeof(DHCP6Option));
1170 if (status < 0)
1171 return status;
1172
1173 if (status > 0) {
1174 log_dhcp6_client(client, "%s Status %s",
1175 dhcp6_message_type_to_string(message->type),
1176 dhcp6_message_status_to_string(status));
1177
1178 return -EINVAL;
1179 }
1180
1181 break;
1182
1183 case SD_DHCP6_OPTION_IA_NA:
1184 if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
1185 log_dhcp6_client(client, "Information request ignoring IA NA option");
1186
1187 break;
1188 }
1189
1190 r = dhcp6_option_parse_ia(option, &lease->ia, &ia_na_status);
1191 if (r < 0 && r != -ENOMSG)
1192 return r;
1193
1194 if (ia_na_status == DHCP6_STATUS_NO_ADDRS_AVAIL) {
1195 pos += offsetof(DHCP6Option, data) + optlen;
1196 continue;
1197 }
1198
1199 r = dhcp6_lease_get_iaid(lease, &iaid_lease);
1200 if (r < 0)
1201 return r;
1202
1203 if (client->ia_na.ia_na.id != iaid_lease) {
1204 log_dhcp6_client(client, "%s has wrong IAID for IA NA",
1205 dhcp6_message_type_to_string(message->type));
1206 return -EINVAL;
1207 }
1208
1209 if (lease->ia.addresses) {
1210 lt_t1 = MIN(lt_t1, be32toh(lease->ia.ia_na.lifetime_t1));
1211 lt_t2 = MIN(lt_t2, be32toh(lease->ia.ia_na.lifetime_t1));
1212 }
1213
1214 break;
1215
1216 case SD_DHCP6_OPTION_IA_PD:
1217 if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
1218 log_dhcp6_client(client, "Information request ignoring IA PD option");
1219
1220 break;
1221 }
1222
1223 r = dhcp6_option_parse_ia(option, &lease->pd, &ia_pd_status);
1224 if (r < 0 && r != -ENOMSG)
1225 return r;
1226
1227 if (ia_pd_status == DHCP6_STATUS_NO_PREFIX_AVAIL) {
1228 pos += offsetof(DHCP6Option, data) + optlen;
1229 continue;
1230 }
1231
1232 r = dhcp6_lease_get_pd_iaid(lease, &iaid_lease);
1233 if (r < 0)
1234 return r;
1235
1236 if (client->ia_pd.ia_pd.id != iaid_lease) {
1237 log_dhcp6_client(client, "%s has wrong IAID for IA PD",
1238 dhcp6_message_type_to_string(message->type));
1239 return -EINVAL;
1240 }
1241
1242 if (lease->pd.addresses) {
1243 lt_t1 = MIN(lt_t1, be32toh(lease->pd.ia_pd.lifetime_t1));
1244 lt_t2 = MIN(lt_t2, be32toh(lease->pd.ia_pd.lifetime_t2));
1245 }
1246
1247 break;
1248
1249 case SD_DHCP6_OPTION_RAPID_COMMIT:
1250 r = dhcp6_lease_set_rapid_commit(lease);
1251 if (r < 0)
1252 return r;
1253
1254 break;
1255
1256 case SD_DHCP6_OPTION_DNS_SERVERS:
1257 r = dhcp6_lease_set_dns(lease, optval, optlen);
1258 if (r < 0)
1259 return r;
1260
1261 break;
1262
1263 case SD_DHCP6_OPTION_DOMAIN_LIST:
1264 r = dhcp6_lease_set_domains(lease, optval, optlen);
1265 if (r < 0)
1266 return r;
1267
1268 break;
1269
1270 case SD_DHCP6_OPTION_NTP_SERVER:
1271 r = dhcp6_lease_set_ntp(lease, optval, optlen);
1272 if (r < 0)
1273 return r;
1274
1275 break;
1276
1277 case SD_DHCP6_OPTION_SNTP_SERVERS:
1278 r = dhcp6_lease_set_sntp(lease, optval, optlen);
1279 if (r < 0)
1280 return r;
1281
1282 break;
1283
1284 case SD_DHCP6_OPTION_FQDN:
1285 r = dhcp6_lease_set_fqdn(lease, optval, optlen);
1286 if (r < 0)
1287 return r;
1288
1289 break;
1290
1291 case SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME:
1292 if (optlen != 4)
1293 return -EINVAL;
1294
1295 irt = unaligned_read_be32((be32_t *) optval) * USEC_PER_SEC;
1296 break;
1297 }
1298
1299 pos += offsetof(DHCP6Option, data) + optlen;
1300 }
1301
1302 if (ia_na_status > 0 && ia_pd_status > 0) {
1303 log_dhcp6_client(client, "No IA_PD prefix or IA_NA address received. Ignoring.");
1304 return -EINVAL;
1305 }
1306
1307 if (!clientid) {
1308 log_dhcp6_client(client, "%s has incomplete options",
1309 dhcp6_message_type_to_string(message->type));
1310 return -EINVAL;
1311 }
1312
1313 if (client->state != DHCP6_STATE_INFORMATION_REQUEST) {
1314 r = dhcp6_lease_get_serverid(lease, NULL, NULL);
1315 if (r < 0) {
1316 log_dhcp6_client(client, "%s has no server id",
1317 dhcp6_message_type_to_string(message->type));
1318 return -EINVAL;
1319 }
1320
1321 } else {
1322 if (lease->ia.addresses) {
1323 lease->ia.ia_na.lifetime_t1 = htobe32(lt_t1);
1324 lease->ia.ia_na.lifetime_t2 = htobe32(lt_t2);
1325 }
1326
1327 if (lease->pd.addresses) {
1328 lease->pd.ia_pd.lifetime_t1 = htobe32(lt_t1);
1329 lease->pd.ia_pd.lifetime_t2 = htobe32(lt_t2);
1330 }
1331 }
1332
1333 client->information_refresh_time_usec = MAX(irt, IRT_MINIMUM);
1334
1335 return 0;
1336 }
1337
1338 static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len) {
1339 _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
1340 bool rapid_commit;
1341 int r;
1342
1343 assert(client);
1344 assert(reply);
1345
1346 if (reply->type != DHCP6_REPLY)
1347 return 0;
1348
1349 r = dhcp6_lease_new(&lease);
1350 if (r < 0)
1351 return -ENOMEM;
1352
1353 r = client_parse_message(client, reply, len, lease);
1354 if (r < 0)
1355 return r;
1356
1357 if (client->state == DHCP6_STATE_SOLICITATION) {
1358 r = dhcp6_lease_get_rapid_commit(lease, &rapid_commit);
1359 if (r < 0)
1360 return r;
1361
1362 if (!rapid_commit)
1363 return 0;
1364 }
1365
1366 sd_dhcp6_lease_unref(client->lease);
1367 client->lease = TAKE_PTR(lease);
1368
1369 return DHCP6_STATE_BOUND;
1370 }
1371
1372 static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len) {
1373 _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
1374 uint8_t pref_advertise = 0, pref_lease = 0;
1375 int r;
1376
1377 if (advertise->type != DHCP6_ADVERTISE)
1378 return 0;
1379
1380 r = dhcp6_lease_new(&lease);
1381 if (r < 0)
1382 return r;
1383
1384 r = client_parse_message(client, advertise, len, lease);
1385 if (r < 0)
1386 return r;
1387
1388 r = dhcp6_lease_get_preference(lease, &pref_advertise);
1389 if (r < 0)
1390 return r;
1391
1392 r = dhcp6_lease_get_preference(client->lease, &pref_lease);
1393
1394 if (r < 0 || pref_advertise > pref_lease) {
1395 sd_dhcp6_lease_unref(client->lease);
1396 client->lease = TAKE_PTR(lease);
1397 r = 0;
1398 }
1399
1400 if (pref_advertise == 255 || client->retransmit_count > 1)
1401 r = DHCP6_STATE_REQUEST;
1402
1403 return r;
1404 }
1405
1406 static int client_receive_message(
1407 sd_event_source *s,
1408 int fd, uint32_t
1409 revents,
1410 void *userdata) {
1411
1412 sd_dhcp6_client *client = userdata;
1413 DHCP6_CLIENT_DONT_DESTROY(client);
1414 _cleanup_free_ DHCP6Message *message = NULL;
1415 ssize_t buflen, len;
1416 int r = 0;
1417
1418 assert(s);
1419 assert(client);
1420 assert(client->event);
1421
1422 buflen = next_datagram_size_fd(fd);
1423 if (buflen == -ENETDOWN) {
1424 /* the link is down. Don't return an error or the I/O event
1425 source will be disconnected and we won't be able to receive
1426 packets again when the link comes back. */
1427 return 0;
1428 }
1429 if (buflen < 0)
1430 return buflen;
1431
1432 message = malloc(buflen);
1433 if (!message)
1434 return -ENOMEM;
1435
1436 len = recv(fd, message, buflen, 0);
1437 if (len < 0) {
1438 /* see comment above for why we shouldn't error out on ENETDOWN. */
1439 if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
1440 return 0;
1441
1442 return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m");
1443
1444 }
1445 if ((size_t) len < sizeof(DHCP6Message)) {
1446 log_dhcp6_client(client, "Too small to be DHCP6 message: ignoring");
1447 return 0;
1448 }
1449
1450 switch(message->type) {
1451 case DHCP6_SOLICIT:
1452 case DHCP6_REQUEST:
1453 case DHCP6_CONFIRM:
1454 case DHCP6_RENEW:
1455 case DHCP6_REBIND:
1456 case DHCP6_RELEASE:
1457 case DHCP6_DECLINE:
1458 case DHCP6_INFORMATION_REQUEST:
1459 case DHCP6_RELAY_FORW:
1460 case DHCP6_RELAY_REPL:
1461 return 0;
1462
1463 case DHCP6_ADVERTISE:
1464 case DHCP6_REPLY:
1465 case DHCP6_RECONFIGURE:
1466 break;
1467
1468 default:
1469 log_dhcp6_client(client, "Unknown message type %d", message->type);
1470 return 0;
1471 }
1472
1473 if (client->transaction_id != (message->transaction_id &
1474 htobe32(0x00ffffff)))
1475 return 0;
1476
1477 switch (client->state) {
1478 case DHCP6_STATE_INFORMATION_REQUEST:
1479 r = client_receive_reply(client, message, len);
1480 if (r < 0)
1481 return 0;
1482
1483 client_notify(client, SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST);
1484
1485 client_start(client, DHCP6_STATE_STOPPED);
1486
1487 break;
1488
1489 case DHCP6_STATE_SOLICITATION:
1490 r = client_receive_advertise(client, message, len);
1491
1492 if (r == DHCP6_STATE_REQUEST) {
1493 client_start(client, r);
1494
1495 break;
1496 }
1497
1498 _fallthrough_; /* for Solicitation Rapid Commit option check */
1499 case DHCP6_STATE_REQUEST:
1500 case DHCP6_STATE_RENEW:
1501 case DHCP6_STATE_REBIND:
1502
1503 r = client_receive_reply(client, message, len);
1504 if (r < 0)
1505 return 0;
1506
1507 if (r == DHCP6_STATE_BOUND) {
1508
1509 r = client_start(client, DHCP6_STATE_BOUND);
1510 if (r < 0) {
1511 client_stop(client, r);
1512 return 0;
1513 }
1514
1515 client_notify(client, SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE);
1516 }
1517
1518 break;
1519
1520 case DHCP6_STATE_BOUND:
1521
1522 break;
1523
1524 case DHCP6_STATE_STOPPED:
1525 return 0;
1526 }
1527
1528 log_dhcp6_client(client, "Recv %s",
1529 dhcp6_message_type_to_string(message->type));
1530
1531 return 0;
1532 }
1533
1534 static int client_get_lifetime(sd_dhcp6_client *client, uint32_t *lifetime_t1,
1535 uint32_t *lifetime_t2) {
1536 assert_return(client, -EINVAL);
1537 assert_return(client->lease, -EINVAL);
1538
1539 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA) && client->lease->ia.addresses) {
1540 *lifetime_t1 = be32toh(client->lease->ia.ia_na.lifetime_t1);
1541 *lifetime_t2 = be32toh(client->lease->ia.ia_na.lifetime_t2);
1542
1543 return 0;
1544 }
1545
1546 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) {
1547 *lifetime_t1 = be32toh(client->lease->pd.ia_pd.lifetime_t1);
1548 *lifetime_t2 = be32toh(client->lease->pd.ia_pd.lifetime_t2);
1549
1550 return 0;
1551 }
1552
1553 return -ENOMSG;
1554 }
1555
1556 static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
1557 int r;
1558 usec_t timeout, time_now;
1559 char time_string[FORMAT_TIMESPAN_MAX];
1560 uint32_t lifetime_t1, lifetime_t2;
1561
1562 assert_return(client, -EINVAL);
1563 assert_return(client->event, -EINVAL);
1564 assert_return(client->ifindex > 0, -EINVAL);
1565 assert_return(client->state != state, -EINVAL);
1566
1567 (void) event_source_disable(client->timeout_resend_expire);
1568 (void) event_source_disable(client->timeout_resend);
1569 client->retransmit_time = 0;
1570 client->retransmit_count = 0;
1571
1572 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
1573 if (r < 0)
1574 return r;
1575
1576 if (!client->receive_message) {
1577 r = sd_event_add_io(client->event, &client->receive_message,
1578 client->fd, EPOLLIN, client_receive_message,
1579 client);
1580 if (r < 0)
1581 goto error;
1582
1583 r = sd_event_source_set_priority(client->receive_message,
1584 client->event_priority);
1585 if (r < 0)
1586 goto error;
1587
1588 r = sd_event_source_set_description(client->receive_message,
1589 "dhcp6-receive-message");
1590 if (r < 0)
1591 goto error;
1592 }
1593
1594 switch (state) {
1595 case DHCP6_STATE_STOPPED:
1596 if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
1597 client->state = DHCP6_STATE_STOPPED;
1598
1599 return 0;
1600 }
1601
1602 _fallthrough_;
1603 case DHCP6_STATE_SOLICITATION:
1604 client->state = DHCP6_STATE_SOLICITATION;
1605
1606 break;
1607
1608 case DHCP6_STATE_INFORMATION_REQUEST:
1609 case DHCP6_STATE_REQUEST:
1610 case DHCP6_STATE_RENEW:
1611 case DHCP6_STATE_REBIND:
1612
1613 client->state = state;
1614
1615 break;
1616
1617 case DHCP6_STATE_BOUND:
1618
1619 r = client_get_lifetime(client, &lifetime_t1, &lifetime_t2);
1620 if (r < 0)
1621 goto error;
1622
1623 if (lifetime_t1 == 0xffffffff || lifetime_t2 == 0xffffffff) {
1624 log_dhcp6_client(client, "Infinite T1 0x%08x or T2 0x%08x",
1625 lifetime_t1, lifetime_t2);
1626
1627 return 0;
1628 }
1629
1630 timeout = client_timeout_compute_random(lifetime_t1 * USEC_PER_SEC);
1631
1632 log_dhcp6_client(client, "T1 expires in %s",
1633 format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
1634
1635 r = event_reset_time(client->event, &client->timeout_t1,
1636 clock_boottime_or_monotonic(),
1637 time_now + timeout, 10 * USEC_PER_SEC,
1638 client_timeout_t1, client,
1639 client->event_priority, "dhcp6-t1-timeout", true);
1640 if (r < 0)
1641 goto error;
1642
1643 timeout = client_timeout_compute_random(lifetime_t2 * USEC_PER_SEC);
1644
1645 log_dhcp6_client(client, "T2 expires in %s",
1646 format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
1647
1648 r = event_reset_time(client->event, &client->timeout_t2,
1649 clock_boottime_or_monotonic(),
1650 time_now + timeout, 10 * USEC_PER_SEC,
1651 client_timeout_t2, client,
1652 client->event_priority, "dhcp6-t2-timeout", true);
1653 if (r < 0)
1654 goto error;
1655
1656 client->state = state;
1657
1658 return 0;
1659 }
1660
1661 client->transaction_id = random_u32() & htobe32(0x00ffffff);
1662 client->transaction_start = time_now;
1663
1664 r = event_reset_time(client->event, &client->timeout_resend,
1665 clock_boottime_or_monotonic(),
1666 0, 0,
1667 client_timeout_resend, client,
1668 client->event_priority, "dhcp6-resend-timeout", true);
1669 if (r < 0)
1670 goto error;
1671
1672 return 0;
1673
1674 error:
1675 client_reset(client);
1676 return r;
1677 }
1678
1679 int sd_dhcp6_client_stop(sd_dhcp6_client *client) {
1680 assert_return(client, -EINVAL);
1681
1682 client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP);
1683
1684 client->fd = safe_close(client->fd);
1685
1686 return 0;
1687 }
1688
1689 int sd_dhcp6_client_is_running(sd_dhcp6_client *client) {
1690 assert_return(client, -EINVAL);
1691
1692 return client->state != DHCP6_STATE_STOPPED;
1693 }
1694
1695 int sd_dhcp6_client_start(sd_dhcp6_client *client) {
1696 enum DHCP6State state = DHCP6_STATE_SOLICITATION;
1697 int r;
1698
1699 assert_return(client, -EINVAL);
1700 assert_return(client->event, -EINVAL);
1701 assert_return(client->ifindex > 0, -EINVAL);
1702 assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &client->local_address) > 0, -EINVAL);
1703
1704 if (!IN_SET(client->state, DHCP6_STATE_STOPPED))
1705 return -EBUSY;
1706
1707 if (!client->information_request && !client->request)
1708 return -EINVAL;
1709
1710 r = client_reset(client);
1711 if (r < 0)
1712 return r;
1713
1714 r = client_ensure_iaid(client);
1715 if (r < 0)
1716 return r;
1717
1718 r = client_ensure_duid(client);
1719 if (r < 0)
1720 return r;
1721
1722 if (client->fd < 0) {
1723 r = dhcp6_network_bind_udp_socket(client->ifindex, &client->local_address);
1724 if (r < 0) {
1725 _cleanup_free_ char *p = NULL;
1726
1727 (void) in_addr_to_string(AF_INET6, (const union in_addr_union*) &client->local_address, &p);
1728 return log_dhcp6_client_errno(client, r,
1729 "Failed to bind to UDP socket at address %s: %m", strna(p));
1730 }
1731
1732 client->fd = r;
1733 }
1734
1735 if (client->information_request) {
1736 usec_t t = now(CLOCK_MONOTONIC);
1737
1738 if (t < usec_add(client->information_request_time_usec, client->information_refresh_time_usec))
1739 return 0;
1740
1741 client->information_request_time_usec = t;
1742 state = DHCP6_STATE_INFORMATION_REQUEST;
1743 }
1744
1745 log_dhcp6_client(client, "Started in %s mode",
1746 client->information_request? "Information request":
1747 "Managed");
1748
1749 return client_start(client, state);
1750 }
1751
1752 int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int64_t priority) {
1753 int r;
1754
1755 assert_return(client, -EINVAL);
1756 assert_return(!client->event, -EBUSY);
1757
1758 if (event)
1759 client->event = sd_event_ref(event);
1760 else {
1761 r = sd_event_default(&client->event);
1762 if (r < 0)
1763 return 0;
1764 }
1765
1766 client->event_priority = priority;
1767
1768 return 0;
1769 }
1770
1771 int sd_dhcp6_client_detach_event(sd_dhcp6_client *client) {
1772 assert_return(client, -EINVAL);
1773
1774 client->event = sd_event_unref(client->event);
1775
1776 return 0;
1777 }
1778
1779 sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) {
1780 assert_return(client, NULL);
1781
1782 return client->event;
1783 }
1784
1785 static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) {
1786 assert(client);
1787
1788 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
1789 client->timeout_resend_expire = sd_event_source_unref(client->timeout_resend_expire);
1790 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
1791 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
1792
1793 client_reset(client);
1794
1795 client->fd = safe_close(client->fd);
1796
1797 sd_dhcp6_client_detach_event(client);
1798
1799 free(client->req_opts);
1800 free(client->fqdn);
1801 free(client->mudurl);
1802
1803 ordered_hashmap_free(client->extra_options);
1804 strv_free(client->user_class);
1805 strv_free(client->vendor_class);
1806
1807 return mfree(client);
1808 }
1809
1810 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_client, sd_dhcp6_client, dhcp6_client_free);
1811
1812 int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
1813 _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
1814 _cleanup_free_ be16_t *req_opts = NULL;
1815 size_t t;
1816
1817 assert_return(ret, -EINVAL);
1818
1819 req_opts = new(be16_t, ELEMENTSOF(default_req_opts));
1820 if (!req_opts)
1821 return -ENOMEM;
1822
1823 for (t = 0; t < ELEMENTSOF(default_req_opts); t++)
1824 req_opts[t] = htobe16(default_req_opts[t]);
1825
1826 client = new(sd_dhcp6_client, 1);
1827 if (!client)
1828 return -ENOMEM;
1829
1830 *client = (sd_dhcp6_client) {
1831 .n_ref = 1,
1832 .ia_na.type = SD_DHCP6_OPTION_IA_NA,
1833 .ia_pd.type = SD_DHCP6_OPTION_IA_PD,
1834 .ifindex = -1,
1835 .request = DHCP6_REQUEST_IA_NA,
1836 .fd = -1,
1837 .req_opts_len = ELEMENTSOF(default_req_opts),
1838 .hint_pd_prefix.iapdprefix.lifetime_preferred = (be32_t) -1,
1839 .hint_pd_prefix.iapdprefix.lifetime_valid = (be32_t) -1,
1840 .req_opts = TAKE_PTR(req_opts),
1841 };
1842
1843 *ret = TAKE_PTR(client);
1844
1845 return 0;
1846 }