Import dhcpcd-10.0.2 with the following changes:
[dragonfly.git] / contrib / dhcpcd / src / dhcp6.c
blobe7767ca744c9304e9519ffddc0dd116abf82b274
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3 * dhcpcd - DHCP client daemon
4 * Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
5 * All rights reserved
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
29 #include <sys/utsname.h>
30 #include <sys/types.h>
32 #include <netinet/in.h>
33 #include <netinet/ip6.h>
35 #include <assert.h>
36 #include <ctype.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <inttypes.h>
40 #include <stdbool.h>
41 #include <stddef.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <fcntl.h>
46 #include <syslog.h>
48 #define ELOOP_QUEUE ELOOP_DHCP6
49 #include "config.h"
50 #include "common.h"
51 #include "dhcp.h"
52 #include "dhcp6.h"
53 #include "duid.h"
54 #include "eloop.h"
55 #include "if.h"
56 #include "if-options.h"
57 #include "ipv6nd.h"
58 #include "logerr.h"
59 #include "privsep.h"
60 #include "script.h"
62 #ifdef HAVE_SYS_BITOPS_H
63 #include <sys/bitops.h>
64 #else
65 #include "compat/bitops.h"
66 #endif
68 /* DHCPCD Project has been assigned an IANA PEN of 40712 */
69 #define DHCPCD_IANA_PEN 40712
71 /* Unsure if I want this */
72 //#define VENDOR_SPLIT
74 /* Support older systems with different defines */
75 #if !defined(IPV6_RECVPKTINFO) && defined(IPV6_PKTINFO)
76 #define IPV6_RECVPKTINFO IPV6_PKTINFO
77 #endif
79 #ifdef DHCP6
81 /* Assert the correct structure size for on wire */
82 struct dhcp6_message {
83 uint8_t type;
84 uint8_t xid[3];
85 /* followed by options */
87 __CTASSERT(sizeof(struct dhcp6_message) == 4);
89 struct dhcp6_option {
90 uint16_t code;
91 uint16_t len;
92 /* followed by data */
94 __CTASSERT(sizeof(struct dhcp6_option) == 4);
96 struct dhcp6_ia_na {
97 uint8_t iaid[4];
98 uint32_t t1;
99 uint32_t t2;
101 __CTASSERT(sizeof(struct dhcp6_ia_na) == 12);
103 struct dhcp6_ia_ta {
104 uint8_t iaid[4];
106 __CTASSERT(sizeof(struct dhcp6_ia_ta) == 4);
108 struct dhcp6_ia_addr {
109 struct in6_addr addr;
110 uint32_t pltime;
111 uint32_t vltime;
113 __CTASSERT(sizeof(struct dhcp6_ia_addr) == 16 + 8);
115 /* XXX FIXME: This is the only packed structure and it does not align.
116 * Maybe manually decode it? */
117 struct dhcp6_pd_addr {
118 uint32_t pltime;
119 uint32_t vltime;
120 uint8_t prefix_len;
121 struct in6_addr prefix;
122 } __packed;
123 __CTASSERT(sizeof(struct dhcp6_pd_addr) == 8 + 1 + 16);
125 struct dhcp6_op {
126 uint16_t type;
127 const char *name;
130 static const struct dhcp6_op dhcp6_ops[] = {
131 { DHCP6_SOLICIT, "SOLICIT6" },
132 { DHCP6_ADVERTISE, "ADVERTISE6" },
133 { DHCP6_REQUEST, "REQUEST6" },
134 { DHCP6_REPLY, "REPLY6" },
135 { DHCP6_RENEW, "RENEW6" },
136 { DHCP6_REBIND, "REBIND6" },
137 { DHCP6_CONFIRM, "CONFIRM6" },
138 { DHCP6_INFORMATION_REQ, "INFORM6" },
139 { DHCP6_RELEASE, "RELEASE6" },
140 { DHCP6_RECONFIGURE, "RECONFIGURE6" },
141 { DHCP6_DECLINE, "DECLINE6" },
142 { 0, NULL }
145 struct dhcp_compat {
146 uint8_t dhcp_opt;
147 uint16_t dhcp6_opt;
151 * RFC 5908 deprecates OPTION_SNTP_SERVERS.
152 * But we can support both as the hook scripts will uniqify the
153 * results if the server returns both options.
155 static const struct dhcp_compat dhcp_compats[] = {
156 { DHO_DNSSERVER, D6_OPTION_DNS_SERVERS },
157 { DHO_HOSTNAME, D6_OPTION_FQDN },
158 { DHO_DNSDOMAIN, D6_OPTION_FQDN },
159 { DHO_NISSERVER, D6_OPTION_NIS_SERVERS },
160 { DHO_NTPSERVER, D6_OPTION_SNTP_SERVERS },
161 { DHO_NTPSERVER, D6_OPTION_NTP_SERVER },
162 { DHO_RAPIDCOMMIT, D6_OPTION_RAPID_COMMIT },
163 { DHO_FQDN, D6_OPTION_FQDN },
164 { DHO_VIVCO, D6_OPTION_VENDOR_CLASS },
165 { DHO_VIVSO, D6_OPTION_VENDOR_OPTS },
166 { DHO_DNSSEARCH, D6_OPTION_DOMAIN_LIST },
167 { 0, 0 }
170 static const char * const dhcp6_statuses[] = {
171 "Success",
172 "Unspecified Failure",
173 "No Addresses Available",
174 "No Binding",
175 "Not On Link",
176 "Use Multicast",
177 "No Prefix Available"
180 static void dhcp6_bind(struct interface *, const char *, const char *);
181 static void dhcp6_failinform(void *);
182 static void dhcp6_recvaddr(void *, unsigned short);
183 static void dhcp6_startdecline(struct interface *);
185 #ifdef SMALL
186 #define dhcp6_hasprefixdelegation(a) (0)
187 #else
188 static int dhcp6_hasprefixdelegation(struct interface *);
189 #endif
191 #define DECLINE_IA(ia) \
192 ((ia)->addr_flags & IN6_IFF_DUPLICATED && \
193 (ia)->ia_type != 0 && (ia)->ia_type != D6_OPTION_IA_PD && \
194 !((ia)->flags & IPV6_AF_STALE) && \
195 (ia)->prefix_vltime != 0)
197 void
198 dhcp6_printoptions(const struct dhcpcd_ctx *ctx,
199 const struct dhcp_opt *opts, size_t opts_len)
201 size_t i, j;
202 const struct dhcp_opt *opt, *opt2;
203 int cols;
205 for (i = 0, opt = ctx->dhcp6_opts;
206 i < ctx->dhcp6_opts_len; i++, opt++)
208 for (j = 0, opt2 = opts; j < opts_len; j++, opt2++)
209 if (opt2->option == opt->option)
210 break;
211 if (j == opts_len) {
212 cols = printf("%05d %s", opt->option, opt->var);
213 dhcp_print_option_encoding(opt, cols);
216 for (i = 0, opt = opts; i < opts_len; i++, opt++) {
217 cols = printf("%05d %s", opt->option, opt->var);
218 dhcp_print_option_encoding(opt, cols);
222 static size_t
223 dhcp6_makeuser(void *data, const struct interface *ifp)
225 const struct if_options *ifo = ifp->options;
226 struct dhcp6_option o;
227 uint8_t *p;
228 const uint8_t *up, *ue;
229 uint16_t ulen, unlen;
230 size_t olen;
232 /* Convert the DHCPv4 user class option to DHCPv6 */
233 up = ifo->userclass;
234 ulen = *up++;
235 if (ulen == 0)
236 return 0;
238 p = data;
239 olen = 0;
240 if (p != NULL)
241 p += sizeof(o);
243 ue = up + ulen;
244 for (; up < ue; up += ulen) {
245 ulen = *up++;
246 olen += sizeof(ulen) + ulen;
247 if (data == NULL)
248 continue;
249 unlen = htons(ulen);
250 memcpy(p, &unlen, sizeof(unlen));
251 p += sizeof(unlen);
252 memcpy(p, up, ulen);
253 p += ulen;
255 if (data != NULL) {
256 o.code = htons(D6_OPTION_USER_CLASS);
257 o.len = htons((uint16_t)olen);
258 memcpy(data, &o, sizeof(o));
261 return sizeof(o) + olen;
264 static size_t
265 dhcp6_makevendor(void *data, const struct interface *ifp)
267 const struct if_options *ifo;
268 size_t len, vlen, i;
269 uint8_t *p;
270 const struct vivco *vivco;
271 struct dhcp6_option o;
273 ifo = ifp->options;
274 len = sizeof(uint32_t); /* IANA PEN */
275 if (ifo->vivco_en) {
276 vlen = 0;
277 for (i = 0, vivco = ifo->vivco;
278 i < ifo->vivco_len;
279 i++, vivco++)
280 vlen += sizeof(uint16_t) + vivco->len;
281 len += vlen;
282 } else if (ifo->vendorclassid[0] != '\0') {
283 /* dhcpcd owns DHCPCD_IANA_PEN.
284 * If you need your own string, get your own IANA PEN. */
285 vlen = strlen(ifp->ctx->vendor);
286 len += sizeof(uint16_t) + vlen;
287 } else
288 return 0;
290 if (len > UINT16_MAX) {
291 logerrx("%s: DHCPv6 Vendor Class too big", ifp->name);
292 return 0;
295 if (data != NULL) {
296 uint32_t pen;
297 uint16_t hvlen;
299 p = data;
300 o.code = htons(D6_OPTION_VENDOR_CLASS);
301 o.len = htons((uint16_t)len);
302 memcpy(p, &o, sizeof(o));
303 p += sizeof(o);
304 pen = htonl(ifo->vivco_en ? ifo->vivco_en : DHCPCD_IANA_PEN);
305 memcpy(p, &pen, sizeof(pen));
306 p += sizeof(pen);
308 if (ifo->vivco_en) {
309 for (i = 0, vivco = ifo->vivco;
310 i < ifo->vivco_len;
311 i++, vivco++)
313 hvlen = htons((uint16_t)vivco->len);
314 memcpy(p, &hvlen, sizeof(hvlen));
315 p += sizeof(hvlen);
316 memcpy(p, vivco->data, vivco->len);
317 p += vivco->len;
319 } else if (ifo->vendorclassid[0] != '\0') {
320 hvlen = htons((uint16_t)vlen);
321 memcpy(p, &hvlen, sizeof(hvlen));
322 p += sizeof(hvlen);
323 memcpy(p, ifp->ctx->vendor, vlen);
327 return sizeof(o) + len;
330 static void *
331 dhcp6_findoption(void *data, size_t data_len, uint16_t code, uint16_t *len)
333 uint8_t *d;
334 struct dhcp6_option o;
336 code = htons(code);
337 for (d = data; data_len != 0; d += o.len, data_len -= o.len) {
338 if (data_len < sizeof(o)) {
339 errno = EINVAL;
340 return NULL;
342 memcpy(&o, d, sizeof(o));
343 d += sizeof(o);
344 data_len -= sizeof(o);
345 o.len = htons(o.len);
346 if (data_len < o.len) {
347 errno = EINVAL;
348 return NULL;
350 if (o.code == code) {
351 if (len != NULL)
352 *len = o.len;
353 return d;
357 errno = ENOENT;
358 return NULL;
361 static void *
362 dhcp6_findmoption(void *data, size_t data_len, uint16_t code,
363 uint16_t *len)
365 uint8_t *d;
367 if (data_len < sizeof(struct dhcp6_message)) {
368 errno = EINVAL;
369 return false;
371 d = data;
372 d += sizeof(struct dhcp6_message);
373 data_len -= sizeof(struct dhcp6_message);
374 return dhcp6_findoption(d, data_len, code, len);
377 static const uint8_t *
378 dhcp6_getoption(struct dhcpcd_ctx *ctx,
379 size_t *os, unsigned int *code, size_t *len,
380 const uint8_t *od, size_t ol, struct dhcp_opt **oopt)
382 struct dhcp6_option o;
383 size_t i;
384 struct dhcp_opt *opt;
386 if (od != NULL) {
387 *os = sizeof(o);
388 if (ol < *os) {
389 errno = EINVAL;
390 return NULL;
392 memcpy(&o, od, sizeof(o));
393 *len = ntohs(o.len);
394 if (*len > ol - *os) {
395 errno = ERANGE;
396 return NULL;
398 *code = ntohs(o.code);
401 *oopt = NULL;
402 for (i = 0, opt = ctx->dhcp6_opts;
403 i < ctx->dhcp6_opts_len; i++, opt++)
405 if (opt->option == *code) {
406 *oopt = opt;
407 break;
411 if (od != NULL)
412 return od + sizeof(o);
413 return NULL;
416 static bool
417 dhcp6_updateelapsed(struct interface *ifp, struct dhcp6_message *m, size_t len)
419 uint8_t *opt;
420 uint16_t opt_len;
421 struct dhcp6_state *state;
422 struct timespec tv;
423 unsigned long long hsec;
424 uint16_t sec;
426 opt = dhcp6_findmoption(m, len, D6_OPTION_ELAPSED, &opt_len);
427 if (opt == NULL)
428 return false;
429 if (opt_len != sizeof(sec)) {
430 errno = EINVAL;
431 return false;
434 state = D6_STATE(ifp);
435 clock_gettime(CLOCK_MONOTONIC, &tv);
436 if (state->RTC == 0) {
437 /* An RTC of zero means we're the first message
438 * out of the door, so the elapsed time is zero. */
439 state->started = tv;
440 hsec = 0;
441 } else {
442 unsigned long long secs;
443 unsigned int nsecs;
445 secs = eloop_timespec_diff(&tv, &state->started, &nsecs);
446 /* Elapsed time is measured in centiseconds.
447 * We need to be sure it will not potentially overflow. */
448 if (secs >= (UINT16_MAX / CSEC_PER_SEC) + 1)
449 hsec = UINT16_MAX;
450 else {
451 hsec = (secs * CSEC_PER_SEC) +
452 (nsecs / NSEC_PER_CSEC);
453 if (hsec > UINT16_MAX)
454 hsec = UINT16_MAX;
457 sec = htons((uint16_t)hsec);
458 memcpy(opt, &sec, sizeof(sec));
459 return true;
462 static void
463 dhcp6_newxid(const struct interface *ifp, struct dhcp6_message *m)
465 const struct interface *ifp1;
466 const struct dhcp6_state *state1;
467 uint32_t xid;
469 if (ifp->options->options & DHCPCD_XID_HWADDR &&
470 ifp->hwlen >= sizeof(xid))
471 /* The lower bits are probably more unique on the network */
472 memcpy(&xid, (ifp->hwaddr + ifp->hwlen) - sizeof(xid),
473 sizeof(xid));
474 else {
475 again:
476 xid = arc4random();
479 m->xid[0] = (xid >> 16) & 0xff;
480 m->xid[1] = (xid >> 8) & 0xff;
481 m->xid[2] = xid & 0xff;
483 /* Ensure it's unique */
484 TAILQ_FOREACH(ifp1, ifp->ctx->ifaces, next) {
485 if (ifp == ifp1)
486 continue;
487 if ((state1 = D6_CSTATE(ifp1)) == NULL)
488 continue;
489 if (state1->send != NULL &&
490 state1->send->xid[0] == m->xid[0] &&
491 state1->send->xid[1] == m->xid[1] &&
492 state1->send->xid[2] == m->xid[2])
493 break;
496 if (ifp1 != NULL) {
497 if (ifp->options->options & DHCPCD_XID_HWADDR &&
498 ifp->hwlen >= sizeof(xid))
500 logerrx("%s: duplicate xid on %s",
501 ifp->name, ifp1->name);
502 return;
504 goto again;
508 #ifndef SMALL
509 static const struct if_sla *
510 dhcp6_findselfsla(struct interface *ifp)
512 size_t i, j;
513 struct if_ia *ia;
515 for (i = 0; i < ifp->options->ia_len; i++) {
516 ia = &ifp->options->ia[i];
517 if (ia->ia_type != D6_OPTION_IA_PD)
518 continue;
519 for (j = 0; j < ia->sla_len; j++) {
520 if (strcmp(ia->sla[j].ifname, ifp->name) == 0)
521 return &ia->sla[j];
524 return NULL;
527 static int
528 dhcp6_delegateaddr(struct in6_addr *addr, struct interface *ifp,
529 const struct ipv6_addr *prefix, const struct if_sla *sla, struct if_ia *ia)
531 struct dhcp6_state *state;
532 struct if_sla asla;
533 char sabuf[INET6_ADDRSTRLEN];
534 const char *sa;
536 state = D6_STATE(ifp);
537 if (state == NULL) {
538 ifp->if_data[IF_DATA_DHCP6] = calloc(1, sizeof(*state));
539 state = D6_STATE(ifp);
540 if (state == NULL) {
541 logerr(__func__);
542 return -1;
545 TAILQ_INIT(&state->addrs);
546 state->state = DH6S_DELEGATED;
547 state->reason = "DELEGATED6";
550 if (sla == NULL || !sla->sla_set) {
551 /* No SLA set, so make an assumption of
552 * desired SLA and prefix length. */
553 asla.sla = ifp->index;
554 asla.prefix_len = 0;
555 asla.sla_set = false;
556 sla = &asla;
557 } else if (sla->prefix_len == 0) {
558 /* An SLA was given, but prefix length was not.
559 * We need to work out a suitable prefix length for
560 * potentially more than one interface. */
561 asla.sla = sla->sla;
562 asla.prefix_len = 0;
563 asla.sla_set = sla->sla_set;
564 sla = &asla;
567 if (sla->prefix_len == 0) {
568 uint32_t sla_max;
569 int bits;
571 sla_max = ia->sla_max;
572 if (sla_max == 0 && (sla == NULL || !sla->sla_set)) {
573 const struct interface *ifi;
575 TAILQ_FOREACH(ifi, ifp->ctx->ifaces, next) {
576 if (ifi->index > sla_max)
577 sla_max = ifi->index;
581 bits = fls32(sla_max);
583 if (prefix->prefix_len + bits > (int)UINT8_MAX)
584 asla.prefix_len = UINT8_MAX;
585 else {
586 asla.prefix_len = (uint8_t)(prefix->prefix_len + bits);
588 /* Make a 64 prefix by default, as this makes SLAAC
589 * possible.
590 * Otherwise round up to the nearest 4 bits. */
591 if (asla.prefix_len <= 64)
592 asla.prefix_len = 64;
593 else
594 asla.prefix_len =
595 (uint8_t)ROUNDUP4(asla.prefix_len);
598 #define BIT(n) (1UL << (n))
599 #define BIT_MASK(len) (BIT(len) - 1)
600 if (ia->sla_max == 0) {
601 /* Work out the real sla_max from our bits used */
602 bits = asla.prefix_len - prefix->prefix_len;
603 /* Make static analysis happy.
604 * Bits cannot be bigger than 32 thanks to fls32. */
605 assert(bits <= 32);
606 ia->sla_max = (uint32_t)BIT_MASK(bits);
610 if (ipv6_userprefix(&prefix->prefix, prefix->prefix_len,
611 sla->sla, addr, sla->prefix_len) == -1)
613 sa = inet_ntop(AF_INET6, &prefix->prefix,
614 sabuf, sizeof(sabuf));
615 logerr("%s: invalid prefix %s/%d + %d/%d",
616 ifp->name, sa, prefix->prefix_len,
617 sla->sla, sla->prefix_len);
618 return -1;
621 if (prefix->prefix_exclude_len &&
622 IN6_ARE_ADDR_EQUAL(addr, &prefix->prefix_exclude))
624 sa = inet_ntop(AF_INET6, &prefix->prefix_exclude,
625 sabuf, sizeof(sabuf));
626 logerrx("%s: cannot delegate excluded prefix %s/%d",
627 ifp->name, sa, prefix->prefix_exclude_len);
628 return -1;
631 return sla->prefix_len;
633 #endif
635 static int
636 dhcp6_makemessage(struct interface *ifp)
638 struct dhcp6_state *state;
639 struct dhcp6_message *m;
640 struct dhcp6_option o;
641 uint8_t *p, *si, *unicast, IA;
642 size_t n, l, len, ml, hl;
643 uint8_t type;
644 uint16_t si_len, uni_len, n_options;
645 uint8_t *o_lenp;
646 struct if_options *ifo = ifp->options;
647 const struct dhcp_opt *opt, *opt2;
648 const struct ipv6_addr *ap;
649 char hbuf[HOSTNAME_MAX_LEN + 1];
650 const char *hostname;
651 int fqdn;
652 struct dhcp6_ia_na ia_na;
653 uint16_t ia_na_len;
654 struct if_ia *ifia;
655 #ifdef AUTH
656 uint16_t auth_len;
657 #endif
658 uint8_t duid[DUID_LEN];
659 size_t duid_len = 0;
661 state = D6_STATE(ifp);
662 if (state->send) {
663 free(state->send);
664 state->send = NULL;
667 switch(state->state) {
668 case DH6S_INIT: /* FALLTHROUGH */
669 case DH6S_DISCOVER:
670 type = DHCP6_SOLICIT;
671 break;
672 case DH6S_REQUEST:
673 type = DHCP6_REQUEST;
674 break;
675 case DH6S_CONFIRM:
676 type = DHCP6_CONFIRM;
677 break;
678 case DH6S_REBIND:
679 type = DHCP6_REBIND;
680 break;
681 case DH6S_RENEW:
682 type = DHCP6_RENEW;
683 break;
684 case DH6S_INFORM:
685 type = DHCP6_INFORMATION_REQ;
686 break;
687 case DH6S_RELEASE:
688 type = DHCP6_RELEASE;
689 break;
690 case DH6S_DECLINE:
691 type = DHCP6_DECLINE;
692 break;
693 default:
694 errno = EINVAL;
695 return -1;
698 /* RFC 4704 Section 5 says we can only send FQDN for these
699 * message types. */
700 switch(type) {
701 case DHCP6_SOLICIT:
702 case DHCP6_REQUEST:
703 case DHCP6_RENEW:
704 case DHCP6_REBIND:
705 fqdn = ifo->fqdn;
706 break;
707 default:
708 fqdn = FQDN_DISABLE;
709 break;
712 if (fqdn == FQDN_DISABLE && ifo->options & DHCPCD_HOSTNAME) {
713 /* We're sending the DHCPv4 hostname option, so send FQDN as
714 * DHCPv6 has no FQDN option and DHCPv4 must not send
715 * hostname and FQDN according to RFC4702 */
716 fqdn = FQDN_BOTH;
718 if (fqdn != FQDN_DISABLE)
719 hostname = dhcp_get_hostname(hbuf, sizeof(hbuf), ifo);
720 else
721 hostname = NULL; /* appearse gcc */
723 /* Work out option size first */
724 n_options = 0;
725 len = 0;
726 si = NULL;
727 hl = 0; /* Appease gcc */
728 if (state->state != DH6S_RELEASE && state->state != DH6S_DECLINE) {
729 for (l = 0, opt = ifp->ctx->dhcp6_opts;
730 l < ifp->ctx->dhcp6_opts_len;
731 l++, opt++)
733 for (n = 0, opt2 = ifo->dhcp6_override;
734 n < ifo->dhcp6_override_len;
735 n++, opt2++)
737 if (opt->option == opt2->option)
738 break;
740 if (n < ifo->dhcp6_override_len)
741 continue;
742 if (!DHC_REQOPT(opt, ifo->requestmask6, ifo->nomask6))
743 continue;
744 n_options++;
745 len += sizeof(o.len);
747 #ifndef SMALL
748 for (l = 0, opt = ifo->dhcp6_override;
749 l < ifo->dhcp6_override_len;
750 l++, opt++)
752 if (!DHC_REQOPT(opt, ifo->requestmask6, ifo->nomask6))
753 continue;
754 n_options++;
755 len += sizeof(o.len);
757 if (dhcp6_findselfsla(ifp)) {
758 n_options++;
759 len += sizeof(o.len);
761 #endif
762 if (len)
763 len += sizeof(o);
765 if (fqdn != FQDN_DISABLE) {
766 hl = encode_rfc1035(hostname, NULL);
767 len += sizeof(o) + 1 + hl;
770 if (!has_option_mask(ifo->nomask6, D6_OPTION_MUDURL) &&
771 ifo->mudurl[0])
772 len += sizeof(o) + ifo->mudurl[0];
774 #ifdef AUTH
775 if ((ifo->auth.options & DHCPCD_AUTH_SENDREQUIRE) !=
776 DHCPCD_AUTH_SENDREQUIRE &&
777 DHC_REQ(ifo->requestmask6, ifo->nomask6,
778 D6_OPTION_RECONF_ACCEPT))
779 len += sizeof(o); /* Reconfigure Accept */
780 #endif
783 len += sizeof(*state->send);
784 len += sizeof(o) + sizeof(uint16_t); /* elapsed */
786 if (ifo->options & DHCPCD_ANONYMOUS) {
787 duid_len = duid_make(duid, ifp, DUID_LL);
788 len += sizeof(o) + duid_len;
789 } else {
790 len += sizeof(o) + ifp->ctx->duid_len;
793 if (!has_option_mask(ifo->nomask6, D6_OPTION_USER_CLASS))
794 len += dhcp6_makeuser(NULL, ifp);
795 if (!has_option_mask(ifo->nomask6, D6_OPTION_VENDOR_CLASS))
796 len += dhcp6_makevendor(NULL, ifp);
798 /* IA */
799 m = NULL;
800 ml = 0;
801 switch(state->state) {
802 case DH6S_REQUEST:
803 m = state->recv;
804 ml = state->recv_len;
805 /* FALLTHROUGH */
806 case DH6S_DECLINE:
807 /* FALLTHROUGH */
808 case DH6S_RELEASE:
809 /* FALLTHROUGH */
810 case DH6S_RENEW:
811 if (m == NULL) {
812 m = state->new;
813 ml = state->new_len;
815 si = dhcp6_findmoption(m, ml, D6_OPTION_SERVERID, &si_len);
816 if (si == NULL)
817 return -1;
818 len += sizeof(o) + si_len;
819 /* FALLTHROUGH */
820 case DH6S_REBIND:
821 /* FALLTHROUGH */
822 case DH6S_CONFIRM:
823 /* FALLTHROUGH */
824 case DH6S_DISCOVER:
825 if (m == NULL) {
826 m = state->new;
827 ml = state->new_len;
829 TAILQ_FOREACH(ap, &state->addrs, next) {
830 if (ap->flags & IPV6_AF_STALE)
831 continue;
832 if (!(ap->flags & IPV6_AF_REQUEST) &&
833 (ap->prefix_vltime == 0 ||
834 state->state == DH6S_DISCOVER))
835 continue;
836 if (DECLINE_IA(ap) && state->state != DH6S_DECLINE)
837 continue;
838 if (ap->ia_type == D6_OPTION_IA_PD) {
839 #ifndef SMALL
840 len += sizeof(o) + sizeof(struct dhcp6_pd_addr);
841 if (ap->prefix_exclude_len)
842 len += sizeof(o) + 1 +
843 (uint8_t)((ap->prefix_exclude_len -
844 ap->prefix_len - 1) / NBBY) + 1;
845 #endif
846 } else
847 len += sizeof(o) + sizeof(struct dhcp6_ia_addr);
849 /* FALLTHROUGH */
850 case DH6S_INIT:
851 for (l = 0; l < ifo->ia_len; l++) {
852 len += sizeof(o) + sizeof(uint32_t); /* IAID */
853 /* IA_TA does not have T1 or T2 timers */
854 if (ifo->ia[l].ia_type != D6_OPTION_IA_TA)
855 len += sizeof(uint32_t) + sizeof(uint32_t);
857 IA = 1;
858 break;
859 default:
860 IA = 0;
863 if (state->state == DH6S_DISCOVER &&
864 !(ifp->ctx->options & DHCPCD_TEST) &&
865 DHC_REQ(ifo->requestmask6, ifo->nomask6, D6_OPTION_RAPID_COMMIT))
866 len += sizeof(o);
868 if (m == NULL) {
869 m = state->new;
870 ml = state->new_len;
873 switch(state->state) {
874 case DH6S_REQUEST: /* FALLTHROUGH */
875 case DH6S_RENEW: /* FALLTHROUGH */
876 case DH6S_RELEASE:
877 if (has_option_mask(ifo->nomask6, D6_OPTION_UNICAST)) {
878 unicast = NULL;
879 break;
881 unicast = dhcp6_findmoption(m, ml, D6_OPTION_UNICAST, &uni_len);
882 break;
883 default:
884 unicast = NULL;
885 break;
888 /* In non manager mode we listen and send from fixed addresses.
889 * We should try and match an address we have to unicast to,
890 * but for now this is the safest policy. */
891 if (unicast != NULL && !(ifp->ctx->options & DHCPCD_MANAGER)) {
892 logdebugx("%s: ignoring unicast option as not manager",
893 ifp->name);
894 unicast = NULL;
897 #ifdef AUTH
898 auth_len = 0;
899 if (ifo->auth.options & DHCPCD_AUTH_SEND) {
900 ssize_t alen = dhcp_auth_encode(ifp->ctx, &ifo->auth,
901 state->auth.token, NULL, 0, 6, type, NULL, 0);
902 if (alen != -1 && alen > UINT16_MAX) {
903 errno = ERANGE;
904 alen = -1;
906 if (alen == -1)
907 logerr("%s: %s: dhcp_auth_encode", __func__, ifp->name);
908 else if (alen != 0) {
909 auth_len = (uint16_t)alen;
910 len += sizeof(o) + auth_len;
913 #endif
915 state->send = malloc(len);
916 if (state->send == NULL)
917 return -1;
919 state->send_len = len;
920 state->send->type = type;
922 /* If we found a unicast option, copy it to our state for sending */
923 if (unicast && uni_len == sizeof(state->unicast))
924 memcpy(&state->unicast, unicast, sizeof(state->unicast));
925 else
926 state->unicast = in6addr_any;
928 dhcp6_newxid(ifp, state->send);
930 #define COPYIN1(_code, _len) { \
931 o.code = htons((_code)); \
932 o.len = htons((_len)); \
933 memcpy(p, &o, sizeof(o)); \
934 p += sizeof(o); \
936 #define COPYIN(_code, _data, _len) do { \
937 COPYIN1((_code), (_len)); \
938 if ((_len) != 0) { \
939 memcpy(p, (_data), (_len)); \
940 p += (_len); \
942 } while (0 /* CONSTCOND */)
943 #define NEXTLEN (p + offsetof(struct dhcp6_option, len))
945 /* Options are listed in numerical order as per RFC 7844 Section 4.1
946 * XXX: They should be randomised. */
948 p = (uint8_t *)state->send + sizeof(*state->send);
949 if (ifo->options & DHCPCD_ANONYMOUS)
950 COPYIN(D6_OPTION_CLIENTID, duid,
951 (uint16_t)duid_len);
952 else
953 COPYIN(D6_OPTION_CLIENTID, ifp->ctx->duid,
954 (uint16_t)ifp->ctx->duid_len);
956 if (si != NULL)
957 COPYIN(D6_OPTION_SERVERID, si, si_len);
959 for (l = 0; IA && l < ifo->ia_len; l++) {
960 ifia = &ifo->ia[l];
961 o_lenp = NEXTLEN;
962 /* TA structure is the same as the others,
963 * it just lacks the T1 and T2 timers.
964 * These happen to be at the end of the struct,
965 * so we just don't copy them in. */
966 if (ifia->ia_type == D6_OPTION_IA_TA)
967 ia_na_len = sizeof(struct dhcp6_ia_ta);
968 else
969 ia_na_len = sizeof(ia_na);
970 memcpy(ia_na.iaid, ifia->iaid, sizeof(ia_na.iaid));
971 /* RFC 8415 21.4 and 21.21 state that T1 and T2 should be zero.
972 * An RFC compliant server MUST ignore them anyway. */
973 ia_na.t1 = 0;
974 ia_na.t2 = 0;
975 COPYIN(ifia->ia_type, &ia_na, ia_na_len);
976 TAILQ_FOREACH(ap, &state->addrs, next) {
977 if (ap->flags & IPV6_AF_STALE)
978 continue;
979 if (!(ap->flags & IPV6_AF_REQUEST) &&
980 (ap->prefix_vltime == 0 ||
981 state->state == DH6S_DISCOVER))
982 continue;
983 if (DECLINE_IA(ap) && state->state != DH6S_DECLINE)
984 continue;
985 if (ap->ia_type != ifia->ia_type)
986 continue;
987 if (memcmp(ap->iaid, ifia->iaid, sizeof(ap->iaid)))
988 continue;
989 if (ap->ia_type == D6_OPTION_IA_PD) {
990 #ifndef SMALL
991 struct dhcp6_pd_addr pdp = {
992 .prefix_len = ap->prefix_len,
994 * RFC 8415 21.22 states that the
995 * valid and preferred lifetimes sent by
996 * the client SHOULD be zero and MUST
997 * be ignored by the server.
1001 /* pdp.prefix is not aligned, so copy it in. */
1002 memcpy(&pdp.prefix, &ap->prefix, sizeof(pdp.prefix));
1003 COPYIN(D6_OPTION_IAPREFIX, &pdp, sizeof(pdp));
1004 ia_na_len = (uint16_t)
1005 (ia_na_len + sizeof(o) + sizeof(pdp));
1007 /* RFC6603 Section 4.2 */
1008 if (ap->prefix_exclude_len) {
1009 uint8_t exb[16], *ep, u8;
1010 const uint8_t *pp;
1012 n = (size_t)((ap->prefix_exclude_len -
1013 ap->prefix_len - 1) / NBBY) + 1;
1014 ep = exb;
1015 *ep++ = (uint8_t)ap->prefix_exclude_len;
1016 pp = ap->prefix_exclude.s6_addr;
1017 pp += (size_t)
1018 ((ap->prefix_len - 1) / NBBY) +
1019 (n - 1);
1020 u8 = ap->prefix_len % NBBY;
1021 if (u8)
1022 n--;
1023 while (n-- > 0)
1024 *ep++ = *pp--;
1025 if (u8)
1026 *ep = (uint8_t)(*pp << u8);
1027 n++;
1028 COPYIN(D6_OPTION_PD_EXCLUDE, exb,
1029 (uint16_t)n);
1030 ia_na_len = (uint16_t)
1031 (ia_na_len + sizeof(o) + n);
1033 #endif
1034 } else {
1035 struct dhcp6_ia_addr ia = {
1036 .addr = ap->addr,
1038 * RFC 8415 21.6 states that the
1039 * valid and preferred lifetimes sent by
1040 * the client SHOULD be zero and MUST
1041 * be ignored by the server.
1045 COPYIN(D6_OPTION_IA_ADDR, &ia, sizeof(ia));
1046 ia_na_len = (uint16_t)
1047 (ia_na_len + sizeof(o) + sizeof(ia));
1051 /* Update the total option lenth. */
1052 ia_na_len = htons(ia_na_len);
1053 memcpy(o_lenp, &ia_na_len, sizeof(ia_na_len));
1056 if (state->send->type != DHCP6_RELEASE &&
1057 state->send->type != DHCP6_DECLINE &&
1058 n_options)
1060 o_lenp = NEXTLEN;
1061 o.len = 0;
1062 COPYIN1(D6_OPTION_ORO, 0);
1063 for (l = 0, opt = ifp->ctx->dhcp6_opts;
1064 l < ifp->ctx->dhcp6_opts_len;
1065 l++, opt++)
1067 #ifndef SMALL
1068 for (n = 0, opt2 = ifo->dhcp6_override;
1069 n < ifo->dhcp6_override_len;
1070 n++, opt2++)
1072 if (opt->option == opt2->option)
1073 break;
1075 if (n < ifo->dhcp6_override_len)
1076 continue;
1077 #endif
1078 if (!DHC_REQOPT(opt, ifo->requestmask6, ifo->nomask6))
1079 continue;
1080 o.code = htons((uint16_t)opt->option);
1081 memcpy(p, &o.code, sizeof(o.code));
1082 p += sizeof(o.code);
1083 o.len = (uint16_t)(o.len + sizeof(o.code));
1085 #ifndef SMALL
1086 for (l = 0, opt = ifo->dhcp6_override;
1087 l < ifo->dhcp6_override_len;
1088 l++, opt++)
1090 if (!DHC_REQOPT(opt, ifo->requestmask6, ifo->nomask6))
1091 continue;
1092 o.code = htons((uint16_t)opt->option);
1093 memcpy(p, &o.code, sizeof(o.code));
1094 p += sizeof(o.code);
1095 o.len = (uint16_t)(o.len + sizeof(o.code));
1097 if (dhcp6_findselfsla(ifp)) {
1098 o.code = htons(D6_OPTION_PD_EXCLUDE);
1099 memcpy(p, &o.code, sizeof(o.code));
1100 p += sizeof(o.code);
1101 o.len = (uint16_t)(o.len + sizeof(o.code));
1103 #endif
1104 o.len = htons(o.len);
1105 memcpy(o_lenp, &o.len, sizeof(o.len));
1108 si_len = 0;
1109 COPYIN(D6_OPTION_ELAPSED, &si_len, sizeof(si_len));
1111 if (state->state == DH6S_DISCOVER &&
1112 !(ifp->ctx->options & DHCPCD_TEST) &&
1113 DHC_REQ(ifo->requestmask6, ifo->nomask6, D6_OPTION_RAPID_COMMIT))
1114 COPYIN1(D6_OPTION_RAPID_COMMIT, 0);
1116 if (!has_option_mask(ifo->nomask6, D6_OPTION_USER_CLASS))
1117 p += dhcp6_makeuser(p, ifp);
1118 if (!has_option_mask(ifo->nomask6, D6_OPTION_VENDOR_CLASS))
1119 p += dhcp6_makevendor(p, ifp);
1121 if (state->send->type != DHCP6_RELEASE &&
1122 state->send->type != DHCP6_DECLINE)
1124 if (fqdn != FQDN_DISABLE) {
1125 o_lenp = NEXTLEN;
1126 COPYIN1(D6_OPTION_FQDN, 0);
1127 if (hl == 0)
1128 *p = D6_FQDN_NONE;
1129 else {
1130 switch (fqdn) {
1131 case FQDN_BOTH:
1132 *p = D6_FQDN_BOTH;
1133 break;
1134 case FQDN_PTR:
1135 *p = D6_FQDN_PTR;
1136 break;
1137 default:
1138 *p = D6_FQDN_NONE;
1139 break;
1142 p++;
1143 encode_rfc1035(hostname, p);
1144 p += hl;
1145 o.len = htons((uint16_t)(hl + 1));
1146 memcpy(o_lenp, &o.len, sizeof(o.len));
1149 if (!has_option_mask(ifo->nomask6, D6_OPTION_MUDURL) &&
1150 ifo->mudurl[0])
1151 COPYIN(D6_OPTION_MUDURL,
1152 ifo->mudurl + 1, ifo->mudurl[0]);
1154 #ifdef AUTH
1155 if ((ifo->auth.options & DHCPCD_AUTH_SENDREQUIRE) !=
1156 DHCPCD_AUTH_SENDREQUIRE &&
1157 DHC_REQ(ifo->requestmask6, ifo->nomask6,
1158 D6_OPTION_RECONF_ACCEPT))
1159 COPYIN1(D6_OPTION_RECONF_ACCEPT, 0);
1160 #endif
1164 #ifdef AUTH
1165 /* This has to be the last option */
1166 if (ifo->auth.options & DHCPCD_AUTH_SEND && auth_len != 0) {
1167 COPYIN1(D6_OPTION_AUTH, auth_len);
1168 /* data will be filled at send message time */
1170 #endif
1172 return 0;
1175 static const char *
1176 dhcp6_get_op(uint16_t type)
1178 const struct dhcp6_op *d;
1180 for (d = dhcp6_ops; d->name; d++)
1181 if (d->type == type)
1182 return d->name;
1183 return NULL;
1186 static void
1187 dhcp6_freedrop_addrs(struct interface *ifp, int drop,
1188 const struct interface *ifd)
1190 struct dhcp6_state *state;
1192 state = D6_STATE(ifp);
1193 if (state) {
1194 ipv6_freedrop_addrs(&state->addrs, drop, ifd);
1195 if (drop)
1196 rt_build(ifp->ctx, AF_INET6);
1200 #ifndef SMALL
1201 static void dhcp6_delete_delegates(struct interface *ifp)
1203 struct interface *ifp0;
1205 if (ifp->ctx->ifaces) {
1206 TAILQ_FOREACH(ifp0, ifp->ctx->ifaces, next) {
1207 if (ifp0 != ifp)
1208 dhcp6_freedrop_addrs(ifp0, 1, ifp);
1212 #endif
1214 #ifdef AUTH
1215 static ssize_t
1216 dhcp6_update_auth(struct interface *ifp, struct dhcp6_message *m, size_t len)
1218 struct dhcp6_state *state;
1219 uint8_t *opt;
1220 uint16_t opt_len;
1222 opt = dhcp6_findmoption(m, len, D6_OPTION_AUTH, &opt_len);
1223 if (opt == NULL)
1224 return -1;
1226 state = D6_STATE(ifp);
1227 return dhcp_auth_encode(ifp->ctx, &ifp->options->auth,
1228 state->auth.token, (uint8_t *)state->send, state->send_len, 6,
1229 state->send->type, opt, opt_len);
1231 #endif
1233 static const struct in6_addr alldhcp = IN6ADDR_LINKLOCAL_ALLDHCP_INIT;
1234 static int
1235 dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *))
1237 struct dhcp6_state *state = D6_STATE(ifp);
1238 struct dhcpcd_ctx *ctx = ifp->ctx;
1239 unsigned int RT;
1240 bool multicast = true;
1241 struct sockaddr_in6 dst = {
1242 .sin6_family = AF_INET6,
1243 /* Setting the port on Linux gives EINVAL when sending.
1244 * This looks like a kernel bug as the equivalent works
1245 * fine with the DHCP counterpart. */
1246 #ifndef __linux__
1247 .sin6_port = htons(DHCP6_SERVER_PORT),
1248 #endif
1250 struct udphdr udp = {
1251 .uh_sport = htons(DHCP6_CLIENT_PORT),
1252 .uh_dport = htons(DHCP6_SERVER_PORT),
1253 .uh_ulen = htons((uint16_t)(sizeof(udp) + state->send_len)),
1255 struct iovec iov[] = {
1256 { .iov_base = &udp, .iov_len = sizeof(udp), },
1257 { .iov_base = state->send, .iov_len = state->send_len, },
1259 union {
1260 struct cmsghdr hdr;
1261 uint8_t buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
1262 } cmsgbuf = { .buf = { 0 } };
1263 struct msghdr msg = {
1264 .msg_name = &dst, .msg_namelen = sizeof(dst),
1265 .msg_iov = iov, .msg_iovlen = __arraycount(iov),
1267 char uaddr[INET6_ADDRSTRLEN];
1269 if (!callback && !if_is_link_up(ifp))
1270 return 0;
1272 if (!IN6_IS_ADDR_UNSPECIFIED(&state->unicast)) {
1273 switch (state->send->type) {
1274 case DHCP6_SOLICIT: /* FALLTHROUGH */
1275 case DHCP6_CONFIRM: /* FALLTHROUGH */
1276 case DHCP6_REBIND:
1277 /* Unicasting is denied for these types. */
1278 break;
1279 default:
1280 multicast = false;
1281 inet_ntop(AF_INET6, &state->unicast, uaddr,
1282 sizeof(uaddr));
1283 break;
1286 dst.sin6_addr = multicast ? alldhcp : state->unicast;
1288 if (!callback) {
1289 logdebugx("%s: %s %s with xid 0x%02x%02x%02x%s%s",
1290 ifp->name,
1291 multicast ? "multicasting" : "unicasting",
1292 dhcp6_get_op(state->send->type),
1293 state->send->xid[0],
1294 state->send->xid[1],
1295 state->send->xid[2],
1296 !multicast ? " " : "",
1297 !multicast ? uaddr : "");
1298 RT = 0;
1299 } else {
1300 if (state->IMD &&
1301 !(ifp->options->options & DHCPCD_INITIAL_DELAY))
1302 state->IMD = 0;
1303 if (state->IMD) {
1304 state->RT = state->IMD * MSEC_PER_SEC;
1305 /* Some buggy PPP servers close the link too early
1306 * after sending an invalid status in their reply
1307 * which means this host won't see it.
1308 * 1 second grace seems to be the sweet spot. */
1309 if (ifp->flags & IFF_POINTOPOINT)
1310 state->RT += MSEC_PER_SEC;
1311 } else if (state->RTC == 0)
1312 state->RT = state->IRT * MSEC_PER_SEC;
1314 if (state->MRT != 0) {
1315 unsigned int mrt = state->MRT * MSEC_PER_SEC;
1317 if (state->RT > mrt)
1318 state->RT = mrt;
1321 /* Add -.1 to .1 * RT randomness as per RFC8415 section 15 */
1322 uint32_t lru = arc4random_uniform(
1323 state->RTC == 0 ? DHCP6_RAND_MAX
1324 : DHCP6_RAND_MAX - DHCP6_RAND_MIN);
1325 int lr = (int)lru - (state->RTC == 0 ? 0 : DHCP6_RAND_MAX);
1326 RT = state->RT
1327 + (unsigned int)((float)state->RT
1328 * ((float)lr / DHCP6_RAND_DIV));
1330 if (if_is_link_up(ifp))
1331 logdebugx("%s: %s %s (xid 0x%02x%02x%02x)%s%s,"
1332 " next in %0.1f seconds",
1333 ifp->name,
1334 state->IMD != 0 ? "delaying" :
1335 multicast ? "multicasting" : "unicasting",
1336 dhcp6_get_op(state->send->type),
1337 state->send->xid[0],
1338 state->send->xid[1],
1339 state->send->xid[2],
1340 state->IMD == 0 && !multicast ? " " : "",
1341 state->IMD == 0 && !multicast ? uaddr : "",
1342 (float)RT / MSEC_PER_SEC);
1344 /* Wait the initial delay */
1345 if (state->IMD != 0) {
1346 state->IMD = 0;
1347 eloop_timeout_add_msec(ctx->eloop, RT, callback, ifp);
1348 return 0;
1352 if (!if_is_link_up(ifp))
1353 return 0;
1355 /* Update the elapsed time */
1356 dhcp6_updateelapsed(ifp, state->send, state->send_len);
1357 #ifdef AUTH
1358 if (ifp->options->auth.options & DHCPCD_AUTH_SEND &&
1359 dhcp6_update_auth(ifp, state->send, state->send_len) == -1)
1361 logerr("%s: %s: dhcp6_updateauth", __func__, ifp->name);
1362 if (errno != ESRCH)
1363 return -1;
1365 #endif
1367 /* Set the outbound interface */
1368 if (multicast) {
1369 struct cmsghdr *cm;
1370 struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
1372 dst.sin6_scope_id = ifp->index;
1373 msg.msg_control = cmsgbuf.buf;
1374 msg.msg_controllen = sizeof(cmsgbuf.buf);
1375 cm = CMSG_FIRSTHDR(&msg);
1376 if (cm == NULL) /* unlikely */
1377 return -1;
1378 cm->cmsg_level = IPPROTO_IPV6;
1379 cm->cmsg_type = IPV6_PKTINFO;
1380 cm->cmsg_len = CMSG_LEN(sizeof(pi));
1381 memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
1384 #ifdef PRIVSEP
1385 if (IN_PRIVSEP(ifp->ctx)) {
1386 if (ps_inet_senddhcp6(ifp, &msg) == -1)
1387 logerr(__func__);
1388 goto sent;
1390 #endif
1392 if (sendmsg(ctx->dhcp6_wfd, &msg, 0) == -1) {
1393 logerr("%s: %s: sendmsg", __func__, ifp->name);
1394 /* Allow DHCPv6 to continue .... the errors
1395 * would be rate limited by the protocol.
1396 * Generally the error is ENOBUFS when struggling to
1397 * associate with an access point. */
1400 #ifdef PRIVSEP
1401 sent:
1402 #endif
1403 state->RTC++;
1404 if (callback) {
1405 state->RT = RT * 2;
1406 if (state->RT < RT) /* Check overflow */
1407 state->RT = RT;
1408 if (state->MRC == 0 || state->RTC < state->MRC)
1409 eloop_timeout_add_msec(ctx->eloop,
1410 RT, callback, ifp);
1411 else if (state->MRC != 0 && state->MRCcallback)
1412 eloop_timeout_add_msec(ctx->eloop,
1413 RT, state->MRCcallback, ifp);
1414 else
1415 logwarnx("%s: sent %d times with no reply",
1416 ifp->name, state->RTC);
1418 return 0;
1421 static void
1422 dhcp6_sendinform(void *arg)
1425 dhcp6_sendmessage(arg, dhcp6_sendinform);
1428 static void
1429 dhcp6_senddiscover(void *arg)
1432 dhcp6_sendmessage(arg, dhcp6_senddiscover);
1435 static void
1436 dhcp6_sendrequest(void *arg)
1439 dhcp6_sendmessage(arg, dhcp6_sendrequest);
1442 static void
1443 dhcp6_sendrebind(void *arg)
1446 dhcp6_sendmessage(arg, dhcp6_sendrebind);
1449 static void
1450 dhcp6_sendrenew(void *arg)
1453 dhcp6_sendmessage(arg, dhcp6_sendrenew);
1456 static void
1457 dhcp6_sendconfirm(void *arg)
1460 dhcp6_sendmessage(arg, dhcp6_sendconfirm);
1463 static void
1464 dhcp6_senddecline(void *arg)
1467 dhcp6_sendmessage(arg, dhcp6_senddecline);
1470 static void
1471 dhcp6_sendrelease(void *arg)
1474 dhcp6_sendmessage(arg, dhcp6_sendrelease);
1477 static void
1478 dhcp6_startrenew(void *arg)
1480 struct interface *ifp;
1481 struct dhcp6_state *state;
1483 ifp = arg;
1484 if ((state = D6_STATE(ifp)) == NULL)
1485 return;
1487 /* Only renew in the bound or renew states */
1488 if (state->state != DH6S_BOUND &&
1489 state->state != DH6S_RENEW)
1490 return;
1492 /* Remove the timeout as the renew may have been forced. */
1493 eloop_timeout_delete(ifp->ctx->eloop, dhcp6_startrenew, ifp);
1495 state->state = DH6S_RENEW;
1496 state->RTC = 0;
1497 state->IMD = REN_MAX_DELAY;
1498 state->IRT = REN_TIMEOUT;
1499 state->MRT = REN_MAX_RT;
1500 state->MRC = 0;
1502 if (dhcp6_makemessage(ifp) == -1)
1503 logerr("%s: %s", __func__, ifp->name);
1504 else
1505 dhcp6_sendrenew(ifp);
1508 void dhcp6_renew(struct interface *ifp)
1511 dhcp6_startrenew(ifp);
1514 bool
1515 dhcp6_dadcompleted(const struct interface *ifp)
1517 const struct dhcp6_state *state;
1518 const struct ipv6_addr *ap;
1520 state = D6_CSTATE(ifp);
1521 TAILQ_FOREACH(ap, &state->addrs, next) {
1522 if (ap->flags & IPV6_AF_ADDED &&
1523 !(ap->flags & IPV6_AF_DADCOMPLETED))
1524 return false;
1526 return true;
1529 static void
1530 dhcp6_dadcallback(void *arg)
1532 struct ipv6_addr *ia = arg;
1533 struct interface *ifp;
1534 struct dhcp6_state *state;
1535 struct ipv6_addr *ia2;
1536 bool completed, valid, oneduplicated;
1538 completed = (ia->flags & IPV6_AF_DADCOMPLETED);
1539 ia->flags |= IPV6_AF_DADCOMPLETED;
1540 if (ia->addr_flags & IN6_IFF_DUPLICATED)
1541 logwarnx("%s: DAD detected %s", ia->iface->name, ia->saddr);
1543 #ifdef ND6_ADVERTISE
1544 else
1545 ipv6nd_advertise(ia);
1546 #endif
1547 if (completed)
1548 return;
1550 ifp = ia->iface;
1551 state = D6_STATE(ifp);
1552 if (state->state != DH6S_BOUND && state->state != DH6S_DELEGATED)
1553 return;
1555 #ifdef SMALL
1556 valid = true;
1557 #else
1558 valid = (ia->delegating_prefix == NULL);
1559 #endif
1560 completed = true;
1561 oneduplicated = false;
1562 TAILQ_FOREACH(ia2, &state->addrs, next) {
1563 if (ia2->flags & IPV6_AF_ADDED &&
1564 !(ia2->flags & IPV6_AF_DADCOMPLETED))
1566 completed = false;
1567 break;
1569 if (DECLINE_IA(ia))
1570 oneduplicated = true;
1572 if (!completed)
1573 return;
1575 logdebugx("%s: DHCPv6 DAD completed", ifp->name);
1577 if (oneduplicated && state->state == DH6S_BOUND) {
1578 dhcp6_startdecline(ifp);
1579 return;
1582 script_runreason(ifp,
1583 #ifndef SMALL
1584 ia->delegating_prefix ? "DELEGATED6" :
1585 #endif
1586 state->reason);
1587 if (valid)
1588 dhcpcd_daemonise(ifp->ctx);
1591 static void
1592 dhcp6_addrequestedaddrs(struct interface *ifp)
1594 struct dhcp6_state *state;
1595 size_t i;
1596 struct if_ia *ia;
1597 struct ipv6_addr *a;
1599 state = D6_STATE(ifp);
1600 /* Add any requested prefixes / addresses */
1601 for (i = 0; i < ifp->options->ia_len; i++) {
1602 ia = &ifp->options->ia[i];
1603 if (!((ia->ia_type == D6_OPTION_IA_PD && ia->prefix_len) ||
1604 !IN6_IS_ADDR_UNSPECIFIED(&ia->addr)))
1605 continue;
1606 a = ipv6_newaddr(ifp, &ia->addr,
1608 * RFC 5942 Section 5
1609 * We cannot assume any prefix length, nor tie the
1610 * address to an existing one as it could expire
1611 * before the address.
1612 * As such we just give it a 128 prefix.
1614 ia->ia_type == D6_OPTION_IA_PD ? ia->prefix_len : 128,
1615 IPV6_AF_REQUEST);
1616 if (a == NULL)
1617 continue;
1618 a->dadcallback = dhcp6_dadcallback;
1619 memcpy(&a->iaid, &ia->iaid, sizeof(a->iaid));
1620 a->ia_type = ia->ia_type;
1621 TAILQ_INSERT_TAIL(&state->addrs, a, next);
1625 static void
1626 dhcp6_startdiscover(void *arg)
1628 struct interface *ifp;
1629 struct dhcp6_state *state;
1630 int llevel;
1632 ifp = arg;
1633 state = D6_STATE(ifp);
1634 #ifndef SMALL
1635 if (state->reason == NULL || strcmp(state->reason, "TIMEOUT6") != 0)
1636 dhcp6_delete_delegates(ifp);
1637 #endif
1638 if (state->new == NULL && !state->failed)
1639 llevel = LOG_INFO;
1640 else
1641 llevel = LOG_DEBUG;
1642 logmessage(llevel, "%s: soliciting a DHCPv6 lease", ifp->name);
1643 state->state = DH6S_DISCOVER;
1644 state->RTC = 0;
1645 state->IMD = SOL_MAX_DELAY;
1646 state->IRT = SOL_TIMEOUT;
1647 state->MRT = state->sol_max_rt;
1648 state->MRC = SOL_MAX_RC;
1650 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
1651 free(state->new);
1652 state->new = NULL;
1653 state->new_len = 0;
1655 if (dhcp6_makemessage(ifp) == -1)
1656 logerr("%s: %s", __func__, ifp->name);
1657 else
1658 dhcp6_senddiscover(ifp);
1661 static void
1662 dhcp6_startinform(void *arg)
1664 struct interface *ifp;
1665 struct dhcp6_state *state;
1666 int llevel;
1668 ifp = arg;
1669 state = D6_STATE(ifp);
1670 llevel = state->failed ? LOG_DEBUG : LOG_INFO;
1671 logmessage(llevel, "%s: requesting DHCPv6 information", ifp->name);
1672 state->state = DH6S_INFORM;
1673 state->RTC = 0;
1674 state->IMD = INF_MAX_DELAY;
1675 state->IRT = INF_TIMEOUT;
1676 state->MRT = state->inf_max_rt;
1677 state->MRC = 0;
1679 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
1680 if (dhcp6_makemessage(ifp) == -1) {
1681 logerr("%s: %s", __func__, ifp->name);
1682 return;
1684 dhcp6_sendinform(ifp);
1685 /* RFC3315 18.1.2 says that if CONFIRM failed then the prior addresses
1686 * SHOULD be used. The wording here is poor, because the addresses are
1687 * merely one facet of the lease as a whole.
1688 * This poor wording might explain the lack of similar text for INFORM
1689 * in 18.1.5 because there are no addresses in the INFORM message. */
1690 eloop_timeout_add_sec(ifp->ctx->eloop,
1691 INF_MAX_RD, dhcp6_failinform, ifp);
1694 static bool
1695 dhcp6_startdiscoinform(struct interface *ifp)
1697 unsigned long long opts = ifp->options->options;
1699 if (opts & DHCPCD_IA_FORCED || ipv6nd_hasradhcp(ifp, true))
1700 dhcp6_startdiscover(ifp);
1701 else if (opts & DHCPCD_INFORM6 || ipv6nd_hasradhcp(ifp, false))
1702 dhcp6_startinform(ifp);
1703 else
1704 return false;
1705 return true;
1708 static void
1709 dhcp6_leaseextend(struct interface *ifp)
1711 struct dhcp6_state *state = D6_STATE(ifp);
1712 struct ipv6_addr *ia;
1714 logwarnx("%s: extending DHCPv6 lease", ifp->name);
1715 TAILQ_FOREACH(ia, &state->addrs, next) {
1716 ia->flags |= IPV6_AF_EXTENDED;
1717 /* Set infinite lifetimes. */
1718 ia->prefix_pltime = ND6_INFINITE_LIFETIME;
1719 ia->prefix_vltime = ND6_INFINITE_LIFETIME;
1723 static void
1724 dhcp6_fail(struct interface *ifp)
1726 struct dhcp6_state *state = D6_STATE(ifp);
1728 state->failed = true;
1730 /* RFC3315 18.1.2 says that prior addresses SHOULD be used on failure.
1731 * RFC2131 3.2.3 says that MAY chose to use the prior address.
1732 * Because dhcpcd was written first for RFC2131, we have the LASTLEASE
1733 * option which defaults to off as that makes the most sense for
1734 * mobile clients.
1735 * dhcpcd also has LASTLEASE_EXTEND to extend this lease past it's
1736 * expiry, but this is strictly not RFC compliant in any way or form. */
1737 if (state->new != NULL &&
1738 ifp->options->options & DHCPCD_LASTLEASE_EXTEND)
1740 dhcp6_leaseextend(ifp);
1741 dhcp6_bind(ifp, NULL, NULL);
1742 } else {
1743 dhcp6_freedrop_addrs(ifp, 1, NULL);
1744 #ifndef SMALL
1745 dhcp6_delete_delegates(ifp);
1746 #endif
1747 free(state->old);
1748 state->old = state->new;
1749 state->old_len = state->new_len;
1750 state->new = NULL;
1751 state->new_len = 0;
1752 if (state->old != NULL)
1753 script_runreason(ifp, "EXPIRE6");
1754 dhcp_unlink(ifp->ctx, state->leasefile);
1755 dhcp6_addrequestedaddrs(ifp);
1758 if (!dhcp6_startdiscoinform(ifp)) {
1759 logwarnx("%s: no advertising IPv6 router wants DHCP",ifp->name);
1760 state->state = DH6S_INIT;
1761 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
1765 static int
1766 dhcp6_failloglevel(struct interface *ifp)
1768 const struct dhcp6_state *state = D6_CSTATE(ifp);
1770 return state->failed ? LOG_DEBUG : LOG_ERR;
1773 static void
1774 dhcp6_failconfirm(void *arg)
1776 struct interface *ifp = arg;
1777 int llevel = dhcp6_failloglevel(ifp);
1779 logmessage(llevel, "%s: failed to confirm prior DHCPv6 address",
1780 ifp->name);
1781 dhcp6_fail(ifp);
1784 static void
1785 dhcp6_failrequest(void *arg)
1787 struct interface *ifp = arg;
1788 int llevel = dhcp6_failloglevel(ifp);
1790 logmessage(llevel, "%s: failed to request DHCPv6 address", ifp->name);
1791 dhcp6_fail(ifp);
1794 static void
1795 dhcp6_failinform(void *arg)
1797 struct interface *ifp = arg;
1798 int llevel = dhcp6_failloglevel(ifp);
1800 logmessage(llevel, "%s: failed to request DHCPv6 information",
1801 ifp->name);
1802 dhcp6_fail(ifp);
1805 #ifndef SMALL
1806 static void
1807 dhcp6_failrebind(void *arg)
1809 struct interface *ifp = arg;
1811 logerrx("%s: failed to rebind prior DHCPv6 delegation", ifp->name);
1812 dhcp6_fail(ifp);
1815 static int
1816 dhcp6_hasprefixdelegation(struct interface *ifp)
1818 size_t i;
1819 uint16_t t;
1821 t = 0;
1822 for (i = 0; i < ifp->options->ia_len; i++) {
1823 if (t && t != ifp->options->ia[i].ia_type) {
1824 if (t == D6_OPTION_IA_PD ||
1825 ifp->options->ia[i].ia_type == D6_OPTION_IA_PD)
1826 return 2;
1828 t = ifp->options->ia[i].ia_type;
1830 return t == D6_OPTION_IA_PD ? 1 : 0;
1832 #endif
1834 static void
1835 dhcp6_startrebind(void *arg)
1837 struct interface *ifp;
1838 struct dhcp6_state *state;
1839 #ifndef SMALL
1840 int pd;
1841 #endif
1843 ifp = arg;
1844 eloop_timeout_delete(ifp->ctx->eloop, dhcp6_sendrenew, ifp);
1845 state = D6_STATE(ifp);
1846 if (state->state == DH6S_RENEW)
1847 logwarnx("%s: failed to renew DHCPv6, rebinding", ifp->name);
1848 else
1849 loginfox("%s: rebinding prior DHCPv6 lease", ifp->name);
1850 state->state = DH6S_REBIND;
1851 state->RTC = 0;
1852 state->MRC = 0;
1854 #ifndef SMALL
1855 /* RFC 3633 section 12.1 */
1856 pd = dhcp6_hasprefixdelegation(ifp);
1857 if (pd) {
1858 state->IMD = CNF_MAX_DELAY;
1859 state->IRT = CNF_TIMEOUT;
1860 state->MRT = CNF_MAX_RT;
1861 } else
1862 #endif
1864 state->IMD = REB_MAX_DELAY;
1865 state->IRT = REB_TIMEOUT;
1866 state->MRT = REB_MAX_RT;
1869 if (dhcp6_makemessage(ifp) == -1)
1870 logerr("%s: %s", __func__, ifp->name);
1871 else
1872 dhcp6_sendrebind(ifp);
1874 #ifndef SMALL
1875 /* RFC 3633 section 12.1 */
1876 if (pd)
1877 eloop_timeout_add_sec(ifp->ctx->eloop,
1878 CNF_MAX_RD, dhcp6_failrebind, ifp);
1879 #endif
1883 static void
1884 dhcp6_startrequest(struct interface *ifp)
1886 struct dhcp6_state *state;
1888 eloop_timeout_delete(ifp->ctx->eloop, dhcp6_senddiscover, ifp);
1889 state = D6_STATE(ifp);
1890 state->state = DH6S_REQUEST;
1891 state->RTC = 0;
1892 state->IMD = 0;
1893 state->IRT = REQ_TIMEOUT;
1894 state->MRT = REQ_MAX_RT;
1895 state->MRC = REQ_MAX_RC;
1896 state->MRCcallback = dhcp6_failrequest;
1898 if (dhcp6_makemessage(ifp) == -1) {
1899 logerr("%s: %s", __func__, ifp->name);
1900 return;
1903 dhcp6_sendrequest(ifp);
1906 static void
1907 dhcp6_startconfirm(struct interface *ifp)
1909 struct dhcp6_state *state;
1910 struct ipv6_addr *ia;
1912 state = D6_STATE(ifp);
1914 TAILQ_FOREACH(ia, &state->addrs, next) {
1915 if (!DECLINE_IA(ia))
1916 continue;
1917 logerrx("%s: prior DHCPv6 has a duplicated address", ifp->name);
1918 dhcp6_startdecline(ifp);
1919 return;
1922 state->state = DH6S_CONFIRM;
1923 state->RTC = 0;
1924 state->IMD = CNF_MAX_DELAY;
1925 state->IRT = CNF_TIMEOUT;
1926 state->MRT = CNF_MAX_RT;
1927 state->MRC = CNF_MAX_RC;
1929 loginfox("%s: confirming prior DHCPv6 lease", ifp->name);
1931 if (dhcp6_makemessage(ifp) == -1) {
1932 logerr("%s: %s", __func__, ifp->name);
1933 return;
1935 dhcp6_sendconfirm(ifp);
1936 eloop_timeout_add_sec(ifp->ctx->eloop,
1937 CNF_MAX_RD, dhcp6_failconfirm, ifp);
1940 static void
1941 dhcp6_startexpire(void *arg)
1943 struct interface *ifp;
1945 ifp = arg;
1946 eloop_timeout_delete(ifp->ctx->eloop, dhcp6_sendrebind, ifp);
1948 logerrx("%s: DHCPv6 lease expired", ifp->name);
1949 dhcp6_fail(ifp);
1952 static void
1953 dhcp6_faildecline(void *arg)
1955 struct interface *ifp = arg;
1957 logerrx("%s: failed to decline duplicated DHCPv6 addresses", ifp->name);
1958 dhcp6_fail(ifp);
1961 static void
1962 dhcp6_startdecline(struct interface *ifp)
1964 struct dhcp6_state *state;
1966 state = D6_STATE(ifp);
1967 loginfox("%s: declining failed DHCPv6 addresses", ifp->name);
1968 state->state = DH6S_DECLINE;
1969 state->RTC = 0;
1970 state->IMD = 0;
1971 state->IRT = DEC_TIMEOUT;
1972 state->MRT = 0;
1973 state->MRC = DEC_MAX_RC;
1974 state->MRCcallback = dhcp6_faildecline;
1976 if (dhcp6_makemessage(ifp) == -1)
1977 logerr("%s: %s", __func__, ifp->name);
1978 else
1979 dhcp6_senddecline(ifp);
1982 static void
1983 dhcp6_finishrelease(void *arg)
1985 struct interface *ifp;
1986 struct dhcp6_state *state;
1988 ifp = (struct interface *)arg;
1989 if ((state = D6_STATE(ifp)) != NULL) {
1990 state->state = DH6S_RELEASED;
1991 dhcp6_drop(ifp, "RELEASE6");
1995 static void
1996 dhcp6_startrelease(struct interface *ifp)
1998 struct dhcp6_state *state;
2000 state = D6_STATE(ifp);
2001 if (state->state != DH6S_BOUND)
2002 return;
2004 state->state = DH6S_RELEASE;
2005 state->RTC = 0;
2006 state->IMD = REL_MAX_DELAY;
2007 state->IRT = REL_TIMEOUT;
2008 state->MRT = REL_MAX_RT;
2009 /* MRC of REL_MAX_RC is optional in RFC 3315 18.1.6 */
2010 #if 0
2011 state->MRC = REL_MAX_RC;
2012 state->MRCcallback = dhcp6_finishrelease;
2013 #else
2014 state->MRC = 0;
2015 state->MRCcallback = NULL;
2016 #endif
2018 if (dhcp6_makemessage(ifp) == -1)
2019 logerr("%s: %s", __func__, ifp->name);
2020 else {
2021 dhcp6_sendrelease(ifp);
2022 dhcp6_finishrelease(ifp);
2026 static int
2027 dhcp6_checkstatusok(const struct interface *ifp,
2028 struct dhcp6_message *m, uint8_t *p, size_t len)
2030 struct dhcp6_state *state;
2031 uint8_t *opt;
2032 uint16_t opt_len, code;
2033 size_t mlen;
2034 void * (*f)(void *, size_t, uint16_t, uint16_t *), *farg;
2035 char buf[32], *sbuf;
2036 const char *status;
2037 int loglevel;
2039 state = D6_STATE(ifp);
2040 f = p ? dhcp6_findoption : dhcp6_findmoption;
2041 if (p)
2042 farg = p;
2043 else
2044 farg = m;
2045 if ((opt = f(farg, len, D6_OPTION_STATUS_CODE, &opt_len)) == NULL) {
2046 //logdebugx("%s: no status", ifp->name);
2047 state->lerror = 0;
2048 errno = ESRCH;
2049 return 0;
2052 if (opt_len < sizeof(code)) {
2053 logerrx("%s: status truncated", ifp->name);
2054 return -1;
2056 memcpy(&code, opt, sizeof(code));
2057 code = ntohs(code);
2058 if (code == D6_STATUS_OK) {
2059 state->lerror = 0;
2060 errno = 0;
2061 return 0;
2064 /* Anything after the code is a message. */
2065 opt += sizeof(code);
2066 mlen = opt_len - sizeof(code);
2067 if (mlen == 0) {
2068 sbuf = NULL;
2069 if (code < sizeof(dhcp6_statuses) / sizeof(char *))
2070 status = dhcp6_statuses[code];
2071 else {
2072 snprintf(buf, sizeof(buf), "Unknown Status (%d)", code);
2073 status = buf;
2075 } else {
2076 if ((sbuf = malloc(mlen + 1)) == NULL) {
2077 logerr(__func__);
2078 return -1;
2080 memcpy(sbuf, opt, mlen);
2081 sbuf[mlen] = '\0';
2082 status = sbuf;
2085 if (state->lerror == code || state->state == DH6S_INIT)
2086 loglevel = LOG_DEBUG;
2087 else
2088 loglevel = LOG_ERR;
2089 logmessage(loglevel, "%s: DHCPv6 REPLY: %s", ifp->name, status);
2090 free(sbuf);
2091 state->lerror = code;
2092 errno = 0;
2094 /* code cannot be D6_STATUS_OK, so there is a failure */
2095 if (ifp->ctx->options & DHCPCD_TEST)
2096 eloop_exit(ifp->ctx->eloop, EXIT_FAILURE);
2098 return (int)code;
2101 const struct ipv6_addr *
2102 dhcp6_iffindaddr(const struct interface *ifp, const struct in6_addr *addr,
2103 unsigned int flags)
2105 const struct dhcp6_state *state;
2106 const struct ipv6_addr *ap;
2108 if ((state = D6_STATE(ifp)) != NULL) {
2109 TAILQ_FOREACH(ap, &state->addrs, next) {
2110 if (ipv6_findaddrmatch(ap, addr, flags))
2111 return ap;
2114 return NULL;
2117 struct ipv6_addr *
2118 dhcp6_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr,
2119 unsigned int flags)
2121 struct interface *ifp;
2122 struct ipv6_addr *ap;
2123 struct dhcp6_state *state;
2125 TAILQ_FOREACH(ifp, ctx->ifaces, next) {
2126 if ((state = D6_STATE(ifp)) != NULL) {
2127 TAILQ_FOREACH(ap, &state->addrs, next) {
2128 if (ipv6_findaddrmatch(ap, addr, flags))
2129 return ap;
2133 return NULL;
2136 static int
2137 dhcp6_findna(struct interface *ifp, uint16_t ot, const uint8_t *iaid,
2138 uint8_t *d, size_t l, const struct timespec *acquired)
2140 struct dhcp6_state *state;
2141 uint8_t *o, *nd;
2142 uint16_t ol;
2143 struct ipv6_addr *a;
2144 int i;
2145 struct dhcp6_ia_addr ia;
2147 i = 0;
2148 state = D6_STATE(ifp);
2149 while ((o = dhcp6_findoption(d, l, D6_OPTION_IA_ADDR, &ol))) {
2150 /* Set d and l first to ensure we find the next option. */
2151 nd = o + ol;
2152 l -= (size_t)(nd - d);
2153 d = nd;
2154 if (ol < sizeof(ia)) {
2155 errno = EINVAL;
2156 logerrx("%s: IA Address option truncated", ifp->name);
2157 continue;
2159 memcpy(&ia, o, sizeof(ia));
2160 ia.pltime = ntohl(ia.pltime);
2161 ia.vltime = ntohl(ia.vltime);
2162 /* RFC 3315 22.6 */
2163 if (ia.pltime > ia.vltime) {
2164 errno = EINVAL;
2165 logerr("%s: IA Address pltime %"PRIu32
2166 " > vltime %"PRIu32,
2167 ifp->name, ia.pltime, ia.vltime);
2168 continue;
2170 TAILQ_FOREACH(a, &state->addrs, next) {
2171 if (ipv6_findaddrmatch(a, &ia.addr, 0))
2172 break;
2174 if (a == NULL) {
2176 * RFC 5942 Section 5
2177 * We cannot assume any prefix length, nor tie the
2178 * address to an existing one as it could expire
2179 * before the address.
2180 * As such we just give it a 128 prefix.
2182 a = ipv6_newaddr(ifp, &ia.addr, 128, IPV6_AF_ONLINK);
2183 a->dadcallback = dhcp6_dadcallback;
2184 a->ia_type = ot;
2185 memcpy(a->iaid, iaid, sizeof(a->iaid));
2186 a->created = *acquired;
2188 TAILQ_INSERT_TAIL(&state->addrs, a, next);
2189 } else {
2190 if (!(a->flags & IPV6_AF_ONLINK))
2191 a->flags |= IPV6_AF_ONLINK | IPV6_AF_NEW;
2192 a->flags &= ~(IPV6_AF_STALE | IPV6_AF_EXTENDED);
2194 a->acquired = *acquired;
2195 a->prefix_pltime = ia.pltime;
2196 if (a->prefix_vltime != ia.vltime) {
2197 a->flags |= IPV6_AF_NEW;
2198 a->prefix_vltime = ia.vltime;
2200 if (a->prefix_pltime && a->prefix_pltime < state->lowpl)
2201 state->lowpl = a->prefix_pltime;
2202 if (a->prefix_vltime && a->prefix_vltime > state->expire)
2203 state->expire = a->prefix_vltime;
2204 i++;
2206 return i;
2209 #ifndef SMALL
2210 static int
2211 dhcp6_findpd(struct interface *ifp, const uint8_t *iaid,
2212 uint8_t *d, size_t l, const struct timespec *acquired)
2214 struct dhcp6_state *state;
2215 uint8_t *o, *nd;
2216 struct ipv6_addr *a;
2217 int i;
2218 uint8_t nb, *pw;
2219 uint16_t ol;
2220 struct dhcp6_pd_addr pdp;
2221 struct in6_addr pdp_prefix;
2223 i = 0;
2224 state = D6_STATE(ifp);
2225 while ((o = dhcp6_findoption(d, l, D6_OPTION_IAPREFIX, &ol))) {
2226 /* Set d and l first to ensure we find the next option. */
2227 nd = o + ol;
2228 l -= (size_t)(nd - d);
2229 d = nd;
2230 if (ol < sizeof(pdp)) {
2231 errno = EINVAL;
2232 logerrx("%s: IA Prefix option truncated", ifp->name);
2233 continue;
2236 memcpy(&pdp, o, sizeof(pdp));
2237 pdp.pltime = ntohl(pdp.pltime);
2238 pdp.vltime = ntohl(pdp.vltime);
2239 /* RFC 3315 22.6 */
2240 if (pdp.pltime > pdp.vltime) {
2241 errno = EINVAL;
2242 logerrx("%s: IA Prefix pltime %"PRIu32
2243 " > vltime %"PRIu32,
2244 ifp->name, pdp.pltime, pdp.vltime);
2245 continue;
2248 o += sizeof(pdp);
2249 ol = (uint16_t)(ol - sizeof(pdp));
2251 /* pdp.prefix is not aligned so copy it out. */
2252 memcpy(&pdp_prefix, &pdp.prefix, sizeof(pdp_prefix));
2253 TAILQ_FOREACH(a, &state->addrs, next) {
2254 if (IN6_ARE_ADDR_EQUAL(&a->prefix, &pdp_prefix))
2255 break;
2258 if (a == NULL) {
2259 a = ipv6_newaddr(ifp, &pdp_prefix, pdp.prefix_len,
2260 IPV6_AF_DELEGATEDPFX);
2261 if (a == NULL)
2262 break;
2263 a->created = *acquired;
2264 a->dadcallback = dhcp6_dadcallback;
2265 a->ia_type = D6_OPTION_IA_PD;
2266 memcpy(a->iaid, iaid, sizeof(a->iaid));
2267 TAILQ_INSERT_TAIL(&state->addrs, a, next);
2268 } else {
2269 if (!(a->flags & IPV6_AF_DELEGATEDPFX))
2270 a->flags |= IPV6_AF_NEW | IPV6_AF_DELEGATEDPFX;
2271 a->flags &= ~(IPV6_AF_STALE |
2272 IPV6_AF_EXTENDED |
2273 IPV6_AF_REQUEST);
2274 if (a->prefix_vltime != pdp.vltime)
2275 a->flags |= IPV6_AF_NEW;
2278 a->acquired = *acquired;
2279 a->prefix_pltime = pdp.pltime;
2280 a->prefix_vltime = pdp.vltime;
2282 if (a->prefix_pltime && a->prefix_pltime < state->lowpl)
2283 state->lowpl = a->prefix_pltime;
2284 if (a->prefix_vltime && a->prefix_vltime > state->expire)
2285 state->expire = a->prefix_vltime;
2286 i++;
2288 a->prefix_exclude_len = 0;
2289 memset(&a->prefix_exclude, 0, sizeof(a->prefix_exclude));
2290 o = dhcp6_findoption(o, ol, D6_OPTION_PD_EXCLUDE, &ol);
2291 if (o == NULL)
2292 continue;
2294 /* RFC 6603 4.2 says option length MUST be between 2 and 17.
2295 * This allows 1 octet for prefix length and 16 for the
2296 * subnet ID. */
2297 if (ol < 2 || ol > 17) {
2298 logerrx("%s: invalid PD Exclude option", ifp->name);
2299 continue;
2302 /* RFC 6603 4.2 says prefix length MUST be between the
2303 * length of the IAPREFIX prefix length + 1 and 128. */
2304 if (*o < a->prefix_len + 1 || *o > 128) {
2305 logerrx("%s: invalid PD Exclude length", ifp->name);
2306 continue;
2309 ol--;
2310 /* Check option length matches prefix length. */
2311 if (((*o - a->prefix_len - 1) / NBBY) + 1 != ol) {
2312 logerrx("%s: PD Exclude length mismatch", ifp->name);
2313 continue;
2315 a->prefix_exclude_len = *o++;
2317 memcpy(&a->prefix_exclude, &a->prefix,
2318 sizeof(a->prefix_exclude));
2319 nb = a->prefix_len % NBBY;
2320 if (nb)
2321 ol--;
2322 pw = a->prefix_exclude.s6_addr +
2323 (a->prefix_exclude_len / NBBY) - 1;
2324 while (ol-- > 0)
2325 *pw-- = *o++;
2326 if (nb)
2327 *pw = (uint8_t)(*pw | (*o >> nb));
2329 return i;
2331 #endif
2333 static int
2334 dhcp6_findia(struct interface *ifp, struct dhcp6_message *m, size_t l,
2335 const char *sfrom, const struct timespec *acquired)
2337 struct dhcp6_state *state;
2338 const struct if_options *ifo;
2339 struct dhcp6_option o;
2340 uint8_t *d, *p;
2341 struct dhcp6_ia_na ia;
2342 int i, e, error;
2343 size_t j;
2344 uint16_t nl;
2345 uint8_t iaid[4];
2346 char buf[sizeof(iaid) * 3];
2347 struct ipv6_addr *ap;
2348 struct if_ia *ifia;
2350 if (l < sizeof(*m)) {
2351 /* Should be impossible with guards at packet in
2352 * and reading leases */
2353 errno = EINVAL;
2354 return -1;
2357 ifo = ifp->options;
2358 i = e = 0;
2359 state = D6_STATE(ifp);
2360 TAILQ_FOREACH(ap, &state->addrs, next) {
2361 if (!(ap->flags & IPV6_AF_DELEGATED))
2362 ap->flags |= IPV6_AF_STALE;
2365 d = (uint8_t *)m + sizeof(*m);
2366 l -= sizeof(*m);
2367 while (l > sizeof(o)) {
2368 memcpy(&o, d, sizeof(o));
2369 o.len = ntohs(o.len);
2370 if (o.len > l || sizeof(o) + o.len > l) {
2371 errno = EINVAL;
2372 logerrx("%s: option overflow", ifp->name);
2373 break;
2375 p = d + sizeof(o);
2376 d = p + o.len;
2377 l -= sizeof(o) + o.len;
2379 o.code = ntohs(o.code);
2380 switch(o.code) {
2381 case D6_OPTION_IA_TA:
2382 nl = 4;
2383 break;
2384 case D6_OPTION_IA_NA:
2385 case D6_OPTION_IA_PD:
2386 nl = 12;
2387 break;
2388 default:
2389 continue;
2391 if (o.len < nl) {
2392 errno = EINVAL;
2393 logerrx("%s: IA option truncated", ifp->name);
2394 continue;
2397 memcpy(&ia, p, nl);
2398 p += nl;
2399 o.len = (uint16_t)(o.len - nl);
2401 for (j = 0; j < ifo->ia_len; j++) {
2402 ifia = &ifo->ia[j];
2403 if (ifia->ia_type == o.code &&
2404 memcmp(ifia->iaid, ia.iaid, sizeof(ia.iaid)) == 0)
2405 break;
2407 if (j == ifo->ia_len &&
2408 !(ifo->ia_len == 0 && ifp->ctx->options & DHCPCD_DUMPLEASE))
2410 logdebugx("%s: ignoring unrequested IAID %s",
2411 ifp->name,
2412 hwaddr_ntoa(ia.iaid, sizeof(ia.iaid),
2413 buf, sizeof(buf)));
2414 continue;
2417 if (o.code != D6_OPTION_IA_TA) {
2418 ia.t1 = ntohl(ia.t1);
2419 ia.t2 = ntohl(ia.t2);
2420 /* RFC 3315 22.4 */
2421 if (ia.t2 > 0 && ia.t1 > ia.t2) {
2422 logwarnx("%s: IAID %s T1(%d) > T2(%d) from %s",
2423 ifp->name,
2424 hwaddr_ntoa(iaid, sizeof(iaid), buf,
2425 sizeof(buf)),
2426 ia.t1, ia.t2, sfrom);
2427 continue;
2429 } else
2430 ia.t1 = ia.t2 = 0; /* appease gcc */
2431 if ((error = dhcp6_checkstatusok(ifp, NULL, p, o.len)) != 0) {
2432 if (error == D6_STATUS_NOBINDING)
2433 state->has_no_binding = true;
2434 e = 1;
2435 continue;
2437 if (o.code == D6_OPTION_IA_PD) {
2438 #ifndef SMALL
2439 if (dhcp6_findpd(ifp, ia.iaid, p, o.len,
2440 acquired) == 0)
2442 logwarnx("%s: %s: DHCPv6 REPLY missing Prefix",
2443 ifp->name, sfrom);
2444 continue;
2446 #endif
2447 } else {
2448 if (dhcp6_findna(ifp, o.code, ia.iaid, p, o.len,
2449 acquired) == 0)
2451 logwarnx("%s: %s: DHCPv6 REPLY missing "
2452 "IA Address",
2453 ifp->name, sfrom);
2454 continue;
2457 if (o.code != D6_OPTION_IA_TA) {
2458 if (ia.t1 != 0 &&
2459 (ia.t1 < state->renew || state->renew == 0))
2460 state->renew = ia.t1;
2461 if (ia.t2 != 0 &&
2462 (ia.t2 < state->rebind || state->rebind == 0))
2463 state->rebind = ia.t2;
2465 i++;
2468 if (i == 0 && e)
2469 return -1;
2470 return i;
2473 #ifndef SMALL
2474 static void
2475 dhcp6_deprecatedele(struct ipv6_addr *ia)
2477 struct ipv6_addr *da, *dan, *dda;
2478 struct timespec now;
2479 struct dhcp6_state *state;
2481 timespecclear(&now);
2482 TAILQ_FOREACH_SAFE(da, &ia->pd_pfxs, pd_next, dan) {
2483 if (ia->prefix_vltime == 0) {
2484 if (da->prefix_vltime != 0)
2485 da->prefix_vltime = 0;
2486 else
2487 continue;
2488 } else if (da->prefix_pltime != 0)
2489 da->prefix_pltime = 0;
2490 else
2491 continue;
2493 if (ipv6_doaddr(da, &now) != -1)
2494 continue;
2496 /* Delegation deleted, forget it. */
2497 TAILQ_REMOVE(&ia->pd_pfxs, da, pd_next);
2499 /* Delete it from the interface. */
2500 state = D6_STATE(da->iface);
2501 TAILQ_FOREACH(dda, &state->addrs, next) {
2502 if (IN6_ARE_ADDR_EQUAL(&dda->addr, &da->addr))
2503 break;
2505 if (dda != NULL) {
2506 TAILQ_REMOVE(&state->addrs, dda, next);
2507 ipv6_freeaddr(dda);
2511 #endif
2513 static void
2514 dhcp6_deprecateaddrs(struct ipv6_addrhead *addrs)
2516 struct ipv6_addr *ia, *ian;
2518 TAILQ_FOREACH_SAFE(ia, addrs, next, ian) {
2519 if (ia->flags & IPV6_AF_EXTENDED)
2521 else if (ia->flags & IPV6_AF_STALE) {
2522 if (ia->prefix_vltime != 0)
2523 logdebugx("%s: %s: became stale",
2524 ia->iface->name, ia->saddr);
2525 /* Technically this violates RFC 8415 18.2.10.1,
2526 * but we need a mechanism to tell the kernel to
2527 * try and prefer other addresses. */
2528 ia->prefix_pltime = 0;
2529 } else if (ia->prefix_vltime == 0)
2530 loginfox("%s: %s: no valid lifetime",
2531 ia->iface->name, ia->saddr);
2532 else
2533 continue;
2535 #ifndef SMALL
2536 /* If we delegated from this prefix, deprecate or remove
2537 * the delegations. */
2538 if (ia->flags & IPV6_AF_DELEGATEDPFX)
2539 dhcp6_deprecatedele(ia);
2540 #endif
2542 if (ia->flags & IPV6_AF_REQUEST) {
2543 ia->prefix_vltime = ia->prefix_pltime = 0;
2544 eloop_q_timeout_delete(ia->iface->ctx->eloop,
2545 ELOOP_QUEUE_ALL, NULL, ia);
2546 continue;
2548 TAILQ_REMOVE(addrs, ia, next);
2549 if (ia->flags & IPV6_AF_EXTENDED)
2550 ipv6_deleteaddr(ia);
2551 ipv6_freeaddr(ia);
2555 static int
2556 dhcp6_validatelease(struct interface *ifp,
2557 struct dhcp6_message *m, size_t len,
2558 const char *sfrom, const struct timespec *acquired)
2560 struct dhcp6_state *state;
2561 int nia, ok_errno;
2562 struct timespec aq;
2564 if (len <= sizeof(*m)) {
2565 logerrx("%s: DHCPv6 lease truncated", ifp->name);
2566 return -1;
2569 state = D6_STATE(ifp);
2570 errno = 0;
2571 if (dhcp6_checkstatusok(ifp, m, NULL, len) != 0)
2572 return -1;
2573 ok_errno = errno;
2575 state->renew = state->rebind = state->expire = 0;
2576 state->lowpl = ND6_INFINITE_LIFETIME;
2577 if (!acquired) {
2578 clock_gettime(CLOCK_MONOTONIC, &aq);
2579 acquired = &aq;
2581 state->has_no_binding = false;
2582 nia = dhcp6_findia(ifp, m, len, sfrom, acquired);
2583 if (nia == 0) {
2584 if (state->state != DH6S_CONFIRM && ok_errno != 0) {
2585 logerrx("%s: no useable IA found in lease", ifp->name);
2586 return -1;
2589 /* We are confirming and have an OK,
2590 * so look for ia's in our old lease.
2591 * IA's must have existed here otherwise we would
2592 * have rejected it earlier. */
2593 assert(state->new != NULL && state->new_len != 0);
2594 state->has_no_binding = false;
2595 nia = dhcp6_findia(ifp, state->new, state->new_len,
2596 sfrom, acquired);
2598 return nia;
2601 static ssize_t
2602 dhcp6_readlease(struct interface *ifp, int validate)
2604 union {
2605 struct dhcp6_message dhcp6;
2606 uint8_t buf[UDPLEN_MAX];
2607 } buf;
2608 struct dhcp6_state *state;
2609 ssize_t bytes;
2610 int fd;
2611 time_t mtime, now;
2612 #ifdef AUTH
2613 uint8_t *o;
2614 uint16_t ol;
2615 #endif
2617 state = D6_STATE(ifp);
2618 if (state->leasefile[0] == '\0') {
2619 logdebugx("reading standard input");
2620 bytes = read(fileno(stdin), buf.buf, sizeof(buf.buf));
2621 } else {
2622 logdebugx("%s: reading lease: %s",
2623 ifp->name, state->leasefile);
2624 bytes = dhcp_readfile(ifp->ctx, state->leasefile,
2625 buf.buf, sizeof(buf.buf));
2627 if (bytes == -1)
2628 goto ex;
2630 if (ifp->ctx->options & DHCPCD_DUMPLEASE || state->leasefile[0] == '\0')
2631 goto out;
2633 if (bytes == 0)
2634 goto ex;
2636 /* If not validating IA's and if they have expired,
2637 * skip to the auth check. */
2638 if (!validate)
2639 goto auth;
2641 if (dhcp_filemtime(ifp->ctx, state->leasefile, &mtime) == -1)
2642 goto ex;
2643 clock_gettime(CLOCK_MONOTONIC, &state->acquired);
2644 if ((now = time(NULL)) == -1)
2645 goto ex;
2646 state->acquired.tv_sec -= now - mtime;
2648 /* Check to see if the lease is still valid */
2649 fd = dhcp6_validatelease(ifp, &buf.dhcp6, (size_t)bytes, NULL,
2650 &state->acquired);
2651 if (fd == -1)
2652 goto ex;
2654 if (state->expire != ND6_INFINITE_LIFETIME &&
2655 (time_t)state->expire < now - mtime &&
2656 !(ifp->options->options & DHCPCD_LASTLEASE_EXTEND))
2658 logdebugx("%s: discarding expired lease", ifp->name);
2659 bytes = 0;
2660 goto ex;
2663 auth:
2664 #ifdef AUTH
2665 /* Authenticate the message */
2666 o = dhcp6_findmoption(&buf.dhcp6, (size_t)bytes, D6_OPTION_AUTH, &ol);
2667 if (o) {
2668 if (dhcp_auth_validate(&state->auth, &ifp->options->auth,
2669 buf.buf, (size_t)bytes, 6, buf.dhcp6.type, o, ol) == NULL)
2671 logerr("%s: authentication failed", ifp->name);
2672 bytes = 0;
2673 goto ex;
2675 if (state->auth.token)
2676 logdebugx("%s: validated using 0x%08" PRIu32,
2677 ifp->name, state->auth.token->secretid);
2678 else
2679 loginfox("%s: accepted reconfigure key", ifp->name);
2680 } else if ((ifp->options->auth.options & DHCPCD_AUTH_SENDREQUIRE) ==
2681 DHCPCD_AUTH_SENDREQUIRE)
2683 logerrx("%s: authentication now required", ifp->name);
2684 goto ex;
2686 #endif
2688 out:
2689 free(state->new);
2690 state->new = malloc((size_t)bytes);
2691 if (state->new == NULL) {
2692 logerr(__func__);
2693 goto ex;
2696 memcpy(state->new, buf.buf, (size_t)bytes);
2697 state->new_len = (size_t)bytes;
2698 return bytes;
2701 dhcp6_freedrop_addrs(ifp, 0, NULL);
2702 dhcp_unlink(ifp->ctx, state->leasefile);
2703 free(state->new);
2704 state->new = NULL;
2705 state->new_len = 0;
2706 dhcp6_addrequestedaddrs(ifp);
2707 return bytes == 0 ? 0 : -1;
2710 static void
2711 dhcp6_startinit(struct interface *ifp)
2713 struct dhcp6_state *state;
2714 ssize_t r;
2715 uint8_t has_ta, has_non_ta;
2716 size_t i;
2718 state = D6_STATE(ifp);
2719 state->state = DH6S_INIT;
2720 state->expire = ND6_INFINITE_LIFETIME;
2721 state->lowpl = ND6_INFINITE_LIFETIME;
2723 dhcp6_addrequestedaddrs(ifp);
2724 has_ta = has_non_ta = 0;
2725 for (i = 0; i < ifp->options->ia_len; i++) {
2726 switch (ifp->options->ia[i].ia_type) {
2727 case D6_OPTION_IA_TA:
2728 has_ta = 1;
2729 break;
2730 default:
2731 has_non_ta = 1;
2735 if (!(ifp->ctx->options & DHCPCD_TEST) &&
2736 !(has_ta && !has_non_ta) &&
2737 ifp->options->reboot != 0)
2739 r = dhcp6_readlease(ifp, 1);
2740 if (r == -1) {
2741 if (errno != ENOENT && errno != ESRCH)
2742 logerr("%s: %s", __func__, state->leasefile);
2743 } else if (r != 0 &&
2744 !(ifp->options->options & DHCPCD_ANONYMOUS))
2746 /* RFC 3633 section 12.1 */
2747 #ifndef SMALL
2748 if (dhcp6_hasprefixdelegation(ifp))
2749 dhcp6_startrebind(ifp);
2750 else
2751 #endif
2752 dhcp6_startconfirm(ifp);
2753 return;
2756 dhcp6_startdiscoinform(ifp);
2759 #ifndef SMALL
2760 static struct ipv6_addr *
2761 dhcp6_ifdelegateaddr(struct interface *ifp, struct ipv6_addr *prefix,
2762 const struct if_sla *sla, struct if_ia *if_ia)
2764 struct dhcp6_state *state;
2765 struct in6_addr addr, daddr;
2766 struct ipv6_addr *ia;
2767 int pfxlen, dadcounter;
2768 uint64_t vl;
2770 /* RFC6603 Section 4.2 */
2771 if (strcmp(ifp->name, prefix->iface->name) == 0) {
2772 if (prefix->prefix_exclude_len == 0) {
2773 /* Don't spam the log automatically */
2774 if (sla != NULL)
2775 logwarnx("%s: DHCPv6 server does not support "
2776 "OPTION_PD_EXCLUDE",
2777 ifp->name);
2778 return NULL;
2780 pfxlen = prefix->prefix_exclude_len;
2781 memcpy(&addr, &prefix->prefix_exclude, sizeof(addr));
2782 } else if ((pfxlen = dhcp6_delegateaddr(&addr, ifp, prefix,
2783 sla, if_ia)) == -1)
2784 return NULL;
2786 if (sla != NULL && fls64(sla->suffix) > 128 - pfxlen) {
2787 logerrx("%s: suffix %" PRIu64 " + prefix_len %d > 128",
2788 ifp->name, sla->suffix, pfxlen);
2789 return NULL;
2792 /* Add our suffix */
2793 if (sla != NULL && sla->suffix != 0) {
2794 daddr = addr;
2795 vl = be64dec(addr.s6_addr + 8);
2796 vl |= sla->suffix;
2797 be64enc(daddr.s6_addr + 8, vl);
2798 } else {
2799 dadcounter = ipv6_makeaddr(&daddr, ifp, &addr, pfxlen, 0);
2800 if (dadcounter == -1) {
2801 logerrx("%s: error adding slaac to prefix_len %d",
2802 ifp->name, pfxlen);
2803 return NULL;
2807 /* Find an existing address */
2808 state = D6_STATE(ifp);
2809 TAILQ_FOREACH(ia, &state->addrs, next) {
2810 if (IN6_ARE_ADDR_EQUAL(&ia->addr, &daddr))
2811 break;
2813 if (ia == NULL) {
2814 ia = ipv6_newaddr(ifp, &daddr, (uint8_t)pfxlen, IPV6_AF_ONLINK);
2815 if (ia == NULL)
2816 return NULL;
2817 ia->dadcallback = dhcp6_dadcallback;
2818 memcpy(&ia->iaid, &prefix->iaid, sizeof(ia->iaid));
2819 ia->created = prefix->acquired;
2821 TAILQ_INSERT_TAIL(&state->addrs, ia, next);
2822 TAILQ_INSERT_TAIL(&prefix->pd_pfxs, ia, pd_next);
2824 ia->delegating_prefix = prefix;
2825 ia->prefix = addr;
2826 ia->prefix_len = (uint8_t)pfxlen;
2827 ia->acquired = prefix->acquired;
2828 ia->prefix_pltime = prefix->prefix_pltime;
2829 ia->prefix_vltime = prefix->prefix_vltime;
2831 /* If the prefix length hasn't changed,
2832 * don't install a reject route. */
2833 if (prefix->prefix_len == pfxlen)
2834 prefix->flags |= IPV6_AF_NOREJECT;
2835 else
2836 prefix->flags &= ~IPV6_AF_NOREJECT;
2838 return ia;
2840 #endif
2842 static void
2843 dhcp6_script_try_run(struct interface *ifp, int delegated)
2845 struct dhcp6_state *state;
2846 struct ipv6_addr *ap;
2847 int completed;
2849 state = D6_STATE(ifp);
2850 completed = 1;
2851 /* If all addresses have completed DAD run the script */
2852 TAILQ_FOREACH(ap, &state->addrs, next) {
2853 if (!(ap->flags & IPV6_AF_ADDED))
2854 continue;
2855 if (ap->flags & IPV6_AF_ONLINK) {
2856 if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
2857 ipv6_iffindaddr(ap->iface, &ap->addr,
2858 IN6_IFF_TENTATIVE))
2859 ap->flags |= IPV6_AF_DADCOMPLETED;
2860 if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0
2861 #ifndef SMALL
2862 && ((delegated && ap->delegating_prefix) ||
2863 (!delegated && !ap->delegating_prefix))
2864 #endif
2867 completed = 0;
2868 break;
2872 if (completed) {
2873 script_runreason(ifp, delegated ? "DELEGATED6" : state->reason);
2874 if (!delegated)
2875 dhcpcd_daemonise(ifp->ctx);
2876 } else
2877 logdebugx("%s: waiting for DHCPv6 DAD to complete", ifp->name);
2880 #ifdef SMALL
2881 size_t
2882 dhcp6_find_delegates(__unused struct interface *ifp)
2885 return 0;
2887 #else
2888 static void
2889 dhcp6_delegate_prefix(struct interface *ifp)
2891 struct if_options *ifo;
2892 struct dhcp6_state *state;
2893 struct ipv6_addr *ap;
2894 size_t i, j, k;
2895 struct if_ia *ia;
2896 struct if_sla *sla;
2897 struct interface *ifd;
2898 bool carrier_warned;
2900 ifo = ifp->options;
2901 state = D6_STATE(ifp);
2903 /* Clear the logged flag. */
2904 TAILQ_FOREACH(ap, &state->addrs, next) {
2905 ap->flags &= ~IPV6_AF_DELEGATEDLOG;
2908 TAILQ_FOREACH(ifd, ifp->ctx->ifaces, next) {
2909 if (!ifd->active)
2910 continue;
2911 if (!(ifd->options->options & DHCPCD_CONFIGURE))
2912 continue;
2913 k = 0;
2914 carrier_warned = false;
2915 TAILQ_FOREACH(ap, &state->addrs, next) {
2916 if (!(ap->flags & IPV6_AF_DELEGATEDPFX))
2917 continue;
2918 if (!(ap->flags & IPV6_AF_DELEGATEDLOG)) {
2919 int loglevel;
2921 if (ap->flags & IPV6_AF_NEW)
2922 loglevel = LOG_INFO;
2923 else
2924 loglevel = LOG_DEBUG;
2925 /* We only want to log this the once as we loop
2926 * through many interfaces first. */
2927 ap->flags |= IPV6_AF_DELEGATEDLOG;
2928 logmessage(loglevel, "%s: delegated prefix %s",
2929 ifp->name, ap->saddr);
2930 ap->flags &= ~IPV6_AF_NEW;
2932 for (i = 0; i < ifo->ia_len; i++) {
2933 ia = &ifo->ia[i];
2934 if (ia->ia_type != D6_OPTION_IA_PD)
2935 continue;
2936 if (memcmp(ia->iaid, ap->iaid,
2937 sizeof(ia->iaid)))
2938 continue;
2939 if (ia->sla_len == 0) {
2940 /* no SLA configured, so lets
2941 * automate it */
2942 if (!if_is_link_up(ifd)) {
2943 logdebugx(
2944 "%s: has no carrier, cannot"
2945 " delegate addresses",
2946 ifd->name);
2947 carrier_warned = true;
2948 break;
2950 if (dhcp6_ifdelegateaddr(ifd, ap,
2951 NULL, ia))
2952 k++;
2954 for (j = 0; j < ia->sla_len; j++) {
2955 sla = &ia->sla[j];
2956 if (strcmp(ifd->name, sla->ifname))
2957 continue;
2958 if (!if_is_link_up(ifd)) {
2959 logdebugx(
2960 "%s: has no carrier, cannot"
2961 " delegate addresses",
2962 ifd->name);
2963 carrier_warned = true;
2964 break;
2966 if (dhcp6_ifdelegateaddr(ifd, ap,
2967 sla, ia))
2968 k++;
2970 if (carrier_warned)
2971 break;
2973 if (carrier_warned)
2974 break;
2976 if (k && !carrier_warned) {
2977 struct dhcp6_state *s = D6_STATE(ifd);
2979 ipv6_addaddrs(&s->addrs);
2980 dhcp6_script_try_run(ifd, 1);
2984 /* Now all addresses have been added, rebuild the routing table. */
2985 rt_build(ifp->ctx, AF_INET6);
2988 static void
2989 dhcp6_find_delegates1(void *arg)
2992 dhcp6_find_delegates(arg);
2995 size_t
2996 dhcp6_find_delegates(struct interface *ifp)
2998 struct if_options *ifo;
2999 struct dhcp6_state *state;
3000 struct ipv6_addr *ap;
3001 size_t i, j, k;
3002 struct if_ia *ia;
3003 struct if_sla *sla;
3004 struct interface *ifd;
3006 if (ifp->options != NULL &&
3007 !(ifp->options->options & DHCPCD_CONFIGURE))
3008 return 0;
3010 k = 0;
3011 TAILQ_FOREACH(ifd, ifp->ctx->ifaces, next) {
3012 ifo = ifd->options;
3013 state = D6_STATE(ifd);
3014 if (state == NULL || state->state != DH6S_BOUND)
3015 continue;
3016 TAILQ_FOREACH(ap, &state->addrs, next) {
3017 if (!(ap->flags & IPV6_AF_DELEGATEDPFX))
3018 continue;
3019 for (i = 0; i < ifo->ia_len; i++) {
3020 ia = &ifo->ia[i];
3021 if (ia->ia_type != D6_OPTION_IA_PD)
3022 continue;
3023 if (memcmp(ia->iaid, ap->iaid,
3024 sizeof(ia->iaid)))
3025 continue;
3026 for (j = 0; j < ia->sla_len; j++) {
3027 sla = &ia->sla[j];
3028 if (strcmp(ifp->name, sla->ifname))
3029 continue;
3030 if (ipv6_linklocal(ifp) == NULL) {
3031 logdebugx(
3032 "%s: delaying adding"
3033 " delegated addresses for"
3034 " LL address",
3035 ifp->name);
3036 ipv6_addlinklocalcallback(ifp,
3037 dhcp6_find_delegates1, ifp);
3038 return 1;
3040 if (dhcp6_ifdelegateaddr(ifp, ap,
3041 sla, ia))
3042 k++;
3048 if (k) {
3049 loginfox("%s: adding delegated prefixes", ifp->name);
3050 state = D6_STATE(ifp);
3051 state->state = DH6S_DELEGATED;
3052 ipv6_addaddrs(&state->addrs);
3053 rt_build(ifp->ctx, AF_INET6);
3054 dhcp6_script_try_run(ifp, 1);
3056 return k;
3058 #endif
3060 static void
3061 dhcp6_bind(struct interface *ifp, const char *op, const char *sfrom)
3063 struct dhcp6_state *state = D6_STATE(ifp);
3064 bool timedout = (op == NULL), confirmed;
3065 struct ipv6_addr *ia;
3066 int loglevel;
3067 struct timespec now;
3069 if (state->state == DH6S_RENEW) {
3070 loglevel = LOG_DEBUG;
3071 TAILQ_FOREACH(ia, &state->addrs, next) {
3072 if (ia->flags & IPV6_AF_NEW) {
3073 loglevel = LOG_INFO;
3074 break;
3077 } else if (state->state == DH6S_INFORM)
3078 loglevel = state->new_start ? LOG_INFO : LOG_DEBUG;
3079 else
3080 loglevel = LOG_INFO;
3081 state->new_start = false;
3083 if (!timedout) {
3084 logmessage(loglevel, "%s: %s received from %s",
3085 ifp->name, op, sfrom);
3086 #ifndef SMALL
3087 /* If we delegated from an unconfirmed lease we MUST drop
3088 * them now. Hopefully we have new delegations. */
3089 if (state->reason != NULL &&
3090 strcmp(state->reason, "TIMEOUT6") == 0)
3091 dhcp6_delete_delegates(ifp);
3092 #endif
3093 state->reason = NULL;
3094 } else
3095 state->reason = "TIMEOUT6";
3097 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
3098 clock_gettime(CLOCK_MONOTONIC, &now);
3100 switch(state->state) {
3101 case DH6S_INFORM:
3103 struct dhcp6_option *o;
3104 uint16_t ol;
3106 if (state->reason == NULL)
3107 state->reason = "INFORM6";
3108 o = dhcp6_findmoption(state->new, state->new_len,
3109 D6_OPTION_INFO_REFRESH_TIME, &ol);
3110 if (o == NULL || ol != sizeof(uint32_t))
3111 state->renew = IRT_DEFAULT;
3112 else {
3113 memcpy(&state->renew, o, ol);
3114 state->renew = ntohl(state->renew);
3115 if (state->renew < IRT_MINIMUM)
3116 state->renew = IRT_MINIMUM;
3118 state->rebind = 0;
3119 state->expire = ND6_INFINITE_LIFETIME;
3120 state->lowpl = ND6_INFINITE_LIFETIME;
3122 break;
3124 case DH6S_REQUEST:
3125 if (state->reason == NULL)
3126 state->reason = "BOUND6";
3127 /* FALLTHROUGH */
3128 case DH6S_RENEW:
3129 if (state->reason == NULL)
3130 state->reason = "RENEW6";
3131 /* FALLTHROUGH */
3132 case DH6S_REBIND:
3133 if (state->reason == NULL)
3134 state->reason = "REBIND6";
3135 /* FALLTHROUGH */
3136 case DH6S_CONFIRM:
3137 if (state->reason == NULL)
3138 state->reason = "REBOOT6";
3139 if (state->renew != 0) {
3140 bool all_expired = true;
3142 TAILQ_FOREACH(ia, &state->addrs, next) {
3143 if (ia->flags & IPV6_AF_STALE)
3144 continue;
3145 if (!(state->renew == ND6_INFINITE_LIFETIME
3146 && ia->prefix_vltime == ND6_INFINITE_LIFETIME)
3147 && ia->prefix_vltime != 0
3148 && ia->prefix_vltime <= state->renew)
3149 logwarnx(
3150 "%s: %s will expire before renewal",
3151 ifp->name, ia->saddr);
3152 else
3153 all_expired = false;
3155 if (all_expired) {
3156 /* All address's vltime happens at or before
3157 * the configured T1 in the IA.
3158 * This is a badly configured server and we
3159 * have to use our own notion of what
3160 * T1 and T2 should be as a result.
3162 * Doing this violates RFC 3315 22.4:
3163 * In a message sent by a server to a client,
3164 * the client MUST use the values in the T1
3165 * and T2 fields for the T1 and T2 parameters,
3166 * unless those values in those fields are 0.
3168 logwarnx("%s: ignoring T1 %"PRIu32
3169 " due to address expiry",
3170 ifp->name, state->renew);
3171 state->renew = state->rebind = 0;
3174 if (state->renew == 0 && state->lowpl != ND6_INFINITE_LIFETIME)
3175 state->renew = (uint32_t)(state->lowpl * 0.5);
3176 if (state->rebind == 0 && state->lowpl != ND6_INFINITE_LIFETIME)
3177 state->rebind = (uint32_t)(state->lowpl * 0.8);
3178 break;
3179 default:
3180 state->reason = "UNKNOWN6";
3181 break;
3184 if (state->state != DH6S_CONFIRM && !timedout) {
3185 state->acquired = now;
3186 free(state->old);
3187 state->old = state->new;
3188 state->old_len = state->new_len;
3189 state->new = state->recv;
3190 state->new_len = state->recv_len;
3191 state->recv = NULL;
3192 state->recv_len = 0;
3193 confirmed = false;
3194 } else {
3195 /* Reduce timers based on when we got the lease. */
3196 uint32_t elapsed;
3198 elapsed = (uint32_t)eloop_timespec_diff(&now,
3199 &state->acquired, NULL);
3200 if (state->renew && state->renew != ND6_INFINITE_LIFETIME) {
3201 if (state->renew > elapsed)
3202 state->renew -= elapsed;
3203 else
3204 state->renew = 0;
3206 if (state->rebind && state->rebind != ND6_INFINITE_LIFETIME) {
3207 if (state->rebind > elapsed)
3208 state->rebind -= elapsed;
3209 else
3210 state->rebind = 0;
3212 if (state->expire && state->expire != ND6_INFINITE_LIFETIME) {
3213 if (state->expire > elapsed)
3214 state->expire -= elapsed;
3215 else
3216 state->expire = 0;
3218 confirmed = true;
3221 if (ifp->ctx->options & DHCPCD_TEST)
3222 script_runreason(ifp, "TEST");
3223 else {
3224 if (state->state == DH6S_INFORM)
3225 state->state = DH6S_INFORMED;
3226 else
3227 state->state = DH6S_BOUND;
3228 state->failed = false;
3230 if (state->renew && state->renew != ND6_INFINITE_LIFETIME)
3231 eloop_timeout_add_sec(ifp->ctx->eloop,
3232 state->renew,
3233 state->state == DH6S_INFORMED ?
3234 dhcp6_startinform : dhcp6_startrenew, ifp);
3235 if (state->rebind && state->rebind != ND6_INFINITE_LIFETIME)
3236 eloop_timeout_add_sec(ifp->ctx->eloop,
3237 state->rebind, dhcp6_startrebind, ifp);
3238 if (state->expire != ND6_INFINITE_LIFETIME)
3239 eloop_timeout_add_sec(ifp->ctx->eloop,
3240 state->expire, dhcp6_startexpire, ifp);
3242 if (ifp->options->options & DHCPCD_CONFIGURE) {
3243 ipv6_addaddrs(&state->addrs);
3244 if (!timedout)
3245 dhcp6_deprecateaddrs(&state->addrs);
3248 if (state->state == DH6S_INFORMED)
3249 logmessage(loglevel, "%s: refresh in %"PRIu32" seconds",
3250 ifp->name, state->renew);
3251 else if (state->renew == ND6_INFINITE_LIFETIME)
3252 logmessage(loglevel, "%s: leased for infinity",
3253 ifp->name);
3254 else if (state->renew || state->rebind)
3255 logmessage(loglevel, "%s: renew in %"PRIu32", "
3256 "rebind in %"PRIu32", "
3257 "expire in %"PRIu32" seconds",
3258 ifp->name,
3259 state->renew, state->rebind, state->expire);
3260 else if (state->expire == 0)
3261 logmessage(loglevel, "%s: will expire", ifp->name);
3262 else
3263 logmessage(loglevel, "%s: expire in %"PRIu32" seconds",
3264 ifp->name, state->expire);
3265 rt_build(ifp->ctx, AF_INET6);
3266 if (!confirmed && !timedout) {
3267 logdebugx("%s: writing lease: %s",
3268 ifp->name, state->leasefile);
3269 if (dhcp_writefile(ifp->ctx, state->leasefile, 0640,
3270 state->new, state->new_len) == -1)
3271 logerr("dhcp_writefile: %s",state->leasefile);
3273 #ifndef SMALL
3274 dhcp6_delegate_prefix(ifp);
3275 #endif
3276 dhcp6_script_try_run(ifp, 0);
3279 if (ifp->ctx->options & DHCPCD_TEST ||
3280 (ifp->options->options & DHCPCD_INFORM &&
3281 !(ifp->ctx->options & DHCPCD_MANAGER)))
3283 eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
3287 static void
3288 dhcp6_recvif(struct interface *ifp, const char *sfrom,
3289 struct dhcp6_message *r, size_t len)
3291 struct dhcpcd_ctx *ctx;
3292 size_t i;
3293 const char *op;
3294 struct dhcp6_state *state;
3295 uint8_t *o;
3296 uint16_t ol;
3297 const struct dhcp_opt *opt;
3298 const struct if_options *ifo;
3299 bool valid_op;
3300 #ifdef AUTH
3301 uint8_t *auth;
3302 uint16_t auth_len;
3303 #endif
3305 ctx = ifp->ctx;
3306 state = D6_STATE(ifp);
3307 if (state == NULL || state->send == NULL) {
3308 logdebugx("%s: DHCPv6 reply received but not running",
3309 ifp->name);
3310 return;
3313 /* We're already bound and this message is for another machine */
3314 /* XXX DELEGATED? */
3315 if (r->type != DHCP6_RECONFIGURE &&
3316 (state->state == DH6S_BOUND || state->state == DH6S_INFORMED))
3318 logdebugx("%s: DHCPv6 reply received but already bound",
3319 ifp->name);
3320 return;
3323 if (dhcp6_findmoption(r, len, D6_OPTION_SERVERID, NULL) == NULL) {
3324 logdebugx("%s: no DHCPv6 server ID from %s", ifp->name, sfrom);
3325 return;
3328 ifo = ifp->options;
3329 for (i = 0, opt = ctx->dhcp6_opts;
3330 i < ctx->dhcp6_opts_len;
3331 i++, opt++)
3333 if (has_option_mask(ifo->requiremask6, opt->option) &&
3334 !dhcp6_findmoption(r, len, (uint16_t)opt->option, NULL))
3336 logwarnx("%s: reject DHCPv6 (no option %s) from %s",
3337 ifp->name, opt->var, sfrom);
3338 return;
3340 if (has_option_mask(ifo->rejectmask6, opt->option) &&
3341 dhcp6_findmoption(r, len, (uint16_t)opt->option, NULL))
3343 logwarnx("%s: reject DHCPv6 (option %s) from %s",
3344 ifp->name, opt->var, sfrom);
3345 return;
3349 #ifdef AUTH
3350 /* Authenticate the message */
3351 auth = dhcp6_findmoption(r, len, D6_OPTION_AUTH, &auth_len);
3352 if (auth != NULL) {
3353 if (dhcp_auth_validate(&state->auth, &ifo->auth,
3354 (uint8_t *)r, len, 6, r->type, auth, auth_len) == NULL)
3356 logerr("%s: authentication failed from %s",
3357 ifp->name, sfrom);
3358 return;
3360 if (state->auth.token)
3361 logdebugx("%s: validated using 0x%08" PRIu32,
3362 ifp->name, state->auth.token->secretid);
3363 else
3364 loginfox("%s: accepted reconfigure key", ifp->name);
3365 } else if (ifo->auth.options & DHCPCD_AUTH_SEND) {
3366 if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) {
3367 logerrx("%s: no authentication from %s",
3368 ifp->name, sfrom);
3369 return;
3371 logwarnx("%s: no authentication from %s", ifp->name, sfrom);
3373 #endif
3375 op = dhcp6_get_op(r->type);
3376 valid_op = op != NULL;
3377 switch(r->type) {
3378 case DHCP6_REPLY:
3379 switch(state->state) {
3380 case DH6S_INFORM:
3381 if (dhcp6_checkstatusok(ifp, r, NULL, len) != 0)
3382 return;
3383 break;
3384 case DH6S_CONFIRM:
3385 if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1)
3387 dhcp6_startdiscoinform(ifp);
3388 return;
3390 break;
3391 case DH6S_DISCOVER:
3392 /* Only accept REPLY in DISCOVER for RAPID_COMMIT.
3393 * Normally we get an ADVERTISE for a DISCOVER. */
3394 if (!has_option_mask(ifo->requestmask6,
3395 D6_OPTION_RAPID_COMMIT) ||
3396 !dhcp6_findmoption(r, len, D6_OPTION_RAPID_COMMIT,
3397 NULL))
3399 valid_op = false;
3400 break;
3402 /* Validate lease before setting state to REQUEST. */
3403 /* FALLTHROUGH */
3404 case DH6S_REQUEST: /* FALLTHROUGH */
3405 case DH6S_RENEW: /* FALLTHROUGH */
3406 case DH6S_REBIND:
3407 if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1)
3410 * If we can't use the lease, fallback to
3411 * DISCOVER and try and get a new one.
3413 * This is needed become some servers
3414 * renumber the prefix or address
3415 * and deny the current one before it expires
3416 * rather than sending it back with a zero
3417 * lifetime along with the new prefix or
3418 * address to use.
3419 * This behavior is wrong, but moving to the
3420 * DISCOVER phase works around it.
3422 * The currently held lease is still valid
3423 * until a new one is found.
3425 if (state->state != DH6S_DISCOVER)
3426 dhcp6_startdiscoinform(ifp);
3427 return;
3429 /* RFC8415 18.2.10.1 */
3430 if ((state->state == DH6S_RENEW ||
3431 state->state == DH6S_REBIND) &&
3432 state->has_no_binding)
3434 dhcp6_startrequest(ifp);
3435 return;
3437 if (state->state == DH6S_DISCOVER)
3438 state->state = DH6S_REQUEST;
3439 break;
3440 case DH6S_DECLINE:
3441 /* This isnt really a failure, but an
3442 * acknowledgement of one. */
3443 loginfox("%s: %s acknowledged DECLINE6",
3444 ifp->name, sfrom);
3445 dhcp6_fail(ifp);
3446 return;
3447 default:
3448 valid_op = false;
3449 break;
3451 break;
3452 case DHCP6_ADVERTISE:
3453 if (state->state != DH6S_DISCOVER) {
3454 valid_op = false;
3455 break;
3457 /* RFC7083 */
3458 o = dhcp6_findmoption(r, len, D6_OPTION_SOL_MAX_RT, &ol);
3459 if (o && ol == sizeof(uint32_t)) {
3460 uint32_t max_rt;
3462 memcpy(&max_rt, o, sizeof(max_rt));
3463 max_rt = ntohl(max_rt);
3464 if (max_rt >= 60 && max_rt <= 86400) {
3465 logdebugx("%s: SOL_MAX_RT %llu -> %u",
3466 ifp->name,
3467 (unsigned long long)state->sol_max_rt,
3468 max_rt);
3469 state->sol_max_rt = max_rt;
3470 } else
3471 logerr("%s: invalid SOL_MAX_RT %u",
3472 ifp->name, max_rt);
3474 o = dhcp6_findmoption(r, len, D6_OPTION_INF_MAX_RT, &ol);
3475 if (o && ol == sizeof(uint32_t)) {
3476 uint32_t max_rt;
3478 memcpy(&max_rt, o, sizeof(max_rt));
3479 max_rt = ntohl(max_rt);
3480 if (max_rt >= 60 && max_rt <= 86400) {
3481 logdebugx("%s: INF_MAX_RT %llu -> %u",
3482 ifp->name,
3483 (unsigned long long)state->inf_max_rt,
3484 max_rt);
3485 state->inf_max_rt = max_rt;
3486 } else
3487 logerrx("%s: invalid INF_MAX_RT %u",
3488 ifp->name, max_rt);
3490 if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1)
3491 return;
3492 break;
3493 case DHCP6_RECONFIGURE:
3494 #ifdef AUTH
3495 if (auth == NULL) {
3496 #endif
3497 logerrx("%s: unauthenticated %s from %s",
3498 ifp->name, op, sfrom);
3499 if (ifo->auth.options & DHCPCD_AUTH_REQUIRE)
3500 return;
3501 #ifdef AUTH
3503 loginfox("%s: %s from %s", ifp->name, op, sfrom);
3504 o = dhcp6_findmoption(r, len, D6_OPTION_RECONF_MSG, &ol);
3505 if (o == NULL) {
3506 logerrx("%s: missing Reconfigure Message option",
3507 ifp->name);
3508 return;
3510 if (ol != 1) {
3511 logerrx("%s: missing Reconfigure Message type",
3512 ifp->name);
3513 return;
3515 switch(*o) {
3516 case DHCP6_RENEW:
3517 if (state->state != DH6S_BOUND) {
3518 logerrx("%s: not bound, ignoring %s",
3519 ifp->name, op);
3520 return;
3522 dhcp6_startrenew(ifp);
3523 break;
3524 case DHCP6_INFORMATION_REQ:
3525 if (state->state != DH6S_INFORMED) {
3526 logerrx("%s: not informed, ignoring %s",
3527 ifp->name, op);
3528 return;
3530 eloop_timeout_delete(ifp->ctx->eloop,
3531 dhcp6_sendinform, ifp);
3532 dhcp6_startinform(ifp);
3533 break;
3534 default:
3535 logerr("%s: unsupported %s type %d",
3536 ifp->name, op, *o);
3537 break;
3539 return;
3540 #else
3541 break;
3542 #endif
3543 default:
3544 logerrx("%s: invalid DHCP6 type %s (%d)",
3545 ifp->name, op, r->type);
3546 return;
3548 if (!valid_op) {
3549 logwarnx("%s: invalid state for DHCP6 type %s (%d)",
3550 ifp->name, op, r->type);
3551 return;
3554 if (state->recv_len < (size_t)len) {
3555 free(state->recv);
3556 state->recv = malloc(len);
3557 if (state->recv == NULL) {
3558 logerr(__func__);
3559 return;
3562 memcpy(state->recv, r, len);
3563 state->recv_len = len;
3565 if (r->type == DHCP6_ADVERTISE) {
3566 struct ipv6_addr *ia;
3568 if (state->state == DH6S_REQUEST) /* rapid commit */
3569 goto bind;
3570 TAILQ_FOREACH(ia, &state->addrs, next) {
3571 if (!(ia->flags & (IPV6_AF_STALE | IPV6_AF_REQUEST)))
3572 break;
3574 if (ia == NULL)
3575 ia = TAILQ_FIRST(&state->addrs);
3576 if (ia == NULL)
3577 loginfox("%s: ADV (no address) from %s",
3578 ifp->name, sfrom);
3579 else
3580 loginfox("%s: ADV %s from %s",
3581 ifp->name, ia->saddr, sfrom);
3582 dhcp6_startrequest(ifp);
3583 return;
3586 bind:
3587 dhcp6_bind(ifp, op, sfrom);
3590 void
3591 dhcp6_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg, struct ipv6_addr *ia)
3593 struct sockaddr_in6 *from = msg->msg_name;
3594 size_t len = msg->msg_iov[0].iov_len;
3595 char sfrom[INET6_ADDRSTRLEN];
3596 struct interface *ifp;
3597 struct dhcp6_message *r;
3598 const struct dhcp6_state *state;
3599 uint8_t *o;
3600 uint16_t ol;
3602 inet_ntop(AF_INET6, &from->sin6_addr, sfrom, sizeof(sfrom));
3603 if (len < sizeof(struct dhcp6_message)) {
3604 logerrx("DHCPv6 packet too short from %s", sfrom);
3605 return;
3608 if (ia != NULL)
3609 ifp = ia->iface;
3610 else {
3611 ifp = if_findifpfromcmsg(ctx, msg, NULL);
3612 if (ifp == NULL) {
3613 logerr(__func__);
3614 return;
3618 r = (struct dhcp6_message *)msg->msg_iov[0].iov_base;
3620 uint8_t duid[DUID_LEN], *dp;
3621 size_t duid_len;
3622 o = dhcp6_findmoption(r, len, D6_OPTION_CLIENTID, &ol);
3623 if (ifp->options->options & DHCPCD_ANONYMOUS) {
3624 duid_len = duid_make(duid, ifp, DUID_LL);
3625 dp = duid;
3626 } else {
3627 duid_len = ctx->duid_len;
3628 dp = ctx->duid;
3630 if (o == NULL || ol != duid_len || memcmp(o, dp, ol) != 0) {
3631 logdebugx("%s: incorrect client ID from %s",
3632 ifp->name, sfrom);
3633 return;
3636 if (dhcp6_findmoption(r, len, D6_OPTION_SERVERID, NULL) == NULL) {
3637 logdebugx("%s: no DHCPv6 server ID from %s",
3638 ifp->name, sfrom);
3639 return;
3642 if (r->type == DHCP6_RECONFIGURE) {
3643 if (!IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr)) {
3644 logerrx("%s: RECONFIGURE6 recv from %s, not LL",
3645 ifp->name, sfrom);
3646 return;
3648 goto recvif;
3651 state = D6_CSTATE(ifp);
3652 if (state == NULL ||
3653 r->xid[0] != state->send->xid[0] ||
3654 r->xid[1] != state->send->xid[1] ||
3655 r->xid[2] != state->send->xid[2])
3657 struct interface *ifp1;
3658 const struct dhcp6_state *state1;
3660 /* Find an interface with a matching xid. */
3661 TAILQ_FOREACH(ifp1, ctx->ifaces, next) {
3662 state1 = D6_CSTATE(ifp1);
3663 if (state1 == NULL || state1->send == NULL)
3664 continue;
3665 if (r->xid[0] == state1->send->xid[0] &&
3666 r->xid[1] == state1->send->xid[1] &&
3667 r->xid[2] == state1->send->xid[2])
3668 break;
3671 if (ifp1 == NULL) {
3672 if (state != NULL)
3673 logdebugx("%s: wrong xid 0x%02x%02x%02x"
3674 " (expecting 0x%02x%02x%02x) from %s",
3675 ifp->name,
3676 r->xid[0], r->xid[1], r->xid[2],
3677 state->send->xid[0],
3678 state->send->xid[1],
3679 state->send->xid[2],
3680 sfrom);
3681 return;
3683 logdebugx("%s: redirecting DHCP6 message to %s",
3684 ifp->name, ifp1->name);
3685 ifp = ifp1;
3688 #if 0
3690 * Handy code to inject raw DHCPv6 packets over responses
3691 * from our server.
3692 * This allows me to take a 3rd party wireshark trace and
3693 * replay it in my code.
3695 static int replyn = 0;
3696 char fname[PATH_MAX], tbuf[UDPLEN_MAX];
3697 int fd;
3698 ssize_t tlen;
3699 uint8_t *si1, *si2;
3700 uint16_t si_len1, si_len2;
3702 snprintf(fname, sizeof(fname),
3703 "/tmp/dhcp6.reply%d.raw", replyn++);
3704 fd = open(fname, O_RDONLY, 0);
3705 if (fd == -1) {
3706 logerr("%s: open: %s", __func__, fname);
3707 return;
3709 tlen = read(fd, tbuf, sizeof(tbuf));
3710 if (tlen == -1)
3711 logerr("%s: read: %s", __func__, fname);
3712 close(fd);
3714 /* Copy across ServerID so we can work with our own server. */
3715 si1 = dhcp6_findmoption(r, len, D6_OPTION_SERVERID, &si_len1);
3716 si2 = dhcp6_findmoption(tbuf, (size_t)tlen,
3717 D6_OPTION_SERVERID, &si_len2);
3718 if (si1 != NULL && si2 != NULL && si_len1 == si_len2)
3719 memcpy(si2, si1, si_len2);
3720 r = (struct dhcp6_message *)tbuf;
3721 len = (size_t)tlen;
3722 #endif
3724 recvif:
3725 dhcp6_recvif(ifp, sfrom, r, len);
3728 static void
3729 dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia, unsigned short events)
3731 struct sockaddr_in6 from;
3732 union {
3733 struct dhcp6_message dhcp6;
3734 uint8_t buf[UDPLEN_MAX]; /* Maximum UDP message size */
3735 } iovbuf;
3736 struct iovec iov = {
3737 .iov_base = iovbuf.buf, .iov_len = sizeof(iovbuf.buf),
3739 union {
3740 struct cmsghdr hdr;
3741 uint8_t buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
3742 } cmsgbuf = { .buf = { 0 } };
3743 struct msghdr msg = {
3744 .msg_name = &from, .msg_namelen = sizeof(from),
3745 .msg_iov = &iov, .msg_iovlen = 1,
3746 .msg_control = cmsgbuf.buf, .msg_controllen = sizeof(cmsgbuf.buf),
3748 int s;
3749 ssize_t bytes;
3751 if (events != ELE_READ)
3752 logerrx("%s: unexpected event 0x%04x", __func__, events);
3754 s = ia != NULL ? ia->dhcp6_fd : ctx->dhcp6_rfd;
3755 bytes = recvmsg(s, &msg, 0);
3756 if (bytes == -1) {
3757 logerr(__func__);
3758 return;
3761 iov.iov_len = (size_t)bytes;
3762 dhcp6_recvmsg(ctx, &msg, ia);
3765 static void
3767 dhcp6_recvaddr(void *arg, unsigned short events)
3769 struct ipv6_addr *ia = arg;
3771 dhcp6_recv(ia->iface->ctx, ia, events);
3774 static void
3775 dhcp6_recvctx(void *arg, unsigned short events)
3777 struct dhcpcd_ctx *ctx = arg;
3779 dhcp6_recv(ctx, NULL, events);
3783 dhcp6_openraw(void)
3785 int fd, v;
3787 fd = socket(PF_INET6, SOCK_RAW | SOCK_CXNB, IPPROTO_UDP);
3788 if (fd == -1)
3789 return -1;
3791 v = 1;
3792 if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &v, sizeof(v)) == -1)
3793 goto errexit;
3795 v = offsetof(struct udphdr, uh_sum);
3796 if (setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &v, sizeof(v)) == -1)
3797 goto errexit;
3799 return fd;
3801 errexit:
3802 close(fd);
3803 return -1;
3807 dhcp6_openudp(unsigned int ifindex, struct in6_addr *ia)
3809 struct sockaddr_in6 sa;
3810 int n, s;
3812 s = xsocket(PF_INET6, SOCK_DGRAM | SOCK_CXNB, IPPROTO_UDP);
3813 if (s == -1)
3814 goto errexit;
3816 memset(&sa, 0, sizeof(sa));
3817 sa.sin6_family = AF_INET6;
3818 sa.sin6_port = htons(DHCP6_CLIENT_PORT);
3819 #ifdef BSD
3820 sa.sin6_len = sizeof(sa);
3821 #endif
3823 if (ia != NULL) {
3824 memcpy(&sa.sin6_addr, ia, sizeof(sa.sin6_addr));
3825 ipv6_setscope(&sa, ifindex);
3828 if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) == -1)
3829 goto errexit;
3831 n = 1;
3832 if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &n, sizeof(n)) == -1)
3833 goto errexit;
3835 #ifdef SO_RERROR
3836 n = 1;
3837 if (setsockopt(s, SOL_SOCKET, SO_RERROR, &n, sizeof(n)) == -1)
3838 goto errexit;
3839 #endif
3841 return s;
3843 errexit:
3844 logerr(__func__);
3845 if (s != -1)
3846 close(s);
3847 return -1;
3850 #ifndef SMALL
3851 static void
3852 dhcp6_activateinterfaces(struct interface *ifp)
3854 struct interface *ifd;
3855 size_t i, j;
3856 struct if_ia *ia;
3857 struct if_sla *sla;
3859 for (i = 0; i < ifp->options->ia_len; i++) {
3860 ia = &ifp->options->ia[i];
3861 if (ia->ia_type != D6_OPTION_IA_PD)
3862 continue;
3863 for (j = 0; j < ia->sla_len; j++) {
3864 sla = &ia->sla[j];
3865 ifd = if_find(ifp->ctx->ifaces, sla->ifname);
3866 if (ifd == NULL) {
3867 logwarn("%s: cannot delegate to %s",
3868 ifp->name, sla->ifname);
3869 continue;
3871 if (!ifd->active) {
3872 loginfox("%s: activating for delegation",
3873 sla->ifname);
3874 dhcpcd_activateinterface(ifd,
3875 DHCPCD_IPV6 | DHCPCD_DHCP6);
3880 #endif
3882 static void
3883 dhcp6_start1(void *arg)
3885 struct interface *ifp = arg;
3886 struct dhcpcd_ctx *ctx = ifp->ctx;
3887 struct if_options *ifo = ifp->options;
3888 struct dhcp6_state *state;
3889 size_t i;
3890 const struct dhcp_compat *dhc;
3892 if ((ctx->options & (DHCPCD_MANAGER|DHCPCD_PRIVSEP)) == DHCPCD_MANAGER &&
3893 ctx->dhcp6_rfd == -1)
3895 ctx->dhcp6_rfd = dhcp6_openudp(0, NULL);
3896 if (ctx->dhcp6_rfd == -1) {
3897 logerr(__func__);
3898 return;
3900 if (eloop_event_add(ctx->eloop, ctx->dhcp6_rfd, ELE_READ,
3901 dhcp6_recvctx, ctx) == -1)
3902 logerr("%s: eloop_event_add", __func__);
3905 if (!IN_PRIVSEP(ctx) && ctx->dhcp6_wfd == -1) {
3906 ctx->dhcp6_wfd = dhcp6_openraw();
3907 if (ctx->dhcp6_wfd == -1) {
3908 logerr(__func__);
3909 return;
3913 state = D6_STATE(ifp);
3914 /* If no DHCPv6 options are configured,
3915 match configured DHCPv4 options to DHCPv6 equivalents. */
3916 for (i = 0; i < sizeof(ifo->requestmask6); i++) {
3917 if (ifo->requestmask6[i] != '\0')
3918 break;
3920 if (i == sizeof(ifo->requestmask6)) {
3921 for (dhc = dhcp_compats; dhc->dhcp_opt; dhc++) {
3922 if (DHC_REQ(ifo->requestmask, ifo->nomask, dhc->dhcp_opt))
3923 add_option_mask(ifo->requestmask6,
3924 dhc->dhcp6_opt);
3926 if (ifo->fqdn != FQDN_DISABLE || ifo->options & DHCPCD_HOSTNAME)
3927 add_option_mask(ifo->requestmask6, D6_OPTION_FQDN);
3930 #ifndef SMALL
3931 /* Rapid commit won't work with Prefix Delegation Exclusion */
3932 if (dhcp6_findselfsla(ifp))
3933 del_option_mask(ifo->requestmask6, D6_OPTION_RAPID_COMMIT);
3934 #endif
3936 if (state->state == DH6S_INFORM) {
3937 add_option_mask(ifo->requestmask6, D6_OPTION_INFO_REFRESH_TIME);
3938 dhcp6_startinform(ifp);
3939 } else {
3940 del_option_mask(ifo->requestmask6, D6_OPTION_INFO_REFRESH_TIME);
3941 dhcp6_startinit(ifp);
3944 #ifndef SMALL
3945 dhcp6_activateinterfaces(ifp);
3946 #endif
3950 dhcp6_start(struct interface *ifp, enum DH6S init_state)
3952 struct dhcp6_state *state;
3954 state = D6_STATE(ifp);
3955 if (state != NULL) {
3956 switch (init_state) {
3957 case DH6S_INIT:
3958 goto gogogo;
3959 case DH6S_INFORM:
3960 if (state->state == DH6S_INIT ||
3961 state->state == DH6S_INFORMED ||
3962 (state->state == DH6S_DISCOVER &&
3963 !(ifp->options->options & DHCPCD_IA_FORCED) &&
3964 !ipv6nd_hasradhcp(ifp, true)))
3966 /* We don't want log spam when the RA
3967 * has just adjusted it's prefix times. */
3968 if (state->state != DH6S_INFORMED) {
3969 state->new_start = true;
3970 state->failed = false;
3972 dhcp6_startinform(ifp);
3974 break;
3975 case DH6S_REQUEST:
3976 if (ifp->options->options & DHCPCD_DHCP6 &&
3977 (state->state == DH6S_INIT ||
3978 state->state == DH6S_INFORM ||
3979 state->state == DH6S_INFORMED ||
3980 state->state == DH6S_DELEGATED))
3982 /* Change from stateless to stateful */
3983 init_state = DH6S_INIT;
3984 goto gogogo;
3986 break;
3987 case DH6S_CONFIRM:
3988 init_state = DH6S_INIT;
3989 goto gogogo;
3990 default:
3991 /* Not possible, but sushes some compiler warnings. */
3992 break;
3994 return 0;
3995 } else {
3996 switch (init_state) {
3997 case DH6S_CONFIRM:
3998 /* No DHCPv6 config, no existing state
3999 * so nothing to do. */
4000 return 0;
4001 case DH6S_INFORM:
4002 break;
4003 default:
4004 init_state = DH6S_INIT;
4005 break;
4009 if (!(ifp->options->options & DHCPCD_DHCP6))
4010 return 0;
4012 ifp->if_data[IF_DATA_DHCP6] = calloc(1, sizeof(*state));
4013 state = D6_STATE(ifp);
4014 if (state == NULL)
4015 return -1;
4017 state->sol_max_rt = SOL_MAX_RT;
4018 state->inf_max_rt = INF_MAX_RT;
4019 TAILQ_INIT(&state->addrs);
4021 gogogo:
4022 state->new_start = true;
4023 state->state = init_state;
4024 state->lerror = 0;
4025 state->failed = false;
4026 dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile),
4027 AF_INET6, ifp);
4028 if (ipv6_linklocal(ifp) == NULL) {
4029 logdebugx("%s: delaying DHCPv6 for LL address", ifp->name);
4030 ipv6_addlinklocalcallback(ifp, dhcp6_start1, ifp);
4031 return 0;
4034 dhcp6_start1(ifp);
4035 return 0;
4038 void
4039 dhcp6_reboot(struct interface *ifp)
4041 struct dhcp6_state *state;
4043 state = D6_STATE(ifp);
4044 if (state == NULL)
4045 return;
4047 state->lerror = 0;
4048 switch (state->state) {
4049 case DH6S_BOUND:
4050 dhcp6_startrebind(ifp);
4051 break;
4052 default:
4053 dhcp6_startdiscoinform(ifp);
4054 break;
4058 static void
4059 dhcp6_freedrop(struct interface *ifp, int drop, const char *reason)
4061 struct dhcp6_state *state;
4062 struct dhcpcd_ctx *ctx;
4063 unsigned long long options;
4065 if (ifp->options)
4066 options = ifp->options->options;
4067 else
4068 options = ifp->ctx->options;
4070 if (ifp->ctx->eloop)
4071 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
4073 #ifndef SMALL
4074 /* If we're dropping the lease, drop delegated addresses.
4075 * If, for whatever reason, we don't drop them in the future
4076 * then they should at least be marked as deprecated (pltime 0). */
4077 if (drop && (options & DHCPCD_NODROP) != DHCPCD_NODROP)
4078 dhcp6_delete_delegates(ifp);
4079 #endif
4081 state = D6_STATE(ifp);
4082 if (state) {
4083 /* Failure to send the release may cause this function to
4084 * re-enter */
4085 if (state->state == DH6S_RELEASE) {
4086 dhcp6_finishrelease(ifp);
4087 return;
4090 if (drop && options & DHCPCD_RELEASE &&
4091 state->state != DH6S_DELEGATED)
4093 if (if_is_link_up(ifp) &&
4094 state->state != DH6S_RELEASED &&
4095 state->state != DH6S_INFORMED)
4097 dhcp6_startrelease(ifp);
4098 return;
4100 dhcp_unlink(ifp->ctx, state->leasefile);
4102 #ifdef AUTH
4103 else if (state->auth.reconf != NULL) {
4105 * Drop the lease as the token may only be present
4106 * in the initial reply message and not subsequent
4107 * renewals.
4108 * If dhcpcd is restarted, the token is lost.
4109 * XXX persist this in another file?
4111 dhcp_unlink(ifp->ctx, state->leasefile);
4113 #endif
4115 dhcp6_freedrop_addrs(ifp, drop, NULL);
4116 free(state->old);
4117 state->old = state->new;
4118 state->old_len = state->new_len;
4119 state->new = NULL;
4120 state->new_len = 0;
4121 if (drop && state->old &&
4122 (options & DHCPCD_NODROP) != DHCPCD_NODROP)
4124 if (reason == NULL)
4125 reason = "STOP6";
4126 script_runreason(ifp, reason);
4128 free(state->old);
4129 free(state->send);
4130 free(state->recv);
4131 free(state);
4132 ifp->if_data[IF_DATA_DHCP6] = NULL;
4135 /* If we don't have any more DHCP6 enabled interfaces,
4136 * close the global socket and release resources */
4137 ctx = ifp->ctx;
4138 if (ctx->ifaces) {
4139 TAILQ_FOREACH(ifp, ctx->ifaces, next) {
4140 if (D6_STATE(ifp))
4141 break;
4144 if (ifp == NULL && ctx->dhcp6_rfd != -1) {
4145 eloop_event_delete(ctx->eloop, ctx->dhcp6_rfd);
4146 close(ctx->dhcp6_rfd);
4147 ctx->dhcp6_rfd = -1;
4151 void
4152 dhcp6_drop(struct interface *ifp, const char *reason)
4155 dhcp6_freedrop(ifp, 1, reason);
4158 void
4159 dhcp6_free(struct interface *ifp)
4162 dhcp6_freedrop(ifp, 0, NULL);
4165 void
4166 dhcp6_abort(struct interface *ifp)
4168 struct dhcp6_state *state;
4169 #ifdef ND6_ADVERTISE
4170 struct ipv6_addr *ia;
4171 #endif
4173 eloop_timeout_delete(ifp->ctx->eloop, dhcp6_start1, ifp);
4174 state = D6_STATE(ifp);
4175 if (state == NULL)
4176 return;
4178 #ifdef ND6_ADVERTISE
4179 TAILQ_FOREACH(ia, &state->addrs, next) {
4180 ipv6nd_advertise(ia);
4182 #endif
4184 eloop_timeout_delete(ifp->ctx->eloop, dhcp6_startdiscover, ifp);
4185 eloop_timeout_delete(ifp->ctx->eloop, dhcp6_senddiscover, ifp);
4186 eloop_timeout_delete(ifp->ctx->eloop, dhcp6_startinform, ifp);
4187 eloop_timeout_delete(ifp->ctx->eloop, dhcp6_sendinform, ifp);
4189 switch (state->state) {
4190 case DH6S_DISCOVER: /* FALLTHROUGH */
4191 case DH6S_REQUEST: /* FALLTHROUGH */
4192 case DH6S_INFORM:
4193 state->state = DH6S_INIT;
4194 break;
4195 default:
4196 break;
4200 void
4201 dhcp6_handleifa(int cmd, struct ipv6_addr *ia, pid_t pid)
4203 struct dhcp6_state *state;
4204 struct interface *ifp = ia->iface;
4206 /* If not running in manager mode, listen to this address */
4207 if (cmd == RTM_NEWADDR &&
4208 !(ia->addr_flags & IN6_IFF_NOTUSEABLE) &&
4209 ifp->active == IF_ACTIVE_USER &&
4210 !(ifp->ctx->options & DHCPCD_MANAGER) &&
4211 ifp->options->options & DHCPCD_DHCP6)
4213 #ifdef PRIVSEP
4214 if (IN_PRIVSEP_SE(ifp->ctx)) {
4215 if (ps_inet_opendhcp6(ia) == -1)
4216 logerr(__func__);
4217 } else
4218 #endif
4220 if (ia->dhcp6_fd == -1)
4221 ia->dhcp6_fd = dhcp6_openudp(ia->iface->index,
4222 &ia->addr);
4223 if (ia->dhcp6_fd != -1 &&
4224 eloop_event_add(ia->iface->ctx->eloop,
4225 ia->dhcp6_fd, ELE_READ, dhcp6_recvaddr, ia) == -1)
4226 logerr("%s: eloop_event_add", __func__);
4230 if ((state = D6_STATE(ifp)) != NULL)
4231 ipv6_handleifa_addrs(cmd, &state->addrs, ia, pid);
4234 ssize_t
4235 dhcp6_env(FILE *fp, const char *prefix, const struct interface *ifp,
4236 const struct dhcp6_message *m, size_t len)
4238 const struct if_options *ifo;
4239 struct dhcp_opt *opt, *vo;
4240 const uint8_t *p;
4241 struct dhcp6_option o;
4242 size_t i;
4243 char *pfx;
4244 uint32_t en;
4245 const struct dhcpcd_ctx *ctx;
4246 #ifndef SMALL
4247 const struct dhcp6_state *state;
4248 const struct ipv6_addr *ap;
4249 #endif
4251 if (m == NULL)
4252 goto delegated;
4254 if (len < sizeof(*m)) {
4255 /* Should be impossible with guards at packet in
4256 * and reading leases */
4257 errno = EINVAL;
4258 return -1;
4261 ifo = ifp->options;
4262 ctx = ifp->ctx;
4264 /* Zero our indexes */
4265 for (i = 0, opt = ctx->dhcp6_opts;
4266 i < ctx->dhcp6_opts_len;
4267 i++, opt++)
4268 dhcp_zero_index(opt);
4269 for (i = 0, opt = ifp->options->dhcp6_override;
4270 i < ifp->options->dhcp6_override_len;
4271 i++, opt++)
4272 dhcp_zero_index(opt);
4273 for (i = 0, opt = ctx->vivso;
4274 i < ctx->vivso_len;
4275 i++, opt++)
4276 dhcp_zero_index(opt);
4277 if (asprintf(&pfx, "%s_dhcp6", prefix) == -1)
4278 return -1;
4280 /* Unlike DHCP, DHCPv6 options *may* occur more than once.
4281 * There is also no provision for option concatenation unlike DHCP. */
4282 p = (const uint8_t *)m + sizeof(*m);
4283 len -= sizeof(*m);
4284 for (; len != 0; p += o.len, len -= o.len) {
4285 if (len < sizeof(o)) {
4286 errno = EINVAL;
4287 break;
4289 memcpy(&o, p, sizeof(o));
4290 p += sizeof(o);
4291 len -= sizeof(o);
4292 o.len = ntohs(o.len);
4293 if (len < o.len) {
4294 errno = EINVAL;
4295 break;
4297 o.code = ntohs(o.code);
4298 if (has_option_mask(ifo->nomask6, o.code))
4299 continue;
4300 for (i = 0, opt = ifo->dhcp6_override;
4301 i < ifo->dhcp6_override_len;
4302 i++, opt++)
4303 if (opt->option == o.code)
4304 break;
4305 if (i == ifo->dhcp6_override_len &&
4306 o.code == D6_OPTION_VENDOR_OPTS &&
4307 o.len > sizeof(en))
4309 memcpy(&en, p, sizeof(en));
4310 en = ntohl(en);
4311 vo = vivso_find(en, ifp);
4312 } else
4313 vo = NULL;
4314 if (i == ifo->dhcp6_override_len) {
4315 for (i = 0, opt = ctx->dhcp6_opts;
4316 i < ctx->dhcp6_opts_len;
4317 i++, opt++)
4318 if (opt->option == o.code)
4319 break;
4320 if (i == ctx->dhcp6_opts_len)
4321 opt = NULL;
4323 if (opt) {
4324 dhcp_envoption(ifp->ctx,
4325 fp, pfx, ifp->name,
4326 opt, dhcp6_getoption, p, o.len);
4328 if (vo) {
4329 dhcp_envoption(ifp->ctx,
4330 fp, pfx, ifp->name,
4331 vo, dhcp6_getoption,
4332 p + sizeof(en),
4333 o.len - sizeof(en));
4336 free(pfx);
4338 delegated:
4339 #ifndef SMALL
4340 /* Needed for Delegated Prefixes */
4341 state = D6_CSTATE(ifp);
4342 TAILQ_FOREACH(ap, &state->addrs, next) {
4343 if (ap->delegating_prefix)
4344 break;
4346 if (ap == NULL)
4347 return 1;
4348 if (fprintf(fp, "%s_delegated_dhcp6_prefix=", prefix) == -1)
4349 return -1;
4350 TAILQ_FOREACH(ap, &state->addrs, next) {
4351 if (ap->delegating_prefix == NULL)
4352 continue;
4353 if (ap != TAILQ_FIRST(&state->addrs)) {
4354 if (fputc(' ', fp) == EOF)
4355 return -1;
4357 if (fprintf(fp, "%s", ap->saddr) == -1)
4358 return -1;
4360 if (fputc('\0', fp) == EOF)
4361 return -1;
4362 #endif
4364 return 1;
4366 #endif
4368 #ifndef SMALL
4370 dhcp6_dump(struct interface *ifp)
4372 struct dhcp6_state *state;
4374 ifp->if_data[IF_DATA_DHCP6] = state = calloc(1, sizeof(*state));
4375 if (state == NULL) {
4376 logerr(__func__);
4377 return -1;
4379 TAILQ_INIT(&state->addrs);
4380 if (dhcp6_readlease(ifp, 0) == -1) {
4381 logerr("dhcp6_readlease");
4382 return -1;
4384 state->reason = "DUMP6";
4385 return script_runreason(ifp, state->reason);
4387 #endif