Module Name: src
Committed By: roy
Date: Wed Feb 12 19:23:13 UTC 2025
Modified Files:
src/external/bsd/dhcpcd/dist/src: bpf.c dhcp.c dhcp6.c dhcpcd.c
if-bsd.c if-options.c ipv6.c ipv6.h ipv6nd.c logerr.c privsep.c
script.c
Log Message:
Sync with dhcpcd-10.2.0
To generate a diff of this commit:
cvs rdiff -u -r1.22 -r1.23 src/external/bsd/dhcpcd/dist/src/bpf.c
cvs rdiff -u -r1.51 -r1.52 src/external/bsd/dhcpcd/dist/src/dhcp.c
cvs rdiff -u -r1.34 -r1.35 src/external/bsd/dhcpcd/dist/src/dhcp6.c
cvs rdiff -u -r1.56 -r1.57 src/external/bsd/dhcpcd/dist/src/dhcpcd.c
cvs rdiff -u -r1.31 -r1.32 src/external/bsd/dhcpcd/dist/src/if-bsd.c \
src/external/bsd/dhcpcd/dist/src/ipv6nd.c
cvs rdiff -u -r1.37 -r1.38 src/external/bsd/dhcpcd/dist/src/if-options.c
cvs rdiff -u -r1.19 -r1.20 src/external/bsd/dhcpcd/dist/src/ipv6.c \
src/external/bsd/dhcpcd/dist/src/privsep.c
cvs rdiff -u -r1.14 -r1.15 src/external/bsd/dhcpcd/dist/src/ipv6.h \
src/external/bsd/dhcpcd/dist/src/logerr.c
cvs rdiff -u -r1.17 -r1.18 src/external/bsd/dhcpcd/dist/src/script.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/external/bsd/dhcpcd/dist/src/bpf.c
diff -u src/external/bsd/dhcpcd/dist/src/bpf.c:1.22 src/external/bsd/dhcpcd/dist/src/bpf.c:1.23
--- src/external/bsd/dhcpcd/dist/src/bpf.c:1.22 Mon Dec 18 16:03:26 2023
+++ src/external/bsd/dhcpcd/dist/src/bpf.c Wed Feb 12 19:23:13 2025
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd: BPF arp and bootp filtering
- * Copyright (c) 2006-2023 Roy Marples <[email protected]>
+ * Copyright (c) 2006-2024 Roy Marples <[email protected]>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
Index: src/external/bsd/dhcpcd/dist/src/dhcp.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcp.c:1.51 src/external/bsd/dhcpcd/dist/src/dhcp.c:1.52
--- src/external/bsd/dhcpcd/dist/src/dhcp.c:1.51 Fri May 24 11:30:29 2024
+++ src/external/bsd/dhcpcd/dist/src/dhcp.c Wed Feb 12 19:23:13 2025
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2023 Roy Marples <[email protected]>
+ * Copyright (c) 2006-2024 Roy Marples <[email protected]>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@@ -49,6 +49,7 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
+#include <stdalign.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
@@ -97,6 +98,8 @@
__CTASSERT(sizeof(struct ip) == 20);
__CTASSERT(sizeof(struct udphdr) == 8);
__CTASSERT(sizeof(struct bootp) == 300);
+#define IP_UDP_SIZE sizeof(struct ip) + sizeof(struct udphdr)
+#define BOOTP_MIN_MTU IP_UDP_SIZE + sizeof(struct bootp)
struct dhcp_op {
uint8_t value;
@@ -302,7 +305,7 @@ get_option_uint32(struct dhcpcd_ctx *ctx
uint32_t d;
p = get_option(ctx, bootp, bootp_len, option, &len);
- if (!p || len < (ssize_t)sizeof(d))
+ if (!p || len != (ssize_t)sizeof(d))
return -1;
memcpy(&d, p, sizeof(d));
if (i)
@@ -319,7 +322,7 @@ get_option_uint16(struct dhcpcd_ctx *ctx
uint16_t d;
p = get_option(ctx, bootp, bootp_len, option, &len);
- if (!p || len < (ssize_t)sizeof(d))
+ if (!p || len != (ssize_t)sizeof(d))
return -1;
memcpy(&d, p, sizeof(d));
if (i)
@@ -335,7 +338,7 @@ get_option_uint8(struct dhcpcd_ctx *ctx,
size_t len;
p = get_option(ctx, bootp, bootp_len, option, &len);
- if (!p || len < (ssize_t)sizeof(*p))
+ if (!p || len != (ssize_t)sizeof(*p))
return -1;
if (i)
*i = *(p);
@@ -676,6 +679,8 @@ dhcp_get_mtu(const struct interface *ifp
get_option_uint16(ifp->ctx, &mtu,
state->new, state->new_len, DHO_MTU) == -1)
return 0;
+ if (mtu < IPV4_MMTU)
+ return IPV4_MMTU;
return mtu;
}
@@ -719,6 +724,77 @@ dhcp_message_add_addr(struct bootp *boot
return 0;
}
+#ifndef SMALL
+struct rfc3396_ctx {
+ uint8_t code;
+ uint8_t *len;
+ uint8_t **buf;
+ size_t buflen;
+};
+
+/* Encode data as a DHCP Long Option, RFC 3396. */
+/* NOTE: Wireshark does not decode this correctly
+ * when the option overflows the boundary and another option
+ * is created to hold the resta of the data.
+ * Tested against Wireshark-4.4.1 */
+#define RFC3396_BOUNDARY 255UL
+static ssize_t
+rfc3396_write(struct rfc3396_ctx *ctx, void *data, size_t len)
+{
+ uint8_t *datap = data;
+ size_t wlen, left, r = 0;
+
+ while (len != 0) {
+ if (ctx->len == NULL || *ctx->len == RFC3396_BOUNDARY) {
+ if (ctx->buflen < 2) {
+ errno = ENOMEM;
+ return -1;
+ }
+ *(*ctx->buf)++ = ctx->code;
+ ctx->len = (*ctx->buf)++;
+ *ctx->len = 0;
+ ctx->buflen -= 2;
+ r += 2;
+ }
+
+ wlen = len < RFC3396_BOUNDARY ? len : RFC3396_BOUNDARY;
+ left = RFC3396_BOUNDARY - *ctx->len;
+ if (left < wlen)
+ wlen = left;
+ if (ctx->buflen < wlen) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ memcpy(*ctx->buf, datap, wlen);
+ datap += wlen;
+ *ctx->buf += wlen;
+ ctx->buflen -= wlen;
+ *ctx->len = (uint8_t)(*ctx->len + wlen);
+ len -= wlen;
+ r += wlen;
+ }
+
+ return (ssize_t)r;
+}
+
+static ssize_t
+rfc3396_write_byte(struct rfc3396_ctx *ctx, uint8_t byte)
+{
+
+ return rfc3396_write(ctx, &byte, sizeof(byte));
+}
+
+static uint8_t *
+rfc3396_zero(struct rfc3396_ctx *ctx) {
+ uint8_t *zerop = *ctx->buf, zero = 0;
+
+ if (rfc3396_write(ctx, &zero, sizeof(zero)) == -1)
+ return NULL;
+ return zerop;
+}
+#endif
+
static ssize_t
make_message(struct bootp **bootpm, const struct interface *ifp, uint8_t type)
{
@@ -734,25 +810,29 @@ make_message(struct bootp **bootpm, cons
const struct dhcp_lease *lease = &state->lease;
char hbuf[HOSTNAME_MAX_LEN + 1];
const char *hostname;
- const struct vivco *vivco;
int mtu;
#ifdef AUTH
uint8_t *auth, auth_len;
#endif
- if ((mtu = if_getmtu(ifp)) == -1)
+ /* We could take the DHCPv6 approach and work out the
+ * message length up front rather than this big hammer approach. */
+ if ((mtu = if_getmtu(ifp)) == -1) {
logerr("%s: if_getmtu", ifp->name);
- else if (mtu < MTU_MIN) {
- if (if_setmtu(ifp, MTU_MIN) == -1)
- logerr("%s: if_setmtu", ifp->name);
- mtu = MTU_MIN;
+ return -1;
+ }
+ if ((size_t)mtu < BOOTP_MIN_MTU) {
+ logerr("%s: interface mtu is too small (%d<%zu)",
+ ifp->name, mtu, BOOTP_MIN_MTU);
+ return -1;
}
- if (ifo->options & DHCPCD_BOOTP)
- bootp = calloc(1, sizeof (*bootp));
- else
+ if (ifo->options & DHCPCD_BOOTP) {
+ bootp = calloc(1, sizeof(*bootp));
+ } else {
/* Make the maximal message we could send */
- bootp = calloc(1, (size_t)(mtu - IP_UDP_SIZE));
+ bootp = calloc(1, (size_t)mtu - IP_UDP_SIZE);
+ }
if (bootp == NULL)
return -1;
@@ -774,7 +854,7 @@ make_message(struct bootp **bootpm, cons
}
if (ifo->options & DHCPCD_BROADCAST &&
- bootp->ciaddr == 0 &&
+ bootp->ciaddr == INADDR_ANY &&
type != DHCP_DECLINE &&
type != DHCP_RELEASE)
bootp->flags = htons(BROADCAST_FLAG);
@@ -797,7 +877,7 @@ make_message(struct bootp **bootpm, cons
return sizeof(*bootp);
p = bootp->vend;
- e = (uint8_t *)bootp + (mtu - IP_UDP_SIZE) - 1; /* -1 for DHO_END */
+ e = (uint8_t *)bootp + ((size_t)mtu - IP_UDP_SIZE - 1/* DHO_END */);
ul = htonl(MAGIC_COOKIE);
memcpy(p, &ul, sizeof(ul));
@@ -924,7 +1004,7 @@ make_message(struct bootp **bootpm, cons
AREA_CHECK(2);
*p++ = DHO_MAXMESSAGESIZE;
*p++ = 2;
- sz = htons((uint16_t)(mtu - IP_UDP_SIZE));
+ sz = htons((uint16_t)((size_t)mtu - IP_UDP_SIZE));
memcpy(p, &sz, 2);
p += 2;
}
@@ -1058,33 +1138,77 @@ make_message(struct bootp **bootpm, cons
p += ifo->mudurl[0] + 1;
}
+#ifndef SMALL
if (ifo->vivco_len &&
!has_option_mask(ifo->nomask, DHO_VIVCO))
{
- AREA_CHECK(sizeof(ul));
- *p++ = DHO_VIVCO;
- lp = p++;
- *lp = sizeof(ul);
- ul = htonl(ifo->vivco_en);
- memcpy(p, &ul, sizeof(ul));
- p += sizeof(ul);
- for (i = 0, vivco = ifo->vivco;
- i < ifo->vivco_len;
- i++, vivco++)
- {
- AREA_FIT(vivco->len);
- if (vivco->len + 2 + *lp > 255) {
- logerrx("%s: VIVCO option too big",
- ifp->name);
- free(bootp);
- return -1;
- }
- *p++ = (uint8_t)vivco->len;
- memcpy(p, vivco->data, vivco->len);
- p += vivco->len;
+ struct vivco *vivco = ifo->vivco;
+ size_t vlen = ifo->vivco_len;
+ struct rfc3396_ctx rctx = {
+ .code = DHO_VIVCO,
+ .buf = &p,
+ .buflen = AREA_LEFT,
+ };
+
+ for (; vlen > 0; vivco++, vlen--) {
+ ul = htonl(vivco->en);
+ if (rfc3396_write(&rctx, &ul, sizeof(ul)) == -1)
+ goto toobig;
+ lp = rfc3396_zero(&rctx);
+ if (lp == NULL)
+ goto toobig;
+ if (rfc3396_write_byte(&rctx,
+ (uint8_t)vivco->len) == -1)
+ goto toobig;
+ if (rfc3396_write(&rctx,
+ vivco->data, vivco->len) == -1)
+ goto toobig;
*lp = (uint8_t)(*lp + vivco->len + 1);
}
}
+
+ if (ifo->vsio_len &&
+ !has_option_mask(ifo->nomask, DHO_VIVSO))
+ {
+ struct vsio *vso = ifo->vsio;
+ size_t vlen = ifo->vsio_len;
+ struct vsio_so *so;
+ size_t slen;
+ struct rfc3396_ctx rctx = {
+ .code = DHO_VIVSO,
+ .buf = &p,
+ .buflen = AREA_LEFT,
+ };
+
+ for (; vlen > 0; vso++, vlen--) {
+ if (vso->so_len == 0)
+ continue;
+
+ so = vso->so;
+ slen = vso->so_len;
+
+ ul = htonl(vso->en);
+ if (rfc3396_write(&rctx, &ul, sizeof(ul)) == -1)
+ goto toobig;
+ lp = rfc3396_zero(&rctx);
+ if (lp == NULL)
+ goto toobig;
+
+ for (; slen > 0; so++, slen--) {
+ if (rfc3396_write_byte(&rctx,
+ (uint8_t)so->opt) == -1)
+ goto toobig;
+ if (rfc3396_write_byte(&rctx,
+ (uint8_t)so->len) == -1)
+ goto toobig;
+ if (rfc3396_write(&rctx,
+ so->data, so->len) == -1)
+ goto toobig;
+ *lp = (uint8_t)(*lp + so->len + 2);
+ }
+ }
+ }
+#endif
#ifdef AUTH
if ((ifo->auth.options & DHCPCD_AUTH_SENDREQUIRE) !=
@@ -1409,9 +1533,15 @@ get_lease(struct interface *ifp,
const struct ipv4_addr *ia;
ia = ipv4_iffindaddr(ifp, &lease->addr, NULL);
- assert(ia != NULL);
- lease->mask = ia->mask;
- lease->brd = ia->brd;
+ if (ia == NULL) {
+ lease->mask.s_addr =
+ ipv4_getnetmask(lease->addr.s_addr);
+ lease->brd.s_addr =
+ lease->addr.s_addr | ~lease->mask.s_addr;
+ } else {
+ lease->mask = ia->mask;
+ lease->brd = ia->brd;
+ }
}
} else {
if (get_option_addr(ctx, &lease->mask, bootp, len,
@@ -1645,7 +1775,7 @@ dhcp_makeudppacket(size_t *sz, const uin
ip->ip_p = IPPROTO_UDP;
ip->ip_src.s_addr = source.s_addr;
- if (dest.s_addr == 0)
+ if (dest.s_addr == INADDR_ANY)
ip->ip_dst.s_addr = INADDR_BROADCAST;
else
ip->ip_dst.s_addr = dest.s_addr;
@@ -2233,6 +2363,46 @@ dhcp_arp_found(struct arp_state *astate,
#endif /* ARP */
+static void
+dhcp_bound(struct interface *ifp, uint8_t old_state)
+{
+ struct dhcpcd_ctx *ctx = ifp->ctx;
+ struct dhcp_state *state = D_STATE(ifp);
+
+ /* Close the BPF filter as we can now receive DHCP messages
+ * on a UDP socket. */
+ dhcp_closebpf(ifp);
+
+ /* If not in manager mode, open an address specific socket. */
+ if (ctx->options & DHCPCD_MANAGER ||
+ ifp->options->options & DHCPCD_STATIC ||
+ (state->old != NULL &&
+ state->old->yiaddr == state->new->yiaddr) ||
+ (old_state & STATE_ADDED && !(old_state & STATE_FAKE)))
+ return;
+
+ dhcp_closeinet(ifp);
+#ifdef PRIVSEP
+ if (IN_PRIVSEP_SE(ctx)) {
+ if (ps_inet_openbootp(state->addr) == -1)
+ logerr(__func__);
+ return;
+ }
+#endif
+
+ state->udp_rfd = dhcp_openudp(&state->addr->addr);
+ if (state->udp_rfd == -1) {
+ logerr(__func__);
+ /* We still need to work, so re-open BPF. */
+ dhcp_openbpf(ifp);
+ return;
+ }
+
+ if (eloop_event_add(ctx->eloop, state->udp_rfd, ELE_READ,
+ dhcp_handleifudp, ifp) == -1)
+ logerr("%s: eloop_event_add", __func__);
+}
+
void
dhcp_bind(struct interface *ifp)
{
@@ -2359,7 +2529,18 @@ dhcp_bind(struct interface *ifp)
old_state = state->added;
- if (!(ifo->options & DHCPCD_CONFIGURE)) {
+ if (ifo->options & DHCPCD_CONFIGURE) {
+ /* Add the address */
+ if (ipv4_applyaddr(ifp) == NULL) {
+ /* There was an error adding the address.
+ * If we are in oneshot, exit with a failure. */
+ if (ctx->options & DHCPCD_ONESHOT) {
+ loginfox("exiting due to oneshot");
+ eloop_exit(ctx->eloop, EXIT_FAILURE);
+ }
+ return;
+ }
+ } else {
struct ipv4_addr *ia;
script_runreason(ifp, state->reason);
@@ -2368,61 +2549,13 @@ dhcp_bind(struct interface *ifp)
/* We we are not configuring the address, we need to keep
* the BPF socket open if the address does not exist. */
ia = ipv4_iffindaddr(ifp, &state->lease.addr, NULL);
- if (ia != NULL) {
- state->addr = ia;
- state->added = STATE_ADDED;
- dhcp_closebpf(ifp);
- goto openudp;
- }
- return;
- }
-
- /* Add the address */
- if (ipv4_applyaddr(ifp) == NULL) {
- /* There was an error adding the address.
- * If we are in oneshot, exit with a failure. */
- if (ctx->options & DHCPCD_ONESHOT) {
- loginfox("exiting due to oneshot");
- eloop_exit(ctx->eloop, EXIT_FAILURE);
- }
- return;
+ if (ia == NULL)
+ return;
+ state->addr = ia;
+ state->added = STATE_ADDED;
}
- /* Close the BPF filter as we can now receive DHCP messages
- * on a UDP socket. */
- dhcp_closebpf(ifp);
-
-openudp:
- /* If not in manager mode, open an address specific socket. */
- if (ctx->options & DHCPCD_MANAGER ||
- ifo->options & DHCPCD_STATIC ||
- (state->old != NULL &&
- state->old->yiaddr == state->new->yiaddr &&
- old_state & STATE_ADDED && !(old_state & STATE_FAKE)))
- return;
-
- dhcp_closeinet(ifp);
-#ifdef PRIVSEP
- if (IN_PRIVSEP_SE(ctx)) {
- if (ps_inet_openbootp(state->addr) == -1)
- logerr(__func__);
- return;
- }
-#endif
-
- state->udp_rfd = dhcp_openudp(&state->addr->addr);
- if (state->udp_rfd == -1) {
- logerr(__func__);
- /* Address sharing without manager mode is not supported.
- * It's also possible another DHCP client could be running,
- * which is even worse.
- * We still need to work, so re-open BPF. */
- dhcp_openbpf(ifp);
- return;
- }
- if (eloop_event_add(ctx->eloop, state->udp_rfd, ELE_READ,
- dhcp_handleifudp, ifp) == -1)
- logerr("%s: eloop_event_add", __func__);
+ dhcp_bound(ifp, old_state);
}
static size_t
@@ -2655,43 +2788,11 @@ dhcp_reboot_newopts(struct interface *if
}
}
-#ifdef ARP
-static int
-dhcp_activeaddr(const struct interface *ifp, const struct in_addr *addr)
-{
- const struct interface *ifp1;
- const struct dhcp_state *state;
-
- TAILQ_FOREACH(ifp1, ifp->ctx->ifaces, next) {
- if (ifp1 == ifp)
- continue;
- if ((state = D_CSTATE(ifp1)) == NULL)
- continue;
- switch(state->state) {
- case DHS_REBOOT:
- case DHS_RENEW:
- case DHS_REBIND:
- case DHS_BOUND:
- case DHS_INFORM:
- break;
- default:
- continue;
- }
- if (state->lease.addr.s_addr == addr->s_addr)
- return 1;
- }
- return 0;
-}
-#endif
-
static void
dhcp_reboot(struct interface *ifp)
{
struct if_options *ifo;
struct dhcp_state *state = D_STATE(ifp);
-#ifdef ARP
- struct ipv4_addr *ia;
-#endif
if (state == NULL || state->state == DHS_NONE)
return;
@@ -2723,25 +2824,11 @@ dhcp_reboot(struct interface *ifp)
loginfox("%s: rebinding lease of %s",
ifp->name, inet_ntoa(state->lease.addr));
-#ifdef ARP
-#ifndef KERNEL_RFC5227
+#if defined(ARP) && !defined(KERNEL_RFC5227)
/* Create the DHCP ARP state so we can defend it. */
(void)dhcp_arp_new(ifp, &state->lease.addr);
#endif
- /* If the address exists on the interface and no other interface
- * is currently using it then announce it to ensure this
- * interface gets the reply. */
- ia = ipv4_iffindaddr(ifp, &state->lease.addr, NULL);
- if (ia != NULL &&
- !(ifp->ctx->options & DHCPCD_TEST) &&
-#ifdef IN_IFF_NOTUSEABLE
- !(ia->addr_flags & IN_IFF_NOTUSEABLE) &&
-#endif
- dhcp_activeaddr(ifp, &state->lease.addr) == 0)
- arp_ifannounceaddr(ifp, &state->lease.addr);
-#endif
-
dhcp_new_xid(ifp);
state->lease.server.s_addr = INADDR_ANY;
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
@@ -2769,6 +2856,7 @@ void
dhcp_drop(struct interface *ifp, const char *reason)
{
struct dhcp_state *state = D_STATE(ifp);
+ struct if_options *ifo = ifp->options;
/* dhcp_start may just have been called and we don't yet have a state
* but we do have a timeout, so punt it. */
@@ -2785,9 +2873,7 @@ dhcp_drop(struct interface *ifp, const c
state->arping_index = -1;
#endif
- if (ifp->options->options & DHCPCD_RELEASE &&
- !(ifp->options->options & DHCPCD_INFORM))
- {
+ if (ifo->options & DHCPCD_RELEASE && !(ifo->options & DHCPCD_INFORM)) {
/* Failure to send the release may cause this function to
* re-enter so guard by setting the state. */
if (state->state == DHS_RELEASE)
@@ -2833,7 +2919,7 @@ dhcp_drop(struct interface *ifp, const c
state->new = NULL;
state->new_len = 0;
state->reason = reason;
- if (ifp->options->options & DHCPCD_CONFIGURE)
+ if (ifo->options & DHCPCD_CONFIGURE)
ipv4_applyaddr(ifp);
else {
state->addr = NULL;
@@ -2844,8 +2930,7 @@ dhcp_drop(struct interface *ifp, const c
state->old = NULL;
state->old_len = 0;
state->lease.addr.s_addr = 0;
- ifp->options->options &= ~(DHCPCD_CSR_WARNED |
- DHCPCD_ROUTER_HOST_ROUTE_WARNED);
+ ifo->options &= ~(DHCPCD_CSR_WARNED | DHCPCD_ROUTER_HOST_ROUTE_WARNED);
/* Close DHCP ports so a changed interface family is picked
* up by a new BPF state. */
@@ -2989,7 +3074,7 @@ dhcp_handledhcp(struct interface *ifp, s
char *msg;
bool bootp_copied;
uint32_t v6only_time = 0;
- bool use_v6only = false;
+ bool use_v6only = false, has_auto_conf = false;
#ifdef AUTH
const uint8_t *auth;
size_t auth_len;
@@ -3143,8 +3228,7 @@ dhcp_handledhcp(struct interface *ifp, s
/* Ensure that no reject options are present */
for (i = 1; i < 255; i++) {
if (has_option_mask(ifo->rejectmask, i) &&
- get_option_uint8(ifp->ctx, &tmp,
- bootp, bootp_len, (uint8_t)i) == 0)
+ get_option(ifp->ctx, bootp, bootp_len, (uint8_t)i, NULL))
{
LOGDHCP(LOG_WARNING, "reject DHCP");
return;
@@ -3192,8 +3276,7 @@ dhcp_handledhcp(struct interface *ifp, s
/* Ensure that all required options are present */
for (i = 1; i < 255; i++) {
if (has_option_mask(ifo->requiremask, i) &&
- get_option_uint8(ifp->ctx, &tmp,
- bootp, bootp_len, (uint8_t)i) != 0)
+ !get_option(ifp->ctx, bootp, bootp_len, (uint8_t)i, NULL))
{
/* If we are BOOTP, then ignore the need for serverid.
* To ignore BOOTP, require dhcp_message_type.
@@ -3209,7 +3292,8 @@ dhcp_handledhcp(struct interface *ifp, s
if (has_option_mask(ifo->requestmask, DHO_IPV6_PREFERRED_ONLY)) {
if (get_option_uint32(ifp->ctx, &v6only_time, bootp, bootp_len,
- DHO_IPV6_PREFERRED_ONLY) == 0 && (state->state == DHS_DISCOVER ||
+ DHO_IPV6_PREFERRED_ONLY) == 0 &&
+ (state->state == DHS_DISCOVER ||
state->state == DHS_REBOOT || state->state == DHS_NONE))
{
char v6msg[128];
@@ -3225,8 +3309,8 @@ dhcp_handledhcp(struct interface *ifp, s
}
/* DHCP Auto-Configure, RFC 2563 */
- if (type == DHCP_OFFER && bootp->yiaddr == 0) {
- LOGDHCP(LOG_WARNING, "no address given");
+ if (type == DHCP_OFFER && bootp->yiaddr == INADDR_ANY) {
+ LOGDHCP(LOG_WARNING, "no address offered");
if ((msg = get_option_string(ifp->ctx,
bootp, bootp_len, DHO_MESSAGE)))
{
@@ -3238,6 +3322,7 @@ dhcp_handledhcp(struct interface *ifp, s
get_option_uint8(ifp->ctx, &tmp, bootp, bootp_len,
DHO_AUTOCONFIGURE) == 0)
{
+ has_auto_conf = true;
switch (tmp) {
case 0:
LOGDHCP(LOG_WARNING, "IPv4LL disabled from");
@@ -3256,24 +3341,27 @@ dhcp_handledhcp(struct interface *ifp, s
ifp->name, tmp);
break;
}
- eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
- eloop_timeout_add_sec(ifp->ctx->eloop,
- use_v6only ? v6only_time : DHCP_MAX,
- dhcp_discover, ifp);
}
#endif
- return;
}
if (use_v6only) {
dhcp_drop(ifp, "EXPIRE");
dhcp_unlink(ifp->ctx, state->leasefile);
+ }
+ if (use_v6only || has_auto_conf) {
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
- eloop_timeout_add_sec(ifp->ctx->eloop, v6only_time,
+ eloop_timeout_add_sec(ifp->ctx->eloop,
+ use_v6only ? v6only_time : DHCP_MAX,
dhcp_discover, ifp);
return;
}
+ /* No hints as what to do with no address?
+ * All we can do is continue. */
+ if (type == DHCP_OFFER && bootp->yiaddr == INADDR_ANY)
+ return;
+
/* Ensure that the address offered is valid */
if ((type == 0 || type == DHCP_OFFER || type == DHCP_ACK) &&
(bootp->ciaddr == INADDR_ANY || bootp->ciaddr == INADDR_BROADCAST)
@@ -3471,61 +3559,63 @@ is_packet_udp_bootp(void *packet, size_t
return true;
}
+/* IPv4 pseudo header used for computing TCP and UDP checksums. */
+struct ip_pseudo {
+ struct in_addr ipp_src;
+ struct in_addr ipp_dst;
+ uint8_t ipp_pad; /* must be zero */
+ uint8_t ipp_p;
+ uint16_t ipp_len;
+};
+
/* Lengths have already been checked. */
static bool
-checksums_valid(void *packet,
+checksums_valid(const void *packet,
struct in_addr *from, unsigned int flags)
{
- struct ip *ip = packet;
- union pip {
- struct ip ip;
- uint16_t w[sizeof(struct ip) / 2];
- } pip = {
- .ip = {
- .ip_p = IPPROTO_UDP,
- .ip_src = ip->ip_src,
- .ip_dst = ip->ip_dst,
- }
- };
+ const struct ip *ip = packet;
size_t ip_hlen;
struct udphdr udp;
- char *udpp, *uh_sump;
+ const char *udpp;
uint32_t csum;
+ struct ip_pseudo ip_pseudo;
+ /* We create a buffer to copy ip_pseudo into and send that to
+ * in_cksum() to avoid memory issues. */
+ uint8_t ip_pseudo_buf[sizeof(struct ip_pseudo)];
if (from != NULL)
from->s_addr = ip->ip_src.s_addr;
ip_hlen = (size_t)ip->ip_hl * 4;
+ /* RFC 1071 states that the check of the checksum is equal to 0. */
if (in_cksum(ip, ip_hlen, NULL) != 0)
return false;
if (flags & BPF_PARTIALCSUM)
return true;
- udpp = (char *)ip + ip_hlen;
+ udpp = (const char *)ip + ip_hlen;
memcpy(&udp, udpp, sizeof(udp));
+ /* RFC 768 states that zero means no checksum to verify. */
if (udp.uh_sum == 0)
return true;
/* UDP checksum is based on a pseudo IP header alongside
* the UDP header and payload. */
- pip.ip.ip_len = udp.uh_ulen;
- csum = 0;
-
- /* Need to zero the UDP sum in the packet for the checksum to work. */
- uh_sump = udpp + offsetof(struct udphdr, uh_sum);
- memset(uh_sump, 0, sizeof(udp.uh_sum));
+ ip_pseudo.ipp_src = ip->ip_src;
+ ip_pseudo.ipp_dst = ip->ip_dst;
+ ip_pseudo.ipp_pad = 0;
+ ip_pseudo.ipp_p = ip->ip_p;
+ ip_pseudo.ipp_len = udp.uh_ulen;
+ memcpy(ip_pseudo_buf, &ip_pseudo, sizeof(ip_pseudo_buf));
/* Checksum pseudo header and then UDP + payload. */
- in_cksum(pip.w, sizeof(pip.w), &csum);
+ csum = 0;
+ in_cksum(ip_pseudo_buf, sizeof(ip_pseudo_buf), &csum);
csum = in_cksum(udpp, ntohs(udp.uh_ulen), &csum);
-#if 0 /* Not needed, just here for completeness. */
- /* Put the checksum back. */
- memcpy(uh_sump, &udp.uh_sum, sizeof(udp.uh_sum));
-#endif
-
- return csum == udp.uh_sum;
+ /* RFC 1071 states that the check of the checksum is equal to 0. */
+ return csum == 0;
}
static void
@@ -3626,7 +3716,8 @@ static void
dhcp_readbpf(void *arg, unsigned short events)
{
struct interface *ifp = arg;
- uint8_t buf[FRAMELEN_MAX];
+ /* Sparc64 needs this buffer aligned */
+ alignas(sizeof(struct ip *)) uint8_t buf[FRAMELEN_MAX];
ssize_t bytes;
struct dhcp_state *state = D_STATE(ifp);
struct bpf *bpf = state->bpf;
@@ -4213,13 +4304,8 @@ dhcp_abort(struct interface *ifp)
eloop_timeout_delete(ifp->ctx->eloop, dhcp_start1, ifp);
- if (state != NULL && state->added) {
+ if (state != NULL && state->added)
rt_build(ifp->ctx, AF_INET);
-#ifdef ARP
- if (ifp->options->options & DHCPCD_ARP)
- arp_announceaddr(ifp->ctx, &state->addr->addr);
-#endif
- }
}
struct ipv4_addr *
@@ -4261,18 +4347,15 @@ dhcp_handleifa(int cmd, struct ipv4_addr
ifo = ifp->options;
-#ifdef PRIVSEP
- if (IN_PRIVSEP_SE(ifp->ctx) &&
- !(ifp->ctx->options & (DHCPCD_MANAGER | DHCPCD_CONFIGURE)) &&
+ if (!(ifp->ctx->options & (DHCPCD_MANAGER | DHCPCD_CONFIGURE)) &&
IN_ARE_ADDR_EQUAL(&state->lease.addr, &ia->addr))
{
+ uint8_t old_state = state->added;
+
state->addr = ia;
state->added = STATE_ADDED;
- dhcp_closebpf(ifp);
- if (ps_inet_openbootp(ia) == -1)
- logerr(__func__);
+ dhcp_bound(ifp, old_state);
}
-#endif
/* If we have requested a specific address, return now.
* The below code is only for when inform or static has been
Index: src/external/bsd/dhcpcd/dist/src/dhcp6.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.34 src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.35
--- src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.34 Fri May 24 16:09:09 2024
+++ src/external/bsd/dhcpcd/dist/src/dhcp6.c Wed Feb 12 19:23:13 2025
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2023 Roy Marples <[email protected]>
+ * Copyright (c) 2006-2024 Roy Marples <[email protected]>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@@ -112,8 +112,9 @@ struct dhcp6_ia_addr {
};
__CTASSERT(sizeof(struct dhcp6_ia_addr) == 16 + 8);
-/* XXX FIXME: This is the only packed structure and it does not align.
- * Maybe manually decode it? */
+/* Some compilers do not support packed structures.
+ * We manually decode this. */
+#if 0
struct dhcp6_pd_addr {
uint32_t pltime;
uint32_t vltime;
@@ -121,6 +122,13 @@ struct dhcp6_pd_addr {
struct in6_addr prefix;
} __packed;
__CTASSERT(sizeof(struct dhcp6_pd_addr) == 8 + 1 + 16);
+#endif
+
+#define DHCP6_PD_ADDR_SIZE (8 + 1 + 16)
+#define DHCP6_PD_ADDR_PLTIME 0
+#define DHCP6_PD_ADDR_VLTIME 4
+#define DHCP6_PD_ADDR_PLEN 8
+#define DHCP6_PD_ADDR_PREFIX 9
struct dhcp6_op {
uint16_t type;
@@ -179,6 +187,7 @@ static const char * const dhcp6_statuses
static void dhcp6_bind(struct interface *, const char *, const char *);
static void dhcp6_failinform(void *);
+static void dhcp6_startrebind(void *arg);
static void dhcp6_recvaddr(void *, unsigned short);
static void dhcp6_startdecline(struct interface *);
static void dhcp6_startrequest(struct interface *);
@@ -195,6 +204,11 @@ static int dhcp6_hasprefixdelegation(str
!((ia)->flags & IPV6_AF_STALE) && \
(ia)->prefix_vltime != 0)
+
+/* Gets a pointer to the length part of the option to fill it
+ * in later. */
+#define NEXTLEN(p) ((p) + offsetof(struct dhcp6_option, len))
+
void
dhcp6_printoptions(const struct dhcpcd_ctx *ctx,
const struct dhcp_opt *opts, size_t opts_len)
@@ -262,29 +276,28 @@ dhcp6_makeuser(void *data, const struct
return sizeof(o) + olen;
}
+#ifndef SMALL
+/* DHCPv6 Option 16 (Vendor Class Option) */
static size_t
dhcp6_makevendor(void *data, const struct interface *ifp)
{
const struct if_options *ifo;
- size_t len, vlen, i;
+ size_t len = 0, optlen, vlen, i;
uint8_t *p;
const struct vivco *vivco;
struct dhcp6_option o;
ifo = ifp->options;
- len = sizeof(uint32_t); /* IANA PEN */
- if (ifo->vivco_en) {
- vlen = 0;
+ if (ifo->vivco_len > 0) {
for (i = 0, vivco = ifo->vivco;
i < ifo->vivco_len;
i++, vivco++)
- vlen += sizeof(uint16_t) + vivco->len;
- len += vlen;
+ len += sizeof(o) + sizeof(uint32_t) + sizeof(uint16_t) + vivco->len;
} else if (ifo->vendorclassid[0] != '\0') {
/* dhcpcd owns DHCPCD_IANA_PEN.
* If you need your own string, get your own IANA PEN. */
vlen = strlen(ifp->ctx->vendor);
- len += sizeof(uint16_t) + vlen;
+ len += sizeof(o) + sizeof(uint32_t) + sizeof(uint16_t) + vlen;
} else
return 0;
@@ -298,19 +311,19 @@ dhcp6_makevendor(void *data, const struc
uint16_t hvlen;
p = data;
- o.code = htons(D6_OPTION_VENDOR_CLASS);
- o.len = htons((uint16_t)len);
- memcpy(p, &o, sizeof(o));
- p += sizeof(o);
- pen = htonl(ifo->vivco_en ? ifo->vivco_en : DHCPCD_IANA_PEN);
- memcpy(p, &pen, sizeof(pen));
- p += sizeof(pen);
- if (ifo->vivco_en) {
+ if (ifo->vivco_len > 0) {
for (i = 0, vivco = ifo->vivco;
i < ifo->vivco_len;
- i++, vivco++)
- {
+ i++, vivco++) {
+ optlen = sizeof(uint32_t) + sizeof(uint16_t) + vivco->len;
+ o.code = htons(D6_OPTION_VENDOR_CLASS);
+ o.len = htons((uint16_t)optlen);
+ memcpy(p, &o, sizeof(o));
+ p += sizeof(o);
+ pen = htonl(vivco->en);
+ memcpy(p, &pen, sizeof(pen));
+ p += sizeof(pen);
hvlen = htons((uint16_t)vivco->len);
memcpy(p, &hvlen, sizeof(hvlen));
p += sizeof(hvlen);
@@ -318,15 +331,88 @@ dhcp6_makevendor(void *data, const struc
p += vivco->len;
}
} else if (ifo->vendorclassid[0] != '\0') {
+ o.code = htons(D6_OPTION_VENDOR_CLASS);
+ o.len = htons((uint16_t)len);
+ memcpy(p, &o, sizeof(o));
+ p += sizeof(o);
+ pen = htonl(DHCPCD_IANA_PEN);
+ memcpy(p, &pen, sizeof(pen));
+ p += sizeof(pen);
hvlen = htons((uint16_t)vlen);
memcpy(p, &hvlen, sizeof(hvlen));
p += sizeof(hvlen);
memcpy(p, ifp->ctx->vendor, vlen);
}
}
+ return len;
+}
- return sizeof(o) + len;
+/* DHCPv6 Option 17 (Vendor-Specific Information Option) */
+static size_t
+dhcp6_makevendoropts(void *data, const struct interface *ifp)
+{
+ uint8_t *p = data, *olenp;
+ const struct if_options *ifo = ifp->options;
+ size_t len = 0, olen;
+ const struct vsio *vsio, *vsio_endp = ifo->vsio6 + ifo->vsio6_len;
+ const struct vsio_so *so, *so_endp;
+ struct dhcp6_option o;
+ uint32_t en;
+ uint16_t opt, slen;
+
+ for (vsio = ifo->vsio6; vsio != vsio_endp; ++vsio) {
+ if (vsio->so_len == 0)
+ continue;
+
+ if (p != NULL) {
+ olenp = NEXTLEN(p);
+ o.code = htons(D6_OPTION_VENDOR_OPTS);
+ o.len = 0;
+ memcpy(p, &o, sizeof(o));
+ p += sizeof(o);
+
+ en = htonl(vsio->en);
+ memcpy(p, &en, sizeof(en));
+ p += sizeof(en);
+ } else
+ olenp = NULL;
+
+ olen = sizeof(en);
+
+ so_endp = vsio->so + vsio->so_len;
+ for (so = vsio->so; so != so_endp; so++) {
+ if (olen + sizeof(opt) + sizeof(slen)
+ + so->len > UINT16_MAX)
+ {
+ logerrx("%s: option too big", __func__);
+ break;
+ }
+
+ if (p != NULL) {
+ opt = htons(so->opt);
+ memcpy(p, &opt, sizeof(opt));
+ p += sizeof(opt);
+ slen = htons(so->len);
+ memcpy(p, &slen, sizeof(slen));
+ p += sizeof(slen);
+ memcpy(p, so->data, so->len);
+ p += so->len;
+ }
+
+ olen += sizeof(opt) + sizeof(slen) + so->len;
+ }
+
+ if (olenp != NULL) {
+ slen = htons((uint16_t)olen);
+ memcpy(olenp, &slen, sizeof(slen));
+ }
+
+ len += sizeof(o) + olen;
+ }
+
+ return len;
}
+#endif
static void *
dhcp6_findoption(void *data, size_t data_len, uint16_t code, uint16_t *len)
@@ -793,8 +879,13 @@ dhcp6_makemessage(struct interface *ifp)
if (!has_option_mask(ifo->nomask6, D6_OPTION_USER_CLASS))
len += dhcp6_makeuser(NULL, ifp);
+
+#ifndef SMALL
if (!has_option_mask(ifo->nomask6, D6_OPTION_VENDOR_CLASS))
len += dhcp6_makevendor(NULL, ifp);
+ if (!has_option_mask(ifo->nomask6, D6_OPTION_VENDOR_OPTS))
+ len += dhcp6_makevendoropts(NULL, ifp);
+#endif
/* IA */
m = NULL;
@@ -838,7 +929,7 @@ dhcp6_makemessage(struct interface *ifp)
continue;
if (ap->ia_type == D6_OPTION_IA_PD) {
#ifndef SMALL
- len += sizeof(o) + sizeof(struct dhcp6_pd_addr);
+ len += sizeof(o) + DHCP6_PD_ADDR_SIZE;
if (ap->prefix_exclude_len)
len += sizeof(o) + 1 +
(uint8_t)((ap->prefix_exclude_len -
@@ -941,7 +1032,6 @@ dhcp6_makemessage(struct interface *ifp)
p += (_len); \
} \
} while (0 /* CONSTCOND */)
-#define NEXTLEN (p + offsetof(struct dhcp6_option, len))
/* Options are listed in numerical order as per RFC 7844 Section 4.1
* XXX: They should be randomised. */
@@ -959,7 +1049,7 @@ dhcp6_makemessage(struct interface *ifp)
for (l = 0; IA && l < ifo->ia_len; l++) {
ifia = &ifo->ia[l];
- o_lenp = NEXTLEN;
+ o_lenp = NEXTLEN(p);
/* TA structure is the same as the others,
* it just lacks the T1 and T2 timers.
* These happen to be at the end of the struct,
@@ -989,19 +1079,14 @@ dhcp6_makemessage(struct interface *ifp)
continue;
if (ap->ia_type == D6_OPTION_IA_PD) {
#ifndef SMALL
- struct dhcp6_pd_addr pdp = {
- .prefix_len = ap->prefix_len,
- /*
- * RFC 8415 21.22 states that the
- * valid and preferred lifetimes sent by
- * the client SHOULD be zero and MUST
- * be ignored by the server.
- */
- };
+ uint8_t pdp[DHCP6_PD_ADDR_SIZE];
+
+ memset(pdp, 0, DHCP6_PD_ADDR_PLEN);
+ pdp[DHCP6_PD_ADDR_PLEN] = (uint8_t)ap->prefix_len;
+ memcpy(pdp + DHCP6_PD_ADDR_PREFIX, &ap->prefix,
+ DHCP6_PD_ADDR_SIZE - DHCP6_PD_ADDR_PREFIX);
+ COPYIN(D6_OPTION_IAPREFIX, pdp, sizeof(pdp));
- /* pdp.prefix is not aligned, so copy it in. */
- memcpy(&pdp.prefix, &ap->prefix, sizeof(pdp.prefix));
- COPYIN(D6_OPTION_IAPREFIX, &pdp, sizeof(pdp));
ia_na_len = (uint16_t)
(ia_na_len + sizeof(o) + sizeof(pdp));
@@ -1060,7 +1145,7 @@ dhcp6_makemessage(struct interface *ifp)
state->send->type != DHCP6_DECLINE &&
n_options)
{
- o_lenp = NEXTLEN;
+ o_lenp = NEXTLEN(p);
o.len = 0;
COPYIN1(D6_OPTION_ORO, 0);
for (l = 0, opt = ifp->ctx->dhcp6_opts;
@@ -1118,14 +1203,19 @@ dhcp6_makemessage(struct interface *ifp)
if (!has_option_mask(ifo->nomask6, D6_OPTION_USER_CLASS))
p += dhcp6_makeuser(p, ifp);
+
+#ifndef SMALL
if (!has_option_mask(ifo->nomask6, D6_OPTION_VENDOR_CLASS))
p += dhcp6_makevendor(p, ifp);
+ if (!has_option_mask(ifo->nomask6, D6_OPTION_VENDOR_OPTS))
+ p += dhcp6_makevendoropts(p, ifp);
+#endif
if (state->send->type != DHCP6_RELEASE &&
state->send->type != DHCP6_DECLINE)
{
if (fqdn != FQDN_DISABLE) {
- o_lenp = NEXTLEN;
+ o_lenp = NEXTLEN(p);
COPYIN1(D6_OPTION_FQDN, 0);
if (hl == 0)
*p = D6_FQDN_NONE;
@@ -1187,14 +1277,14 @@ dhcp6_get_op(uint16_t type)
}
static void
-dhcp6_freedrop_addrs(struct interface *ifp, int drop,
+dhcp6_freedrop_addrs(struct interface *ifp, int drop, unsigned int notflags,
const struct interface *ifd)
{
struct dhcp6_state *state;
state = D6_STATE(ifp);
if (state) {
- ipv6_freedrop_addrs(&state->addrs, drop, ifd);
+ ipv6_freedrop_addrs(&state->addrs, drop, notflags, ifd);
if (drop)
rt_build(ifp->ctx, AF_INET6);
}
@@ -1208,7 +1298,7 @@ static void dhcp6_delete_delegates(struc
if (ifp->ctx->ifaces) {
TAILQ_FOREACH(ifp0, ifp->ctx->ifaces, next) {
if (ifp0 != ifp)
- dhcp6_freedrop_addrs(ifp0, 1, ifp);
+ dhcp6_freedrop_addrs(ifp0, 1, 0, ifp);
}
}
}
@@ -1408,7 +1498,7 @@ sent:
state->RT = RT * 2;
if (state->RT < RT) /* Check overflow */
state->RT = RT;
- if (state->MRC == 0 || state->RTC < state->MRC)
+ if (state->MRC == 0 || state->RTC <= state->MRC)
eloop_timeout_add_msec(ctx->eloop,
RT, callback, ifp);
else if (state->MRC != 0 && state->MRCcallback)
@@ -1570,10 +1660,6 @@ dhcp6_dadcallback(void *arg)
if (ia->addr_flags & IN6_IFF_DUPLICATED)
logwarnx("%s: DAD detected %s", ia->iface->name, ia->saddr);
-#ifdef ND6_ADVERTISE
- else
- ipv6nd_advertise(ia);
-#endif
if (completed)
return;
@@ -1656,16 +1742,22 @@ static void
dhcp6_startdiscover(void *arg)
{
struct interface *ifp;
+ struct if_options *ifo;
struct dhcp6_state *state;
int llevel;
struct ipv6_addr *ia;
ifp = arg;
state = D6_STATE(ifp);
+ ifo = ifp->options;
#ifndef SMALL
if (state->reason == NULL || strcmp(state->reason, "TIMEOUT6") != 0)
dhcp6_delete_delegates(ifp);
#endif
+ /* Ensure we never request INFO_REFRESH_TIME,
+ * this only belongs in Information-Request messages */
+ del_option_mask(ifo->requestmask6, D6_OPTION_INFO_REFRESH_TIME);
+
if (state->new == NULL && !state->failed)
llevel = LOG_INFO;
else
@@ -1678,11 +1770,6 @@ dhcp6_startdiscover(void *arg)
state->MRT = state->sol_max_rt;
state->MRC = SOL_MAX_RC;
- eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
- free(state->new);
- state->new = NULL;
- state->new_len = 0;
-
/* If we fail to renew or confirm, our requested addreses will
* be marked as stale.
To re-request them, just mark them as not stale. */
@@ -1703,9 +1790,11 @@ dhcp6_startinform(void *arg)
struct interface *ifp;
struct dhcp6_state *state;
int llevel;
+ struct if_options *ifo;
ifp = arg;
state = D6_STATE(ifp);
+ ifo = ifp->options;
llevel = state->failed ? LOG_DEBUG : LOG_INFO;
logmessage(llevel, "%s: requesting DHCPv6 information", ifp->name);
state->state = DH6S_INFORM;
@@ -1715,7 +1804,9 @@ dhcp6_startinform(void *arg)
state->MRT = state->inf_max_rt;
state->MRC = 0;
- eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+ /* Ensure we always request INFO_REFRESH_TIME as per rfc8415 */
+ add_option_mask(ifo->requestmask6, D6_OPTION_INFO_REFRESH_TIME);
+
if (dhcp6_makemessage(ifp) == -1) {
logerr("%s: %s", __func__, ifp->name);
return;
@@ -1745,41 +1836,15 @@ dhcp6_startdiscoinform(struct interface
}
static void
-dhcp6_leaseextend(struct interface *ifp)
-{
- struct dhcp6_state *state = D6_STATE(ifp);
- struct ipv6_addr *ia;
-
- logwarnx("%s: extending DHCPv6 lease", ifp->name);
- TAILQ_FOREACH(ia, &state->addrs, next) {
- ia->flags |= IPV6_AF_EXTENDED;
- /* Set infinite lifetimes. */
- ia->prefix_pltime = ND6_INFINITE_LIFETIME;
- ia->prefix_vltime = ND6_INFINITE_LIFETIME;
- }
-}
-
-static void
-dhcp6_fail(struct interface *ifp)
+dhcp6_fail(struct interface *ifp, bool drop)
{
struct dhcp6_state *state = D6_STATE(ifp);
state->failed = true;
- /* RFC3315 18.1.2 says that prior addresses SHOULD be used on failure.
- * RFC2131 3.2.3 says that MAY chose to use the prior address.
- * Because dhcpcd was written first for RFC2131, we have the LASTLEASE
- * option which defaults to off as that makes the most sense for
- * mobile clients.
- * dhcpcd also has LASTLEASE_EXTEND to extend this lease past it's
- * expiry, but this is strictly not RFC compliant in any way or form. */
- if (state->new != NULL &&
- ifp->options->options & DHCPCD_LASTLEASE_EXTEND)
- {
- dhcp6_leaseextend(ifp);
- dhcp6_bind(ifp, NULL, NULL);
- } else {
- dhcp6_freedrop_addrs(ifp, 1, NULL);
+ if (drop) {
+ dhcp6_freedrop_addrs(ifp, 1,
+ IPV6_AF_DELEGATED | IPV6_AF_PFXDELEGATION, NULL);
#ifndef SMALL
dhcp6_delete_delegates(ifp);
#endif
@@ -1792,12 +1857,21 @@ dhcp6_fail(struct interface *ifp)
script_runreason(ifp, "EXPIRE6");
dhcp_unlink(ifp->ctx, state->leasefile);
dhcp6_addrequestedaddrs(ifp);
+ eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+ } else if ((state->state == DH6S_CONFIRM || state->state == DH6S_REBIND) &&
+ ifp->options->options & DHCPCD_LASTLEASE) {
+ dhcp6_bind(ifp, NULL, NULL);
+ state->state = DH6S_REBIND;
+ dhcp6_startrebind(ifp);
+ return;
+ } else if (state->new) {
+ script_runreason(ifp, "TIMEOUT6");
+ // We need to keep the expire timeout alive
}
if (!dhcp6_startdiscoinform(ifp)) {
logwarnx("%s: no advertising IPv6 router wants DHCP",ifp->name);
state->state = DH6S_INIT;
- eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
}
}
@@ -1817,7 +1891,10 @@ dhcp6_failconfirm(void *arg)
logmessage(llevel, "%s: failed to confirm prior DHCPv6 address",
ifp->name);
- dhcp6_fail(ifp);
+ eloop_timeout_delete(ifp->ctx->eloop, dhcp6_sendconfirm, ifp);
+
+ /* RFC8415 18.2.3 says that prior addresses SHOULD be used on failure. */
+ dhcp6_fail(ifp, false);
}
static void
@@ -1827,7 +1904,7 @@ dhcp6_failrequest(void *arg)
int llevel = dhcp6_failloglevel(ifp);
logmessage(llevel, "%s: failed to request DHCPv6 address", ifp->name);
- dhcp6_fail(ifp);
+ dhcp6_fail(ifp, true);
}
static void
@@ -1838,17 +1915,21 @@ dhcp6_failinform(void *arg)
logmessage(llevel, "%s: failed to request DHCPv6 information",
ifp->name);
- dhcp6_fail(ifp);
+ dhcp6_fail(ifp, true);
}
#ifndef SMALL
static void
-dhcp6_failrebind(void *arg)
+dhcp6_failrebindpd(void *arg)
{
struct interface *ifp = arg;
logerrx("%s: failed to rebind prior DHCPv6 delegation", ifp->name);
- dhcp6_fail(ifp);
+ eloop_timeout_delete(ifp->ctx->eloop, dhcp6_sendrebind, ifp);
+
+ /* RFC8415 18.2.3 says that prior addresses SHOULD be used on failure.
+ * 18.2 says REBIND rather than CONFIRM with PD but use CONFIRM timings. */
+ dhcp6_fail(ifp, false);
}
static int
@@ -1875,47 +1956,39 @@ dhcp6_startrebind(void *arg)
{
struct interface *ifp;
struct dhcp6_state *state;
-#ifndef SMALL
- int pd;
-#endif
ifp = arg;
eloop_timeout_delete(ifp->ctx->eloop, dhcp6_sendrenew, ifp);
state = D6_STATE(ifp);
+
+ state->IMD = REB_MAX_DELAY;
+ state->IRT = REB_TIMEOUT;
+ state->MRT = REB_MAX_RT;
+ state->RTC = 0;
+ state->MRC = 0;
+
if (state->state == DH6S_RENEW)
logwarnx("%s: failed to renew DHCPv6, rebinding", ifp->name);
- else
+ else {
loginfox("%s: rebinding prior DHCPv6 lease", ifp->name);
- state->state = DH6S_REBIND;
- state->RTC = 0;
- state->MRC = 0;
#ifndef SMALL
- /* RFC 3633 section 12.1 */
- pd = dhcp6_hasprefixdelegation(ifp);
- if (pd) {
- state->IMD = CNF_MAX_DELAY;
- state->IRT = CNF_TIMEOUT;
- state->MRT = CNF_MAX_RT;
- } else
+ /* RFC 8415 18.2.5 */
+ if (dhcp6_hasprefixdelegation(ifp)) {
+ state->IMD = CNF_MAX_DELAY;
+ state->IRT = CNF_TIMEOUT;
+ state->MRT = CNF_MAX_RT;
+ eloop_timeout_add_sec(ifp->ctx->eloop,
+ CNF_MAX_RD, dhcp6_failrebindpd, ifp);
+ }
#endif
- {
- state->IMD = REB_MAX_DELAY;
- state->IRT = REB_TIMEOUT;
- state->MRT = REB_MAX_RT;
}
+ state->state = DH6S_REBIND;
if (dhcp6_makemessage(ifp) == -1)
logerr("%s: %s", __func__, ifp->name);
else
dhcp6_sendrebind(ifp);
-
-#ifndef SMALL
- /* RFC 3633 section 12.1 */
- if (pd)
- eloop_timeout_add_sec(ifp->ctx->eloop,
- CNF_MAX_RD, dhcp6_failrebind, ifp);
-#endif
}
static void
@@ -1984,7 +2057,7 @@ dhcp6_startexpire(void *arg)
eloop_timeout_delete(ifp->ctx->eloop, dhcp6_sendrebind, ifp);
logerrx("%s: DHCPv6 lease expired", ifp->name);
- dhcp6_fail(ifp);
+ dhcp6_fail(ifp, true);
}
static void
@@ -1993,7 +2066,7 @@ dhcp6_faildecline(void *arg)
struct interface *ifp = arg;
logerrx("%s: failed to decline duplicated DHCPv6 addresses", ifp->name);
- dhcp6_fail(ifp);
+ dhcp6_fail(ifp, true);
}
static void
@@ -2129,6 +2202,12 @@ dhcp6_checkstatusok(const struct interfa
state->lerror = code;
errno = 0;
+ /* RFC 8415 18.2.10 */
+ if (code == D6_STATUS_USEMULTICAST) {
+ logdebugx("%s: server sent USEMULTICAST", ifp->name);
+ state->unicast = in6addr_any;
+ }
+
/* code cannot be D6_STATUS_OK, so there is a failure */
if (ifp->ctx->options & DHCPCD_TEST)
eloop_exit(ifp->ctx->eloop, EXIT_FAILURE);
@@ -2255,7 +2334,8 @@ dhcp6_findpd(struct interface *ifp, cons
int i;
uint8_t nb, *pw;
uint16_t ol;
- struct dhcp6_pd_addr pdp;
+ uint32_t pdp_vltime, pdp_pltime;
+ uint8_t pdp_plen;
struct in6_addr pdp_prefix;
i = 0;
@@ -2265,37 +2345,43 @@ dhcp6_findpd(struct interface *ifp, cons
nd = o + ol;
l -= (size_t)(nd - d);
d = nd;
- if (ol < sizeof(pdp)) {
+ if (ol < DHCP6_PD_ADDR_SIZE) {
errno = EINVAL;
logerrx("%s: IA Prefix option truncated", ifp->name);
continue;
}
- memcpy(&pdp, o, sizeof(pdp));
- pdp.pltime = ntohl(pdp.pltime);
- pdp.vltime = ntohl(pdp.vltime);
+ memcpy(&pdp_pltime, o, sizeof(pdp_pltime));
+ o += sizeof(pdp_pltime);
+ memcpy(&pdp_vltime, o, sizeof(pdp_vltime));
+ o += sizeof(pdp_vltime);
+ memcpy(&pdp_plen, o, sizeof(pdp_plen));
+ o += sizeof(pdp_plen);
+
+ pdp_pltime = ntohl(pdp_pltime);
+ pdp_vltime = ntohl(pdp_vltime);
/* RFC 3315 22.6 */
- if (pdp.pltime > pdp.vltime) {
+ if (pdp_pltime > pdp_vltime) {
errno = EINVAL;
logerrx("%s: IA Prefix pltime %"PRIu32
" > vltime %"PRIu32,
- ifp->name, pdp.pltime, pdp.vltime);
+ ifp->name, pdp_pltime, pdp_vltime);
continue;
}
- o += sizeof(pdp);
- ol = (uint16_t)(ol - sizeof(pdp));
+ memcpy(&pdp_prefix, o, sizeof(pdp_prefix));
+ o += sizeof(pdp_prefix);
+ ol = (uint16_t)(ol - sizeof(pdp_pltime) - sizeof(pdp_vltime) -
+ sizeof(pdp_plen) - sizeof(pdp_prefix));
- /* pdp.prefix is not aligned so copy it out. */
- memcpy(&pdp_prefix, &pdp.prefix, sizeof(pdp_prefix));
TAILQ_FOREACH(a, &state->addrs, next) {
if (IN6_ARE_ADDR_EQUAL(&a->prefix, &pdp_prefix))
break;
}
if (a == NULL) {
- a = ipv6_newaddr(ifp, &pdp_prefix, pdp.prefix_len,
- IPV6_AF_DELEGATEDPFX);
+ a = ipv6_newaddr(ifp, &pdp_prefix, pdp_plen,
+ IPV6_AF_PFXDELEGATION);
if (a == NULL)
break;
a->created = *acquired;
@@ -2304,16 +2390,16 @@ dhcp6_findpd(struct interface *ifp, cons
memcpy(a->iaid, iaid, sizeof(a->iaid));
TAILQ_INSERT_TAIL(&state->addrs, a, next);
} else {
- if (!(a->flags & IPV6_AF_DELEGATEDPFX))
- a->flags |= IPV6_AF_NEW | IPV6_AF_DELEGATEDPFX;
+ if (!(a->flags & IPV6_AF_PFXDELEGATION))
+ a->flags |= IPV6_AF_NEW | IPV6_AF_PFXDELEGATION;
a->flags &= ~(IPV6_AF_STALE | IPV6_AF_EXTENDED);
- if (a->prefix_vltime != pdp.vltime)
+ if (a->prefix_vltime != pdp_vltime)
a->flags |= IPV6_AF_NEW;
}
a->acquired = *acquired;
- a->prefix_pltime = pdp.pltime;
- a->prefix_vltime = pdp.vltime;
+ a->prefix_pltime = pdp_pltime;
+ a->prefix_vltime = pdp_vltime;
if (a->prefix_pltime && a->prefix_pltime < state->lowpl)
state->lowpl = a->prefix_pltime;
@@ -2394,6 +2480,8 @@ dhcp6_findia(struct interface *ifp, stru
i = e = 0;
state = D6_STATE(ifp);
TAILQ_FOREACH(ap, &state->addrs, next) {
+ /* Anything not from a lease for this interface should be
+ * marked as stale. */
if (!(ap->flags & IPV6_AF_DELEGATED))
ap->flags |= IPV6_AF_STALE;
}
@@ -2571,7 +2659,7 @@ dhcp6_deprecateaddrs(struct ipv6_addrhea
#ifndef SMALL
/* If we delegated from this prefix, deprecate or remove
* the delegations. */
- if (ia->flags & IPV6_AF_DELEGATEDPFX)
+ if (ia->flags & IPV6_AF_PFXDELEGATION)
dhcp6_deprecatedele(ia);
#endif
@@ -2582,7 +2670,7 @@ dhcp6_deprecateaddrs(struct ipv6_addrhea
continue;
}
TAILQ_REMOVE(addrs, ia, next);
- if (ia->flags & IPV6_AF_EXTENDED)
+ if (!(ia->flags & IPV6_AF_EXTENDED))
ipv6_deleteaddr(ia);
ipv6_freeaddr(ia);
}
@@ -2686,8 +2774,7 @@ dhcp6_readlease(struct interface *ifp, i
}
if (state->expire != ND6_INFINITE_LIFETIME &&
- (time_t)state->expire < now - mtime &&
- !(ifp->options->options & DHCPCD_LASTLEASE_EXTEND))
+ (time_t)state->expire < now - mtime)
{
logdebugx("%s: discarding expired lease", ifp->name);
bytes = 0;
@@ -2732,7 +2819,7 @@ out:
return bytes;
ex:
- dhcp6_freedrop_addrs(ifp, 0, NULL);
+ dhcp6_freedrop_addrs(ifp, 0, IPV6_AF_DELEGATED, NULL);
dhcp_unlink(ifp->ctx, state->leasefile);
free(state->new);
state->new = NULL;
@@ -2745,19 +2832,20 @@ static void
dhcp6_startinit(struct interface *ifp)
{
struct dhcp6_state *state;
+ struct if_options *ifo;
ssize_t r;
uint8_t has_ta, has_non_ta;
size_t i;
state = D6_STATE(ifp);
- state->state = DH6S_INIT;
+ ifo = ifp->options;
state->expire = ND6_INFINITE_LIFETIME;
state->lowpl = ND6_INFINITE_LIFETIME;
dhcp6_addrequestedaddrs(ifp);
has_ta = has_non_ta = 0;
- for (i = 0; i < ifp->options->ia_len; i++) {
- switch (ifp->options->ia[i].ia_type) {
+ for (i = 0; i < ifo->ia_len; i++) {
+ switch (ifo->ia[i].ia_type) {
case D6_OPTION_IA_TA:
has_ta = 1;
break;
@@ -2768,18 +2856,19 @@ dhcp6_startinit(struct interface *ifp)
if (!(ifp->ctx->options & DHCPCD_TEST) &&
!(has_ta && !has_non_ta) &&
- ifp->options->reboot != 0)
+ ifo->reboot != 0)
{
r = dhcp6_readlease(ifp, 1);
if (r == -1) {
if (errno != ENOENT && errno != ESRCH)
logerr("%s: %s", __func__, state->leasefile);
} else if (r != 0 &&
- !(ifp->options->options & DHCPCD_ANONYMOUS))
+ !(ifo->options & DHCPCD_ANONYMOUS))
{
/* RFC 3633 section 12.1 */
#ifndef SMALL
- if (dhcp6_hasprefixdelegation(ifp))
+ if (state->state == DH6S_MANUALREBIND ||
+ dhcp6_hasprefixdelegation(ifp))
dhcp6_startrebind(ifp);
else
#endif
@@ -2947,7 +3036,7 @@ dhcp6_delegate_prefix(struct interface *
k = 0;
carrier_warned = false;
TAILQ_FOREACH(ap, &state->addrs, next) {
- if (!(ap->flags & IPV6_AF_DELEGATEDPFX))
+ if (!(ap->flags & IPV6_AF_PFXDELEGATION))
continue;
if (!(ap->flags & IPV6_AF_DELEGATEDLOG)) {
int loglevel;
@@ -3048,7 +3137,7 @@ dhcp6_find_delegates(struct interface *i
if (state == NULL || state->state != DH6S_BOUND)
continue;
TAILQ_FOREACH(ap, &state->addrs, next) {
- if (!(ap->flags & IPV6_AF_DELEGATEDPFX))
+ if (!(ap->flags & IPV6_AF_PFXDELEGATION))
continue;
for (i = 0; i < ifo->ia_len; i++) {
ia = &ifo->ia[i];
@@ -3082,7 +3171,6 @@ dhcp6_find_delegates(struct interface *i
if (k) {
loginfox("%s: adding delegated prefixes", ifp->name);
state = D6_STATE(ifp);
- state->state = DH6S_DELEGATED;
ipv6_addaddrs(&state->addrs);
rt_build(ifp->ctx, AF_INET6);
dhcp6_script_try_run(ifp, 1);
@@ -3139,7 +3227,7 @@ dhcp6_bind(struct interface *ifp, const
if (state->reason == NULL)
state->reason = "INFORM6";
- o = dhcp6_findmoption(state->new, state->new_len,
+ o = dhcp6_findmoption(state->recv, state->recv_len,
D6_OPTION_INFO_REFRESH_TIME, &ol);
if (o == NULL || ol != sizeof(uint32_t))
state->renew = IRT_DEFAULT;
@@ -3319,6 +3407,48 @@ dhcp6_bind(struct interface *ifp, const
}
static void
+dhcp6_adjust_max_rt(struct interface *ifp,
+ struct dhcp6_message *r, size_t len)
+{
+ struct dhcp6_state *state = D6_STATE(ifp);
+ uint8_t *o;
+ uint16_t ol;
+
+ /* RFC 8415 */
+ o = dhcp6_findmoption(r, len, D6_OPTION_SOL_MAX_RT, &ol);
+ if (o != NULL && ol == sizeof(uint32_t)) {
+ uint32_t max_rt;
+
+ memcpy(&max_rt, o, sizeof(max_rt));
+ max_rt = ntohl(max_rt);
+ if (max_rt >= 60 && max_rt <= 86400) {
+ logdebugx("%s: SOL_MAX_RT %llu -> %u",
+ ifp->name,
+ (unsigned long long)state->sol_max_rt,
+ max_rt);
+ state->sol_max_rt = max_rt;
+ } else
+ logerrx("%s: invalid SOL_MAX_RT %u", ifp->name, max_rt);
+ }
+
+ o = dhcp6_findmoption(r, len, D6_OPTION_INF_MAX_RT, &ol);
+ if (o != NULL && ol == sizeof(uint32_t)) {
+ uint32_t max_rt;
+
+ memcpy(&max_rt, o, sizeof(max_rt));
+ max_rt = ntohl(max_rt);
+ if (max_rt >= 60 && max_rt <= 86400) {
+ logdebugx("%s: INF_MAX_RT %llu -> %u",
+ ifp->name,
+ (unsigned long long)state->inf_max_rt,
+ max_rt);
+ state->inf_max_rt = max_rt;
+ } else
+ logerrx("%s: invalid INF_MAX_RT %u", ifp->name, max_rt);
+ }
+}
+
+static void
dhcp6_recvif(struct interface *ifp, const char *sfrom,
struct dhcp6_message *r, size_t len)
{
@@ -3326,7 +3456,7 @@ dhcp6_recvif(struct interface *ifp, cons
size_t i;
const char *op;
struct dhcp6_state *state;
- uint8_t *o;
+ uint8_t *o, preference = 0;
uint16_t ol;
const struct dhcp_opt *opt;
const struct if_options *ifo;
@@ -3438,6 +3568,7 @@ dhcp6_recvif(struct interface *ifp, cons
case DH6S_REQUEST: /* FALLTHROUGH */
case DH6S_RENEW: /* FALLTHROUGH */
case DH6S_REBIND:
+ dhcp6_adjust_max_rt(ifp, r, len);
if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1)
{
/*
@@ -3476,7 +3607,7 @@ dhcp6_recvif(struct interface *ifp, cons
* acknowledgement of one. */
loginfox("%s: %s acknowledged DECLINE6",
ifp->name, sfrom);
- dhcp6_fail(ifp);
+ dhcp6_fail(ifp, true);
return;
default:
valid_op = false;
@@ -3488,49 +3619,25 @@ dhcp6_recvif(struct interface *ifp, cons
valid_op = false;
break;
}
+
+ o = dhcp6_findmoption(r, len, D6_OPTION_PREFERENCE, &ol);
+ if (o && ol == sizeof(uint8_t))
+ preference = *o;
+
+ /* If we already have an advertisement check that this one
+ * has a higher preference value. */
if (state->recv_len && state->recv->type == DHCP6_ADVERTISE) {
- /* We already have an advertismemnt.
- * RFC 8415 says we have to wait for the IRT to elapse.
- * To keep the same behaviour we won't do anything with
- * this. In the future we should make a lists of
- * ADVERTS and pick the "best" one. */
- logdebugx("%s: discarding ADVERTISEMENT from %s",
- ifp->name, sfrom);
- return;
- }
- /* RFC7083 */
- o = dhcp6_findmoption(r, len, D6_OPTION_SOL_MAX_RT, &ol);
- if (o && ol == sizeof(uint32_t)) {
- uint32_t max_rt;
-
- memcpy(&max_rt, o, sizeof(max_rt));
- max_rt = ntohl(max_rt);
- if (max_rt >= 60 && max_rt <= 86400) {
- logdebugx("%s: SOL_MAX_RT %llu -> %u",
- ifp->name,
- (unsigned long long)state->sol_max_rt,
- max_rt);
- state->sol_max_rt = max_rt;
- } else
- logerr("%s: invalid SOL_MAX_RT %u",
- ifp->name, max_rt);
- }
- o = dhcp6_findmoption(r, len, D6_OPTION_INF_MAX_RT, &ol);
- if (o && ol == sizeof(uint32_t)) {
- uint32_t max_rt;
-
- memcpy(&max_rt, o, sizeof(max_rt));
- max_rt = ntohl(max_rt);
- if (max_rt >= 60 && max_rt <= 86400) {
- logdebugx("%s: INF_MAX_RT %llu -> %u",
- ifp->name,
- (unsigned long long)state->inf_max_rt,
- max_rt);
- state->inf_max_rt = max_rt;
- } else
- logerrx("%s: invalid INF_MAX_RT %u",
- ifp->name, max_rt);
+ o = dhcp6_findmoption(state->recv, state->recv_len,
+ D6_OPTION_PREFERENCE, &ol);
+ if (o && ol == sizeof(uint8_t) && *o >= preference) {
+ logdebugx(
+ "%s: discarding ADVERTISEMENT from %s (%u)",
+ ifp->name, sfrom, preference);
+ return;
+ }
}
+
+ dhcp6_adjust_max_rt(ifp, r, len);
if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1)
return;
break;
@@ -3609,8 +3716,6 @@ dhcp6_recvif(struct interface *ifp, cons
if (r->type == DHCP6_ADVERTISE) {
struct ipv6_addr *ia;
- if (state->state == DH6S_REQUEST) /* rapid commit */
- goto bind;
TAILQ_FOREACH(ia, &state->addrs, next) {
if (!(ia->flags & (IPV6_AF_STALE | IPV6_AF_REQUEST)))
break;
@@ -3618,16 +3723,22 @@ dhcp6_recvif(struct interface *ifp, cons
if (ia == NULL)
ia = TAILQ_FIRST(&state->addrs);
if (ia == NULL)
- loginfox("%s: ADV (no address) from %s",
- ifp->name, sfrom);
+ loginfox("%s: ADV (no address) from %s (%u)",
+ ifp->name, sfrom, preference);
else
- loginfox("%s: ADV %s from %s",
- ifp->name, ia->saddr, sfrom);
- // We will request when the IRT elapses
+ loginfox("%s: ADV %s from %s (%u)",
+ ifp->name, ia->saddr, sfrom, preference);
+
+ /*
+ * RFC 8415 18.2.1 says we must collect until ADVERTISEMENTs
+ * until we get one with a preference of 255 or
+ * the initial RT has elpased.
+ */
+ if (preference == 255 || state->RTC > 1)
+ dhcp6_startrequest(ifp);
return;
}
-bind:
dhcp6_bind(ifp, op, sfrom);
}
@@ -3978,13 +4089,10 @@ dhcp6_start1(void *arg)
del_option_mask(ifo->requestmask6, D6_OPTION_RAPID_COMMIT);
#endif
- if (state->state == DH6S_INFORM) {
- add_option_mask(ifo->requestmask6, D6_OPTION_INFO_REFRESH_TIME);
+ if (state->state == DH6S_INFORM)
dhcp6_startinform(ifp);
- } else {
- del_option_mask(ifo->requestmask6, D6_OPTION_INFO_REFRESH_TIME);
+ else
dhcp6_startinit(ifp);
- }
#ifndef SMALL
dhcp6_activateinterfaces(ifp);
@@ -4026,7 +4134,17 @@ dhcp6_start(struct interface *ifp, enum
}
break;
case DH6S_CONFIRM:
- init_state = DH6S_INIT;
+ /*
+ * CONFIRM a prior lease from a RA.
+ * This could be triggered by a roaming interface.
+ * We could also get here if we are delegated to.
+ * Now that we don't remove delegated addresses when
+ * reading the lease file this is the safe path.
+ */
+ if (state->state == DH6S_MANUALREBIND)
+ init_state = DH6S_MANUALREBIND;
+ else
+ init_state = DH6S_INIT;
goto gogogo;
default:
/* Not possible, but sushes some compiler warnings. */
@@ -4060,8 +4178,8 @@ dhcp6_start(struct interface *ifp, enum
TAILQ_INIT(&state->addrs);
gogogo:
- state->new_start = true;
state->state = init_state;
+ state->new_start = true;
state->lerror = 0;
state->failed = false;
dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile),
@@ -4085,15 +4203,17 @@ dhcp6_reboot(struct interface *ifp)
if (state == NULL)
return;
- state->lerror = 0;
switch (state->state) {
- case DH6S_BOUND:
- dhcp6_startrebind(ifp);
+ case DH6S_RENEW: /* FALLTHROUGH */
+ case DH6S_BOUND: /* FALLTHROUGH */
+ case DH6S_REBIND:
+ state->state = DH6S_MANUALREBIND;
break;
- default:
- dhcp6_startdiscoinform(ifp);
+ default: /* Appease compilers */
break;
}
+
+ /* Do nothing. On confirming the next lease we will REBIND instead. */
}
static void
@@ -4153,7 +4273,7 @@ dhcp6_freedrop(struct interface *ifp, in
}
#endif
- dhcp6_freedrop_addrs(ifp, drop, NULL);
+ dhcp6_freedrop_addrs(ifp, drop, 0, NULL);
free(state->old);
state->old = state->new;
state->old_len = state->new_len;
@@ -4207,21 +4327,12 @@ void
dhcp6_abort(struct interface *ifp)
{
struct dhcp6_state *state;
-#ifdef ND6_ADVERTISE
- struct ipv6_addr *ia;
-#endif
eloop_timeout_delete(ifp->ctx->eloop, dhcp6_start1, ifp);
state = D6_STATE(ifp);
if (state == NULL)
return;
-#ifdef ND6_ADVERTISE
- TAILQ_FOREACH(ia, &state->addrs, next) {
- ipv6nd_advertise(ia);
- }
-#endif
-
eloop_timeout_delete(ifp->ctx->eloop, dhcp6_startdiscover, ifp);
eloop_timeout_delete(ifp->ctx->eloop, dhcp6_senddiscover, ifp);
eloop_timeout_delete(ifp->ctx->eloop, dhcp6_startinform, ifp);
Index: src/external/bsd/dhcpcd/dist/src/dhcpcd.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.56 src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.57
--- src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.56 Fri May 24 16:09:09 2024
+++ src/external/bsd/dhcpcd/dist/src/dhcpcd.c Wed Feb 12 19:23:13 2025
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2023 Roy Marples <[email protected]>
+ * Copyright (c) 2006-2024 Roy Marples <[email protected]>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@@ -26,10 +26,9 @@
* SUCH DAMAGE.
*/
-static const char dhcpcd_copyright[] = "Copyright (c) 2006-2023 Roy Marples";
+static const char dhcpcd_copyright[] = "Copyright (c) 2006-2024 Roy Marples";
#include <sys/file.h>
-#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
@@ -115,7 +114,7 @@ printf("usage: "PACKAGE"\t[-146ABbDdEGgH
"\t\t[-O, --nooption option] [-o, --option option]\n"
"\t\t[-Q, --require option] [-r, --request address]\n"
"\t\t[-S, --static value]\n"
- "\t\t[-s, --inform address[/cidr[/broadcast_address]]]\n [--inform6]"
+ "\t\t[-s, --inform address[/cidr[/broadcast_address]]] [--inform6]\n"
"\t\t[-t, --timeout seconds] [-u, --userclass class]\n"
"\t\t[-v, --vendor code, value] [-W, --whitelist address[/cidr]] [-w]\n"
"\t\t[--waitip [4 | 6]] [-y, --reboot seconds]\n"
@@ -724,6 +723,9 @@ dhcpcd_nocarrier_roaming(struct interfac
#ifdef INET
dhcp_abort(ifp);
#endif
+#ifdef INET6
+ ipv6nd_abort(ifp);
+#endif
#ifdef DHCP6
dhcp6_abort(ifp);
#endif
@@ -963,6 +965,7 @@ dhcpcd_startinterface(void *arg)
else if (ifo->options & DHCPCD_INFORM6)
d6_state = DH6S_INFORM;
else
+ /* CONFIRM lease triggered from RA */
d6_state = DH6S_CONFIRM;
if (dhcp6_start(ifp, d6_state) == -1)
logerr("%s: dhcp6_start", ifp->name);
@@ -2278,8 +2281,7 @@ printpidfile:
#ifndef SMALL
if (ctx.options & DHCPCD_DUMPLEASE &&
- ioctl(fileno(stdin), FIONREAD, &i, sizeof(i)) == 0 &&
- i > 0)
+ ctx.ifc == 1 && ctx.ifv[0][0] == '-' && ctx.ifv[0][1] == '\0')
{
ctx.options |= DHCPCD_FORKED; /* pretend child process */
#ifdef PRIVSEP
@@ -2720,6 +2722,7 @@ exit1:
eloop_free(ctx.eloop);
logclose();
free(ctx.logfile);
+ fflush(stdout);
free(ctx.ctl_buf);
#ifdef SETPROCTITLE_H
setproctitle_fini();
Index: src/external/bsd/dhcpcd/dist/src/if-bsd.c
diff -u src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.31 src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.32
--- src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.31 Fri May 24 11:30:29 2024
+++ src/external/bsd/dhcpcd/dist/src/if-bsd.c Wed Feb 12 19:23:13 2025
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* BSD interface driver for dhcpcd
- * Copyright (c) 2006-2023 Roy Marples <[email protected]>
+ * Copyright (c) 2006-2024 Roy Marples <[email protected]>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@@ -742,15 +742,12 @@ if_route(unsigned char cmd, const struct
{
rtm->rtm_index = (unsigned short)rt->rt_ifp->index;
/*
- * OpenBSD rejects the message for on-link routes.
- * FreeBSD-12 kernel apparently panics.
- * I can't replicate the panic, but better safe than sorry!
- * https://roy.marples.name/archives/dhcpcd-discuss/0002286.html
- *
- * Neither OS currently allows IPv6 address sharing anyway, so let's
- * try to encourage someone to fix that by logging a waring during compile.
+ * OpenBSD rejects this for on-link routes when there is no default route
+ * OpenBSD does not allow the same IPv6 address on different
+ * interfaces on the same network, so let's try to encourage someone to
+ * fix that by logging a waring during compile.
*/
-#if defined(__FreeBSD__) || defined(__OpenBSD__)
+#ifdef __OpenBSD__
#warning kernel does not allow IPv6 address sharing
if (!gateway_unspec || rt->rt_dest.sa_family!=AF_INET6)
#endif
@@ -1355,8 +1352,18 @@ if_ifa(struct dhcpcd_ctx *ctx, const str
/* All BSD's set IFF_UP on the interface when adding an address.
* But not all BSD's emit this via RTM_IFINFO when they do this ... */
- if (ifam->ifam_type == RTM_NEWADDR && !(ifp->flags & IFF_UP))
- dhcpcd_handlecarrier(ifp, ifp->carrier, ifp->flags | IFF_UP);
+ if (ifam->ifam_type == RTM_NEWADDR && !(ifp->flags & IFF_UP)) {
+ struct ifreq ifr = { .ifr_flags = 0 };
+
+ /* Don't blindly assume the interface is up though.
+ * We might get the address via a state change. */
+ strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
+ if (ioctl(ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == -1)
+ return -1;
+ if (ifr.ifr_flags & IFF_UP)
+ dhcpcd_handlecarrier(ifp, ifp->carrier,
+ ifp->flags | IFF_UP);
+ }
switch (rti_info[RTAX_IFA]->sa_family) {
case AF_LINK:
@@ -1671,8 +1678,7 @@ if_machinearch(char *str, size_t len)
}
#ifdef INET6
-#if (defined(IPV6CTL_ACCEPT_RTADV) && !defined(ND6_IFF_ACCEPT_RTADV)) || \
- defined(IPV6CTL_FORWARDING)
+#if (defined(IPV6CTL_ACCEPT_RTADV) && !defined(ND6_IFF_ACCEPT_RTADV))
#define get_inet6_sysctl(code) inet6_sysctl(code, 0, 0)
#define set_inet6_sysctl(code, val) inet6_sysctl(code, val, 1)
static int
@@ -1744,39 +1750,6 @@ if_applyra(const struct ra *rap)
#endif
}
-#ifndef IPV6CTL_FORWARDING
-#define get_inet6_sysctlbyname(code) inet6_sysctlbyname(code, 0, 0)
-#define set_inet6_sysctlbyname(code, val) inet6_sysctlbyname(code, val, 1)
-static int
-inet6_sysctlbyname(const char *name, int val, int action)
-{
- size_t size;
-
- size = sizeof(val);
- if (action) {
- if (sysctlbyname(name, NULL, 0, &val, size) == -1)
- return -1;
- return 0;
- }
- if (sysctlbyname(name, &val, &size, NULL, 0) == -1)
- return -1;
- return val;
-}
-#endif
-
-int
-ip6_forwarding(__unused const char *ifname)
-{
- int val;
-
-#ifdef IPV6CTL_FORWARDING
- val = get_inet6_sysctl(IPV6CTL_FORWARDING);
-#else
- val = get_inet6_sysctlbyname("net.inet6.ip6.forwarding");
-#endif
- return val < 0 ? 0 : val;
-}
-
#ifdef SIOCIFAFATTACH
static int
if_af_attach(const struct interface *ifp, int af)
Index: src/external/bsd/dhcpcd/dist/src/ipv6nd.c
diff -u src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.31 src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.32
--- src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.31 Fri May 24 11:30:29 2024
+++ src/external/bsd/dhcpcd/dist/src/ipv6nd.c Wed Feb 12 19:23:13 2025
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - IPv6 ND handling
- * Copyright (c) 2006-2023 Roy Marples <[email protected]>
+ * Copyright (c) 2006-2024 Roy Marples <[email protected]>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@@ -434,167 +434,6 @@ sent:
logwarnx("%s: no IPv6 Routers available", ifp->name);
}
-#ifdef ND6_ADVERTISE
-static void
-ipv6nd_sendadvertisement(void *arg)
-{
- struct ipv6_addr *ia = arg;
- struct interface *ifp = ia->iface;
- struct dhcpcd_ctx *ctx = ifp->ctx;
- struct sockaddr_in6 dst = {
- .sin6_family = AF_INET6,
- .sin6_addr = IN6ADDR_LINKLOCAL_ALLNODES_INIT,
- .sin6_scope_id = ifp->index,
- };
- struct iovec iov = { .iov_base = ia->na, .iov_len = ia->na_len };
- union {
- struct cmsghdr hdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
- } cmsgbuf = { .buf = { 0 } };
- struct msghdr msg = {
- .msg_name = &dst, .msg_namelen = sizeof(dst),
- .msg_iov = &iov, .msg_iovlen = 1,
- .msg_control = cmsgbuf.buf, .msg_controllen = sizeof(cmsgbuf.buf),
- };
- struct cmsghdr *cm;
- struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
- const struct rs_state *state = RS_CSTATE(ifp);
- int s;
-
- if (state == NULL || !if_is_link_up(ifp))
- goto freeit;
-
-#ifdef SIN6_LEN
- dst.sin6_len = sizeof(dst);
-#endif
-
- /* Set the outbound interface. */
- cm = CMSG_FIRSTHDR(&msg);
- assert(cm != NULL);
- cm->cmsg_level = IPPROTO_IPV6;
- cm->cmsg_type = IPV6_PKTINFO;
- cm->cmsg_len = CMSG_LEN(sizeof(pi));
- memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
- logdebugx("%s: sending NA for %s", ifp->name, ia->saddr);
-
-#ifdef PRIVSEP
- if (IN_PRIVSEP(ifp->ctx)) {
- if (ps_inet_sendnd(ifp, &msg) == -1)
- logerr(__func__);
- goto sent;
- }
-#endif
-#ifdef __sun
- s = state->nd_fd;
-#else
- s = ctx->nd_fd;
-#endif
- if (sendmsg(s, &msg, 0) == -1)
- logerr(__func__);
-
-#ifdef PRIVSEP
-sent:
-#endif
- if (++ia->na_count < MAX_NEIGHBOR_ADVERTISEMENT) {
- eloop_timeout_add_sec(ctx->eloop,
- state->retrans / 1000, ipv6nd_sendadvertisement, ia);
- return;
- }
-
-freeit:
- free(ia->na);
- ia->na = NULL;
- ia->na_count = 0;
-}
-
-void
-ipv6nd_advertise(struct ipv6_addr *ia)
-{
- struct dhcpcd_ctx *ctx;
- struct interface *ifp;
- struct ipv6_state *state;
- struct ipv6_addr *iap, *iaf;
- struct nd_neighbor_advert *na;
-
- if (IN6_IS_ADDR_MULTICAST(&ia->addr))
- return;
-
-#ifdef __sun
- if (!(ia->flags & IPV6_AF_AUTOCONF) && ia->flags & IPV6_AF_RAPFX)
- return;
-#endif
-
- ctx = ia->iface->ctx;
- /* Find the most preferred address to advertise. */
- iaf = NULL;
- TAILQ_FOREACH(ifp, ctx->ifaces, next) {
- state = IPV6_STATE(ifp);
- if (state == NULL || !if_is_link_up(ifp))
- continue;
-
- TAILQ_FOREACH(iap, &state->addrs, next) {
- if (!IN6_ARE_ADDR_EQUAL(&iap->addr, &ia->addr))
- continue;
-
- /* Cancel any current advertisement. */
- eloop_timeout_delete(ctx->eloop,
- ipv6nd_sendadvertisement, iap);
-
- /* Don't advertise what we can't use. */
- if (iap->prefix_vltime == 0 ||
- iap->addr_flags & IN6_IFF_NOTUSEABLE)
- continue;
-
- if (iaf == NULL ||
- iaf->iface->metric > iap->iface->metric)
- iaf = iap;
- }
- }
- if (iaf == NULL)
- return;
-
- /* Make the packet. */
- ifp = iaf->iface;
- iaf->na_len = sizeof(*na);
- if (ifp->hwlen != 0)
- iaf->na_len += (size_t)ROUNDUP8(ifp->hwlen + 2);
- na = calloc(1, iaf->na_len);
- if (na == NULL) {
- logerr(__func__);
- return;
- }
-
- na->nd_na_type = ND_NEIGHBOR_ADVERT;
- na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE;
-#if defined(PRIVSEP) && (defined(__linux__) || defined(HAVE_PLEDGE))
- if (IN_PRIVSEP(ctx)) {
- if (ps_root_ip6forwarding(ctx, ifp->name) != 0)
- na->nd_na_flags_reserved |= ND_NA_FLAG_ROUTER;
- } else
-#endif
- if (ip6_forwarding(ifp->name) != 0)
- na->nd_na_flags_reserved |= ND_NA_FLAG_ROUTER;
- na->nd_na_target = ia->addr;
-
- if (ifp->hwlen != 0) {
- struct nd_opt_hdr *opt;
-
- opt = (struct nd_opt_hdr *)(na + 1);
- opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
- opt->nd_opt_len = (uint8_t)((ROUNDUP8(ifp->hwlen + 2)) >> 3);
- memcpy(opt + 1, ifp->hwaddr, ifp->hwlen);
- }
-
- iaf->na_count = 0;
- free(iaf->na);
- iaf->na = na;
- eloop_timeout_delete(ctx->eloop, ipv6nd_sendadvertisement, iaf);
- ipv6nd_sendadvertisement(iaf);
-}
-#elif !defined(SMALL)
-#warning kernel does not support userland sending ND6 advertisements
-#endif /* ND6_ADVERTISE */
-
static void
ipv6nd_expire(void *arg)
{
@@ -842,7 +681,7 @@ ipv6nd_removefreedrop_ra(struct ra *rap,
eloop_timeout_delete(rap->iface->ctx->eloop, NULL, rap);
if (remove_ra)
TAILQ_REMOVE(rap->iface->ctx->ra_routers, rap, next);
- ipv6_freedrop_addrs(&rap->addrs, drop_ra, NULL);
+ ipv6_freedrop_addrs(&rap->addrs, drop_ra, 0, NULL);
routeinfohead_free(&rap->rinfos);
free(rap->data);
free(rap);
@@ -1065,9 +904,6 @@ try_script:
ipv6nd_scriptrun(rap);
}
}
-#ifdef ND6_ADVERTISE
- ipv6nd_advertise(ia);
-#endif
}
}
@@ -1138,6 +974,12 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
bool new_ia;
#endif
+#define FREE_RAP(rap) \
+ if (new_rap) \
+ ipv6nd_removefreedrop_ra(rap, 0, 0); \
+ else \
+ ipv6nd_free_ra(rap); \
+
if (ifp == NULL || RS_STATE(ifp) == NULL) {
#ifdef DEBUG_RS
logdebugx("RA for unexpected interface from %s", sfrom);
@@ -1294,8 +1136,10 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
memcpy(&ndo, p, sizeof(ndo));
olen = (size_t)ndo.nd_opt_len * 8;
if (olen == 0) {
+ /* RFC4681 4.6 says we MUST discard this ND packet. */
logerrx("%s: zero length option", ifp->name);
- break;
+ FREE_RAP(rap);
+ return;
}
if (olen > len) {
logerrx("%s: option length exceeds message",
@@ -1319,10 +1163,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
else
logwarnx("%s: reject RA (option %d) from %s",
ifp->name, ndo.nd_opt_type, rap->sfrom);
- if (new_rap)
- ipv6nd_removefreedrop_ra(rap, 0, 0);
- else
- ipv6nd_free_ra(rap);
+ FREE_RAP(rap);
return;
}
@@ -1573,10 +1414,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
{
logwarnx("%s: reject RA (no option %s) from %s",
ifp->name, dho->var, rap->sfrom);
- if (new_rap)
- ipv6nd_removefreedrop_ra(rap, 0, 0);
- else
- ipv6nd_free_ra(rap);
+ FREE_RAP(rap);
return;
}
}
@@ -1598,7 +1436,8 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
logwarnx("%s: %s: no longer a default router (lifetime = 0)",
ifp->name, rap->sfrom);
- if (new_data && !has_address && rap->lifetime && !ipv6_anyglobal(ifp))
+ if (new_data && !has_address && rap->lifetime &&
+ ifp->options->options & DHCPCD_GATEWAY && !ipv6_anyglobal(ifp))
logwarnx("%s: no global addresses for default route",
ifp->name);
@@ -1657,6 +1496,7 @@ nodhcp6:
/* Expire should be called last as the rap object could be destroyed */
ipv6nd_expirera(ifp);
+#undef FREE_RAP
}
bool
@@ -1862,7 +1702,6 @@ ipv6nd_expirera(void *arg)
struct interface *ifp;
struct ra *rap, *ran;
struct timespec now;
- uint32_t elapsed;
bool expired, valid;
struct ipv6_addr *ia;
struct routeinfo *rinfo, *rinfob;
@@ -1874,11 +1713,11 @@ ipv6nd_expirera(void *arg)
#endif
struct nd_opt_dnssl dnssl;
struct nd_opt_rdnss rdnss;
- unsigned int next = 0, ltime;
+ uint32_t next = 0, ltime, elapsed;
size_t nexpired = 0;
ifp = arg;
- clock_gettime(CLOCK_MONOTONIC, &now);
+ timespecclear(&now);
expired = false;
TAILQ_FOREACH_SAFE(rap, ifp->ctx->ra_routers, next, ran) {
@@ -1886,10 +1725,10 @@ ipv6nd_expirera(void *arg)
continue;
valid = false;
/* lifetime may be set to infinite by rfc4191 route information */
- if (rap->lifetime && rap->lifetime != ND6_INFINITE_LIFETIME) {
- elapsed = (uint32_t)eloop_timespec_diff(&now,
- &rap->acquired, NULL);
- if (elapsed >= rap->lifetime || rap->doexpire) {
+ if (rap->lifetime) {
+ ltime = lifetime_left(rap->lifetime,
+ &rap->acquired, &now);
+ if (ltime == 0 || rap->doexpire) {
if (!rap->expired) {
logwarnx("%s: %s: router expired",
ifp->name, rap->sfrom);
@@ -1898,7 +1737,6 @@ ipv6nd_expirera(void *arg)
}
} else {
valid = true;
- ltime = rap->lifetime - elapsed;
if (next == 0 || ltime < next)
next = ltime;
}
@@ -1910,15 +1748,9 @@ ipv6nd_expirera(void *arg)
TAILQ_FOREACH(ia, &rap->addrs, next) {
if (ia->prefix_vltime == 0)
continue;
- if (ia->prefix_vltime == ND6_INFINITE_LIFETIME &&
- !rap->doexpire)
- {
- valid = true;
- continue;
- }
- elapsed = (uint32_t)eloop_timespec_diff(&now,
- &ia->acquired, NULL);
- if (elapsed >= ia->prefix_vltime || rap->doexpire) {
+ ltime = lifetime_left(ia->prefix_vltime,
+ &ia->acquired, &now);
+ if (ltime == 0 || rap->doexpire) {
if (ia->flags & IPV6_AF_ADDED) {
logwarnx("%s: expired %s %s",
ia->iface->name,
@@ -1936,7 +1768,6 @@ ipv6nd_expirera(void *arg)
expired = true;
} else {
valid = true;
- ltime = ia->prefix_vltime - elapsed;
if (next == 0 || ltime < next)
next = ltime;
}
@@ -1944,12 +1775,9 @@ ipv6nd_expirera(void *arg)
/* Expire route information */
TAILQ_FOREACH_SAFE(rinfo, &rap->rinfos, next, rinfob) {
- if (rinfo->lifetime == ND6_INFINITE_LIFETIME &&
- !rap->doexpire)
- continue;
- elapsed = (uint32_t)eloop_timespec_diff(&now,
- &rinfo->acquired, NULL);
- if (elapsed >= rinfo->lifetime || rap->doexpire) {
+ ltime = lifetime_left(rinfo->lifetime,
+ &rinfo->acquired, &now);
+ if (ltime == 0 || rap->doexpire) {
logwarnx("%s: expired route %s",
rap->iface->name, rinfo->sprefix);
TAILQ_REMOVE(&rap->rinfos, rinfo, next);
@@ -2163,7 +1991,7 @@ ipv6nd_handledata(void *arg, unsigned sh
}
static void
-ipv6nd_startrs1(void *arg)
+ipv6nd_startrs2(void *arg)
{
struct interface *ifp = arg;
struct rs_state *state;
@@ -2195,22 +2023,43 @@ ipv6nd_startrs1(void *arg)
ipv6nd_sendrsprobe(ifp);
}
-void
-ipv6nd_startrs(struct interface *ifp)
+static void
+ipv6nd_startrs1(void *arg)
{
+ struct interface *ifp = arg;
unsigned int delay;
- eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
if (!(ifp->options->options & DHCPCD_INITIAL_DELAY)) {
- ipv6nd_startrs1(ifp);
+ ipv6nd_startrs2(ifp);
return;
}
delay = arc4random_uniform(MAX_RTR_SOLICITATION_DELAY * MSEC_PER_SEC);
logdebugx("%s: delaying IPv6 router solicitation for %0.1f seconds",
ifp->name, (float)delay / MSEC_PER_SEC);
- eloop_timeout_add_msec(ifp->ctx->eloop, delay, ipv6nd_startrs1, ifp);
- return;
+ eloop_timeout_add_msec(ifp->ctx->eloop, delay, ipv6nd_startrs2, ifp);
+}
+
+void
+ipv6nd_startrs(struct interface *ifp)
+{
+
+ if (ipv6_linklocal(ifp) == NULL) {
+ logdebugx("%s: "
+ "delaying IPv6 Router Solicitation for LL address",
+ ifp->name);
+ ipv6_addlinklocalcallback(ifp, ipv6nd_startrs1, ifp);
+ } else
+ ipv6nd_startrs1(ifp);
+}
+
+void
+ipv6nd_abort(struct interface *ifp)
+{
+
+ eloop_timeout_delete(ifp->ctx->eloop, ipv6nd_startrs1, ifp);
+ eloop_timeout_delete(ifp->ctx->eloop, ipv6nd_startrs2, ifp);
+ eloop_timeout_delete(ifp->ctx->eloop, ipv6nd_sendrsprobe, ifp);
}
static struct routeinfo *routeinfo_findalloc(struct ra *rap, const struct in6_addr *prefix, uint8_t prefix_len)
Index: src/external/bsd/dhcpcd/dist/src/if-options.c
diff -u src/external/bsd/dhcpcd/dist/src/if-options.c:1.37 src/external/bsd/dhcpcd/dist/src/if-options.c:1.38
--- src/external/bsd/dhcpcd/dist/src/if-options.c:1.37 Fri May 24 11:30:29 2024
+++ src/external/bsd/dhcpcd/dist/src/if-options.c Wed Feb 12 19:23:13 2025
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2023 Roy Marples <[email protected]>
+ * Copyright (c) 2006-2024 Roy Marples <[email protected]>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@@ -87,6 +87,8 @@ const struct option cf_options[] = {
#ifndef SMALL
{"msuserclass", required_argument, NULL, O_MSUSERCLASS},
#endif
+ {"vsio", required_argument, NULL, O_VSIO},
+ {"vsio6", required_argument, NULL, O_VSIO6},
{"vendor", required_argument, NULL, 'v'},
{"waitip", optional_argument, NULL, 'w'},
{"exit", no_argument, NULL, 'x'},
@@ -654,6 +656,7 @@ parse_option(struct dhcpcd_ctx *ctx, con
struct dhcp_opt **dop, *ndop;
size_t *dop_len, dl, odl;
struct vivco *vivco;
+ const struct vivco *vivco_endp = ifo->vivco + ifo->vivco_len;
struct group *grp;
#ifdef AUTH
struct token *token;
@@ -666,7 +669,11 @@ parse_option(struct dhcpcd_ctx *ctx, con
struct if_ia *ia;
uint8_t iaid[4];
#ifndef SMALL
+ struct in6_addr in6addr;
struct if_sla *sla, *slap;
+ struct vsio **vsiop = NULL, *vsio;
+ size_t *vsio_lenp = NULL, opt_max, opt_header;
+ struct vsio_so *vsio_so;
#endif
#endif
@@ -755,7 +762,7 @@ parse_option(struct dhcpcd_ctx *ctx, con
case 'i':
if (arg)
s = parse_string((char *)ifo->vendorclassid + 1,
- VENDORCLASSID_MAX_LEN, arg);
+ sizeof(ifo->vendorclassid) - 1, arg);
else
s = 0;
if (s == -1) {
@@ -897,6 +904,139 @@ parse_option(struct dhcpcd_ctx *ctx, con
ifo->userclass[0] = (uint8_t)s;
break;
#endif
+
+ case O_VSIO:
+#ifndef SMALL
+ vsiop = &ifo->vsio;
+ vsio_lenp = &ifo->vsio_len;
+ opt_max = UINT8_MAX;
+ opt_header = sizeof(uint8_t) + sizeof(uint8_t);
+#endif
+ /* FALLTHROUGH */
+ case O_VSIO6:
+#ifndef SMALL
+ if (vsiop == NULL) {
+ vsiop = &ifo->vsio6;
+ vsio_lenp = &ifo->vsio6_len;
+ opt_max = UINT16_MAX;
+ opt_header = sizeof(uint16_t) + sizeof(uint16_t);
+ }
+#endif
+ ARG_REQUIRED;
+#ifdef SMALL
+ logwarnx("%s: vendor options not compiled in", ifname);
+ return -1;
+#else
+ fp = strwhite(arg);
+ if (fp)
+ *fp++ = '\0';
+ u = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
+ if (e) {
+ logerrx("invalid code: %s", arg);
+ return -1;
+ }
+
+ fp = strskipwhite(fp);
+ p = strchr(fp, ',');
+ if (!p || !p[1]) {
+ logerrx("invalid vendor format: %s", arg);
+ return -1;
+ }
+
+ /* Strip and preserve the comma */
+ *p = '\0';
+ i = (int)strtoi(fp, NULL, 0, 1, (intmax_t)opt_max, &e);
+ *p = ',';
+ if (e) {
+ logerrx("vendor option should be between"
+ " 1 and %zu inclusive", opt_max);
+ return -1;
+ }
+
+ fp = p + 1;
+
+ if (fp) {
+ if (inet_pton(AF_INET, fp, &addr) == 1) {
+ s = sizeof(addr.s_addr);
+ dl = (size_t)s;
+ np = malloc(dl);
+ if (np == NULL) {
+ logerr(__func__);
+ return -1;
+ }
+ memcpy(np, &addr.s_addr, dl);
+ } else if (inet_pton(AF_INET6, fp, &in6addr) == 1) {
+ s = sizeof(in6addr.s6_addr);
+ dl = (size_t)s;
+ np = malloc(dl);
+ if (np == NULL) {
+ logerr(__func__);
+ return -1;
+ }
+ memcpy(np, &in6addr.s6_addr, dl);
+ } else {
+ s = parse_string(NULL, 0, fp);
+ if (s == -1) {
+ logerr(__func__);
+ return -1;
+ }
+ dl = (size_t)s;
+ np = malloc(dl);
+ if (np == NULL) {
+ logerr(__func__);
+ return -1;
+ }
+ parse_string(np, dl, fp);
+ }
+ } else {
+ dl = 0;
+ np = NULL;
+ }
+
+ for (sl = 0, vsio = *vsiop; sl < *vsio_lenp; sl++, vsio++) {
+ if (vsio->en == (uint32_t)u)
+ break;
+ }
+ if (sl == *vsio_lenp) {
+ vsio = reallocarray(*vsiop, *vsio_lenp + 1,
+ sizeof(**vsiop));
+ if (vsio == NULL) {
+ logerr("%s: reallocarray vsio", __func__);
+ free(np);
+ return -1;
+ }
+ *vsiop = vsio;
+ vsio = &(*vsiop)[(*vsio_lenp)++];
+ vsio->en = (uint32_t)u;
+ vsio->so = NULL;
+ vsio->so_len = 0;
+ }
+
+ for (sl = 0, vsio_so = vsio->so;
+ sl < vsio->so_len;
+ sl++, vsio_so++)
+ opt_max -= opt_header + vsio_so->len;
+ if (opt_header + dl > opt_max) {
+ logerrx("vsio is too big: %s", fp);
+ free(np);
+ return -1;
+ }
+
+ vsio_so = reallocarray(vsio->so, vsio->so_len + 1,
+ sizeof(*vsio_so));
+ if (vsio_so == NULL) {
+ logerr("%s: reallocarray vsio_so", __func__);
+ free(np);
+ return -1;
+ }
+
+ vsio->so = vsio_so;
+ vsio_so = &vsio->so[vsio->so_len++];
+ vsio_so->opt = (uint16_t)i;
+ vsio_so->len = (uint16_t)dl;
+ vsio_so->data = np;
+ break;
+#endif
case 'v':
ARG_REQUIRED;
p = strchr(arg, ',');
@@ -909,7 +1049,7 @@ parse_option(struct dhcpcd_ctx *ctx, con
if (p == arg) {
arg++;
s = parse_string((char *)ifo->vendor + 1,
- VENDOR_MAX_LEN, arg);
+ sizeof(ifo->vendor) - 1, arg);
if (s == -1) {
logerr("vendor");
return -1;
@@ -936,7 +1076,7 @@ parse_option(struct dhcpcd_ctx *ctx, con
}
arg = p + 1;
- s = VENDOR_MAX_LEN - ifo->vendor[0] - 2;
+ s = sizeof(ifo->vendor) - 1 - ifo->vendor[0] - 2;
if (inet_aton(arg, &addr) == 1) {
if (s < 6) {
s = -1;
@@ -1063,11 +1203,13 @@ parse_option(struct dhcpcd_ctx *ctx, con
ifo->options |= DHCPCD_XID_HWADDR;
break;
case 'I':
- /* Strings have a type of 0 */;
- ifo->clientid[1] = 0;
if (arg)
+ /* If parse_hwaddr cannot decoded arg as a
+ * hardware address then the first byte
+ * in the clientid will be zero to indicate
+ * a string value. */
s = parse_hwaddr((char *)ifo->clientid + 1,
- CLIENTID_MAX_LEN, arg);
+ sizeof(ifo->clientid) - 1, arg);
else
s = 0;
if (s == -1) {
@@ -1218,7 +1360,7 @@ parse_option(struct dhcpcd_ctx *ctx, con
if (p == NULL)
break;
ifo->mtu = (unsigned int)strtou(p, NULL, 0,
- MTU_MIN, MTU_MAX, &e);
+ IPV4_MMTU, UINT_MAX, &e);
if (e) {
logerrx("invalid MTU %s", p);
return -1;
@@ -1972,6 +2114,10 @@ err_sla:
break;
case O_VENDCLASS:
ARG_REQUIRED;
+#ifdef SMALL
+ logwarnx("%s: vendor options not compiled in", ifname);
+ return -1;
+#else
fp = strwhite(arg);
if (fp)
*fp++ = '\0';
@@ -1980,6 +2126,12 @@ err_sla:
logerrx("invalid code: %s", arg);
return -1;
}
+ for (vivco = ifo->vivco; vivco != vivco_endp; vivco++) {
+ if (vivco->en == (uint32_t)u) {
+ logerrx("vendor class option for enterprise number %u already defined", vivco->en);
+ return -1;
+ }
+ }
fp = strskipwhite(fp);
if (fp) {
s = parse_string(NULL, 0, fp);
@@ -2010,11 +2162,12 @@ err_sla:
return -1;
}
ifo->vivco = vivco;
- ifo->vivco_en = (uint32_t)u;
vivco = &ifo->vivco[ifo->vivco_len++];
+ vivco->en = (uint32_t)u;
vivco->len = dl;
vivco->data = (uint8_t *)np;
break;
+#endif
case O_AUTHPROTOCOL:
ARG_REQUIRED;
#ifdef AUTH
@@ -2318,7 +2471,8 @@ invalid_token:
break;
case O_MUDURL:
ARG_REQUIRED;
- s = parse_string((char *)ifo->mudurl + 1, MUDURL_MAX_LEN, arg);
+ s = parse_string((char *)ifo->mudurl + 1,
+ sizeof(ifo->mudurl) - 1, arg);
if (s == -1) {
logerr("mudurl");
return -1;
@@ -2801,6 +2955,10 @@ free_options(struct dhcpcd_ctx *ctx, str
#ifdef AUTH
struct token *token;
#endif
+#ifndef SMALL
+ struct vsio *vsio;
+ struct vsio_so *vsio_so;
+#endif
if (ifo == NULL)
return;
@@ -2851,11 +3009,35 @@ free_options(struct dhcpcd_ctx *ctx, str
opt++, ifo->dhcp6_override_len--)
free_dhcp_opt_embenc(opt);
free(ifo->dhcp6_override);
+#ifndef SMALL
for (vo = ifo->vivco;
ifo->vivco_len > 0;
vo++, ifo->vivco_len--)
free(vo->data);
free(ifo->vivco);
+ for (vsio = ifo->vsio;
+ ifo->vsio_len > 0;
+ vsio++, ifo->vsio_len--)
+ {
+ for (vsio_so = vsio->so;
+ vsio->so_len > 0;
+ vsio_so++, vsio->so_len--)
+ free(vsio_so->data);
+ free(vsio->so);
+ }
+ free(ifo->vsio);
+ for (vsio = ifo->vsio6;
+ ifo->vsio6_len > 0;
+ vsio++, ifo->vsio6_len--)
+ {
+ for (vsio_so = vsio->so;
+ vsio->so_len > 0;
+ vsio_so++, vsio->so_len--)
+ free(vsio_so->data);
+ free(vsio->so);
+ }
+ free(ifo->vsio6);
+#endif
for (opt = ifo->vivso_override;
ifo->vivso_override_len > 0;
opt++, ifo->vivso_override_len--)
Index: src/external/bsd/dhcpcd/dist/src/ipv6.c
diff -u src/external/bsd/dhcpcd/dist/src/ipv6.c:1.19 src/external/bsd/dhcpcd/dist/src/ipv6.c:1.20
--- src/external/bsd/dhcpcd/dist/src/ipv6.c:1.19 Fri May 24 11:30:29 2024
+++ src/external/bsd/dhcpcd/dist/src/ipv6.c Wed Feb 12 19:23:13 2025
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2023 Roy Marples <[email protected]>
+ * Copyright (c) 2006-2024 Roy Marples <[email protected]>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@@ -89,7 +89,6 @@
#ifdef IPV6_POLLADDRFLAG
# warning kernel does not report IPv6 address flag changes
-# warning polling tentative address flags periodically
#endif
/* Hackery at it's finest. */
@@ -615,9 +614,8 @@ ipv6_deletedaddr(struct ipv6_addr *ia)
#ifdef PRIVSEP
if (!(ia->iface->ctx->options & DHCPCD_MANAGER))
ps_inet_closedhcp6(ia);
-#elif defined(SMALL)
- UNUSED(ia);
-#else
+#endif
+#ifndef SMALL
/* NOREJECT is set if we delegated exactly the prefix to another
* address.
* This can only be one address, so just clear the flag.
@@ -625,8 +623,10 @@ ipv6_deletedaddr(struct ipv6_addr *ia)
if (ia->delegating_prefix != NULL)
ia->delegating_prefix->flags &= ~IPV6_AF_NOREJECT;
#endif
-#else
- UNUSED(ia);
+#endif
+
+#if !defined(DHCP6) || (!defined(PRIVSEP) && defined(SMALL))
+ UNUSED(ia)
#endif
}
@@ -652,45 +652,52 @@ ipv6_deleteaddr(struct ipv6_addr *ia)
break;
}
}
+}
-#ifdef ND6_ADVERTISE
- /* Advertise the address if it exists on another interface. */
- ipv6nd_advertise(ia);
-#endif
+static struct ipv6_state *
+ipv6_getstate(struct interface *ifp)
+{
+ struct ipv6_state *state;
+
+ state = IPV6_STATE(ifp);
+ if (state == NULL) {
+ ifp->if_data[IF_DATA_IPV6] = calloc(1, sizeof(*state));
+ state = IPV6_STATE(ifp);
+ if (state == NULL) {
+ logerr(__func__);
+ return NULL;
+ }
+ TAILQ_INIT(&state->addrs);
+ TAILQ_INIT(&state->ll_callbacks);
+ }
+ return state;
}
static int
-ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now)
+ipv6_addaddr1(struct ipv6_addr *ia, struct timespec *now)
{
struct interface *ifp;
uint32_t pltime, vltime;
int loglevel;
-#ifdef ND6_ADVERTISE
- bool vltime_was_zero = ia->prefix_vltime == 0;
-#endif
-#ifdef __sun
- struct ipv6_state *state;
- struct ipv6_addr *ia2;
+ struct ipv6_addr *iaf;
+#ifdef __sun
/* If we re-add then address on Solaris then the prefix
* route will be scrubbed and re-added. Something might
* be using it, so let's avoid it. */
if (ia->flags & IPV6_AF_DADCOMPLETED) {
logdebugx("%s: IP address %s already exists",
ia->iface->name, ia->saddr);
-#ifdef ND6_ADVERTISE
- goto advertise;
-#else
return 0;
-#endif
}
#endif
/* Remember the interface of the address. */
ifp = ia->iface;
- if (!(ia->flags & IPV6_AF_DADCOMPLETED) &&
- ipv6_iffindaddr(ifp, &ia->addr, IN6_IFF_NOTUSEABLE))
+ /* Find any existing address. */
+ iaf = ipv6_iffindaddr(ifp, &ia->addr, 0);
+ if (iaf != NULL && !(iaf->addr_flags & IN6_IFF_NOTUSEABLE))
ia->flags |= IPV6_AF_DADCOMPLETED;
/* Adjust plftime and vltime based on acquired time */
@@ -704,31 +711,11 @@ ipv6_addaddr1(struct ipv6_addr *ia, cons
ia->prefix_vltime = ia->prefix_pltime = ND6_INFINITE_LIFETIME;
}
- if (timespecisset(&ia->acquired) &&
- (ia->prefix_pltime != ND6_INFINITE_LIFETIME ||
- ia->prefix_vltime != ND6_INFINITE_LIFETIME))
- {
- uint32_t elapsed;
- struct timespec n;
-
- if (now == NULL) {
- clock_gettime(CLOCK_MONOTONIC, &n);
- now = &n;
- }
- elapsed = (uint32_t)eloop_timespec_diff(now, &ia->acquired,
- NULL);
- if (ia->prefix_pltime != ND6_INFINITE_LIFETIME) {
- if (elapsed > ia->prefix_pltime)
- ia->prefix_pltime = 0;
- else
- ia->prefix_pltime -= elapsed;
- }
- if (ia->prefix_vltime != ND6_INFINITE_LIFETIME) {
- if (elapsed > ia->prefix_vltime)
- ia->prefix_vltime = 0;
- else
- ia->prefix_vltime -= elapsed;
- }
+ if (timespecisset(&ia->acquired)) {
+ ia->prefix_pltime = lifetime_left(ia->prefix_pltime,
+ &ia->acquired, now);
+ ia->prefix_vltime = lifetime_left(ia->prefix_vltime,
+ &ia->acquired, now);
}
loglevel = ia->flags & IPV6_AF_NEW ? LOG_INFO : LOG_DEBUG;
@@ -793,35 +780,19 @@ ipv6_addaddr1(struct ipv6_addr *ia, cons
}
#endif
-#ifdef __sun
- /* Solaris does not announce new addresses which need DaD
- * so we need to take a copy and add it to our list.
- * Otherwise aliasing gets confused if we add another
- * address during DaD. */
+ /* Take a copy of the address and add it to our state if
+ * it does not exist.
+ * This is important if route overflow loses the message. */
+ if (iaf == NULL) {
+ struct ipv6_state *state = ipv6_getstate(ifp);
- state = IPV6_STATE(ifp);
- TAILQ_FOREACH(ia2, &state->addrs, next) {
- if (IN6_ARE_ADDR_EQUAL(&ia2->addr, &ia->addr))
- break;
- }
- if (ia2 == NULL) {
- if ((ia2 = malloc(sizeof(*ia2))) == NULL) {
+ if ((iaf = malloc(sizeof(*iaf))) == NULL) {
logerr(__func__);
return 0; /* Well, we did add the address */
}
- memcpy(ia2, ia, sizeof(*ia2));
- TAILQ_INSERT_TAIL(&state->addrs, ia2, next);
+ memcpy(iaf, ia, sizeof(*iaf));
+ TAILQ_INSERT_TAIL(&state->addrs, iaf, next);
}
-#endif
-
-#ifdef ND6_ADVERTISE
-#ifdef __sun
-advertise:
-#endif
- /* Re-advertise the preferred address to be safe. */
- if (!vltime_was_zero)
- ipv6nd_advertise(ia);
-#endif
return 0;
}
@@ -889,7 +860,7 @@ find_unit:
#endif
int
-ipv6_addaddr(struct ipv6_addr *ia, const struct timespec *now)
+ipv6_addaddr(struct ipv6_addr *ia, struct timespec *now)
{
int r;
#ifdef ALIAS_ADDR
@@ -965,7 +936,7 @@ ipv6_doaddr(struct ipv6_addr *ia, struct
{
/* A delegated prefix is not an address. */
- if (ia->flags & IPV6_AF_DELEGATEDPFX)
+ if (ia->flags & IPV6_AF_PFXDELEGATION)
return 0;
if (ia->prefix_vltime == 0) {
@@ -984,8 +955,6 @@ ipv6_doaddr(struct ipv6_addr *ia, struct
IN6_IS_ADDR_UNSPECIFIED(&ia->addr))
return 0;
- if (!timespecisset(now))
- clock_gettime(CLOCK_MONOTONIC, now);
ipv6_addaddr(ia, now);
return ia->flags & IPV6_AF_NEW ? 1 : 0;
}
@@ -1019,7 +988,7 @@ ipv6_freeaddr(struct ipv6_addr *ia)
struct ipv6_addr *iad;
/* Forget the reference */
- if (ia->flags & IPV6_AF_DELEGATEDPFX) {
+ if (ia->flags & IPV6_AF_PFXDELEGATION) {
TAILQ_FOREACH(iad, &ia->pd_pfxs, pd_next) {
iad->delegating_prefix = NULL;
}
@@ -1040,7 +1009,7 @@ ipv6_freeaddr(struct ipv6_addr *ia)
void
ipv6_freedrop_addrs(struct ipv6_addrhead *addrs, int drop,
- const struct interface *ifd)
+ unsigned int notflags, const struct interface *ifd)
{
struct ipv6_addr *ap, *apn, *apf;
struct timespec now;
@@ -1050,6 +1019,8 @@ ipv6_freedrop_addrs(struct ipv6_addrhead
#endif
timespecclear(&now);
TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
+ if (ap->flags & notflags)
+ continue;
#ifndef SMALL
if (ifd != NULL &&
(ap->delegating_prefix == NULL ||
@@ -1077,12 +1048,7 @@ ipv6_freedrop_addrs(struct ipv6_addrhead
ipv6_deleteaddr(ap);
if (!(ap->iface->options->options &
DHCPCD_EXITING) && apf)
- {
- if (!timespecisset(&now))
- clock_gettime(CLOCK_MONOTONIC,
- &now);
ipv6_addaddr(apf, &now);
- }
if (drop == 2)
ipv6_freeaddr(ap);
}
@@ -1092,61 +1058,51 @@ ipv6_freedrop_addrs(struct ipv6_addrhead
}
}
-static struct ipv6_state *
-ipv6_getstate(struct interface *ifp)
+static struct ipv6_addr *
+ipv6_ifanyglobal(struct interface *ifp)
{
struct ipv6_state *state;
+ struct ipv6_addr *ia;
state = IPV6_STATE(ifp);
- if (state == NULL) {
- ifp->if_data[IF_DATA_IPV6] = calloc(1, sizeof(*state));
- state = IPV6_STATE(ifp);
- if (state == NULL) {
- logerr(__func__);
- return NULL;
- }
- TAILQ_INIT(&state->addrs);
- TAILQ_INIT(&state->ll_callbacks);
+ if (state == NULL)
+ return NULL;
+
+ TAILQ_FOREACH(ia, &state->addrs, next) {
+ if (IN6_IS_ADDR_LINKLOCAL(&ia->addr) ||
+ IN6_IS_ADDR_LOOPBACK(&ia->addr))
+ continue;
+ /* Let's be optimistic.
+ * Any decent OS won't forward or accept traffic
+ * from/to tentative or detached addresses. */
+ if (!(ia->addr_flags & IN6_IFF_DUPLICATED))
+ return ia;
}
- return state;
+
+ return NULL;
}
struct ipv6_addr *
ipv6_anyglobal(struct interface *sifp)
{
- struct interface *ifp;
- struct ipv6_state *state;
struct ipv6_addr *ia;
- bool forwarding;
-
- /* BSD forwarding is either on or off.
- * Linux forwarding is technically the same as it's
- * configured by the "all" interface.
- * Per interface only affects IsRouter of NA messages. */
-#if defined(PRIVSEP) && (defined(HAVE_PLEDGE) || defined(__linux__))
- if (IN_PRIVSEP(sifp->ctx))
- forwarding = ps_root_ip6forwarding(sifp->ctx, NULL) != 0;
- else
-#endif
- forwarding = ip6_forwarding(NULL) != 0;
+ struct interface *ifp;
+ /*
+ * IPv6 source address selection will prefer the outgoing interface,
+ * but will also use any other interface if it things the address is
+ * a better fit for the destination.
+ * This logic is pretty much baked into all kernels and you
+ * don't need to be a router either.
+ * We only have this logic to work around badly configured IPv6
+ * setups where there is a default router, but you're not handed
+ * a reachable address. This results in network timeouts which we
+ * want to actively avoid.
+ */
TAILQ_FOREACH(ifp, sifp->ctx->ifaces, next) {
- if (ifp != sifp && !forwarding)
- continue;
-
- state = IPV6_STATE(ifp);
- if (state == NULL)
- continue;
-
- TAILQ_FOREACH(ia, &state->addrs, next) {
- if (IN6_IS_ADDR_LINKLOCAL(&ia->addr))
- continue;
- /* Let's be optimistic.
- * Any decent OS won't forward or accept traffic
- * from/to tentative or detached addresses. */
- if (!(ia->addr_flags & IN6_IFF_DUPLICATED))
- return ia;
- }
+ ia = ipv6_ifanyglobal(ifp);
+ if (ia != NULL)
+ return ia;
}
return NULL;
}
@@ -1198,22 +1154,20 @@ ipv6_handleifa(struct dhcpcd_ctx *ctx,
anyglobal = ipv6_anyglobal(ifp) != NULL;
TAILQ_FOREACH(ia, &state->addrs, next) {
- if (IN6_ARE_ADDR_EQUAL(&ia->addr, addr))
+ if (IN6_ARE_ADDR_EQUAL(&ia->addr, addr)) {
+ ia->addr_flags = addrflags;
break;
+ }
}
switch (cmd) {
case RTM_DELADDR:
if (ia != NULL) {
TAILQ_REMOVE(&state->addrs, ia, next);
-#ifdef ND6_ADVERTISE
- /* Advertise the address if it exists on
- * another interface. */
- ipv6nd_advertise(ia);
-#endif
/* We'll free it at the end of the function. */
}
break;
+
case RTM_NEWADDR:
if (ia == NULL) {
ia = ipv6_newaddr(ifp, addr, prefix_len, 0);
@@ -1244,49 +1198,52 @@ ipv6_handleifa(struct dhcpcd_ctx *ctx,
* generate a new temporary address on
* restart. */
ia->acquired = ia->created;
+ ia->addr_flags = addrflags;
TAILQ_INSERT_TAIL(&state->addrs, ia, next);
}
- ia->addr_flags = addrflags;
ia->flags &= ~IPV6_AF_STALE;
#ifdef IPV6_MANAGETEMPADDR
if (ia->addr_flags & IN6_IFF_TEMPORARY)
ia->flags |= IPV6_AF_TEMPORARY;
#endif
- if (IN6_IS_ADDR_LINKLOCAL(&ia->addr) || ia->dadcallback) {
+
#ifdef IPV6_POLLADDRFLAG
- if (ia->addr_flags & IN6_IFF_TENTATIVE) {
- eloop_timeout_add_msec(
- ia->iface->ctx->eloop,
- RETRANS_TIMER / 2, ipv6_checkaddrflags, ia);
- break;
- }
+ if ((IN6_IS_ADDR_LINKLOCAL(&ia->addr) || ia->dadcallback) &&
+ ia->addr_flags & IN6_IFF_TENTATIVE)
+ {
+ eloop_timeout_add_msec(
+ ia->iface->ctx->eloop,
+ RETRANS_TIMER / 2, ipv6_checkaddrflags, ia);
+ }
#endif
- if (ia->dadcallback)
- ia->dadcallback(ia);
-
- if (IN6_IS_ADDR_LINKLOCAL(&ia->addr) &&
- !(ia->addr_flags & IN6_IFF_NOTUSEABLE))
- {
- /* Now run any callbacks.
- * Typically IPv6RS or DHCPv6 */
- while ((cb =
- TAILQ_FIRST(&state->ll_callbacks)))
- {
- TAILQ_REMOVE(
- &state->ll_callbacks,
- cb, next);
- cb->callback(cb->arg);
- free(cb);
- }
- }
- }
break;
+
+ default:
+ return;
}
if (ia == NULL)
return;
+ if (ia->dadcallback && ((ia->addr_flags &
+ (IN6_IFF_DETACHED | IN6_IFF_TENTATIVE)) == 0 ||
+ ia->addr_flags & IN6_IFF_DUPLICATED))
+ ia->dadcallback(ia);
+
+ if (IN6_IS_ADDR_LINKLOCAL(&ia->addr) &&
+ !(ia->addr_flags & IN6_IFF_NOTUSEABLE))
+ {
+ /* Now run any callbacks.
+ * Typically IPv6RS or DHCPv6 */
+ while ((cb = TAILQ_FIRST(&state->ll_callbacks)))
+ {
+ TAILQ_REMOVE(&state->ll_callbacks, cb, next);
+ cb->callback(cb->arg);
+ free(cb);
+ }
+ }
+
ctx->options &= ~DHCPCD_RTBUILD;
ipv6nd_handleifa(cmd, ia, pid);
#ifdef DHCP6
@@ -1332,17 +1289,19 @@ ipv6_iffindaddr(struct interface *ifp, c
struct ipv6_addr *ap;
state = IPV6_STATE(ifp);
- if (state) {
- TAILQ_FOREACH(ap, &state->addrs, next) {
- if (addr == NULL) {
- if (IN6_IS_ADDR_LINKLOCAL(&ap->addr) &&
- (!revflags || !(ap->addr_flags & revflags)))
- return ap;
- } else {
- if (IN6_ARE_ADDR_EQUAL(&ap->addr, addr) &&
- (!revflags || !(ap->addr_flags & revflags)))
- return ap;
- }
+ if (state == NULL)
+ return NULL;
+
+ TAILQ_FOREACH(ap, &state->addrs, next) {
+ if (addr == NULL) {
+ if (IN6_IS_ADDR_LINKLOCAL(&ap->addr) &&
+ (!revflags || !(ap->addr_flags & revflags)))
+ return ap;
+ } else if (IN6_ARE_ADDR_EQUAL(&ap->addr, addr)) {
+ /* This is our address so we will return now */
+ if (!revflags || !(ap->addr_flags & revflags))
+ return ap;
+ return NULL;
}
}
return NULL;
@@ -1391,18 +1350,17 @@ ipv6_addlinklocalcallback(struct interfa
state = ipv6_getstate(ifp);
TAILQ_FOREACH(cb, &state->ll_callbacks, next) {
if (cb->callback == callback && cb->arg == arg)
- break;
+ return 0;
}
+
+ cb = malloc(sizeof(*cb));
if (cb == NULL) {
- cb = malloc(sizeof(*cb));
- if (cb == NULL) {
- logerr(__func__);
- return -1;
- }
- cb->callback = callback;
- cb->arg = arg;
- TAILQ_INSERT_TAIL(&state->ll_callbacks, cb, next);
+ logerr(__func__);
+ return -1;
}
+ cb->callback = callback;
+ cb->arg = arg;
+ TAILQ_INSERT_TAIL(&state->ll_callbacks, cb, next);
return 0;
}
@@ -1609,38 +1567,13 @@ ipv6_newaddr(struct interface *ifp, cons
struct ipv6_addr *ia, *iaf;
char buf[INET6_ADDRSTRLEN];
const char *cbp;
- bool tempaddr;
- int addr_flags;
-
-#ifdef IPV6_AF_TEMPORARY
- tempaddr = flags & IPV6_AF_TEMPORARY;
-#else
- tempaddr = false;
-#endif
-
- /* If adding a new DHCP / RA derived address, check current flags
- * from an existing address. */
- if (tempaddr)
- iaf = NULL;
- else if (flags & IPV6_AF_AUTOCONF)
- iaf = ipv6nd_iffindprefix(ifp, addr, prefix_len);
- else
- iaf = ipv6_iffindaddr(ifp, addr, 0);
- if (iaf != NULL) {
- addr_flags = iaf->addr_flags;
- flags |= IPV6_AF_ADDED;
- } else
- addr_flags = IN6_IFF_TENTATIVE;
ia = calloc(1, sizeof(*ia));
if (ia == NULL)
goto err;
ia->iface = ifp;
- ia->addr_flags = addr_flags;
ia->flags = IPV6_AF_NEW | flags;
- if (!(ia->addr_flags & IN6_IFF_NOTUSEABLE))
- ia->flags |= IPV6_AF_DADCOMPLETED;
ia->prefix_len = prefix_len;
ia->dhcp6_fd = -1;
@@ -1652,6 +1585,7 @@ ipv6_newaddr(struct interface *ifp, cons
goto makepfx;
else if (ia->flags & IPV6_AF_AUTOCONF) {
ia->prefix = *addr;
+ iaf = ipv6nd_iffindprefix(ifp, addr, prefix_len);
if (iaf != NULL)
memcpy(&ia->addr, &iaf->addr, sizeof(ia->addr));
else {
@@ -1669,9 +1603,9 @@ ipv6_newaddr(struct interface *ifp, cons
cbp = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf));
goto paddr;
#else
- return ia;
+ goto flags;
#endif
- } else if (ia->flags & (IPV6_AF_REQUEST | IPV6_AF_DELEGATEDPFX)) {
+ } else if (ia->flags & (IPV6_AF_REQUEST | IPV6_AF_PFXDELEGATION)) {
ia->prefix = *addr;
cbp = inet_ntop(AF_INET6, &ia->prefix, buf, sizeof(buf));
goto paddr;
@@ -1689,6 +1623,21 @@ paddr:
goto err;
snprintf(ia->saddr, sizeof(ia->saddr), "%s/%d", cbp, ia->prefix_len);
+#ifndef __sun
+flags:
+#endif
+ /* If adding a new DHCP / RA derived address, check current flags
+ * from an existing address. */
+ iaf = ipv6_iffindaddr(ifp, &ia->addr, 0);
+ if (iaf != NULL) {
+ ia->addr_flags = iaf->addr_flags;
+ ia->flags |= IPV6_AF_ADDED;
+ } else
+ ia->addr_flags |= IN6_IFF_TENTATIVE;
+
+ if (!(ia->addr_flags & IN6_IFF_NOTUSEABLE))
+ ia->flags |= IPV6_AF_DADCOMPLETED;
+
return ia;
err:
@@ -1857,7 +1806,7 @@ ipv6_freedrop(struct interface *ifp, int
free(cb);
}
- ipv6_freedrop_addrs(&state->addrs, drop ? 2 : 0, NULL);
+ ipv6_freedrop_addrs(&state->addrs, drop ? 2 : 0, 0, NULL);
if (drop) {
if (ifp->ctx->ra_routers != NULL)
rt_build(ifp->ctx, AF_INET6);
@@ -1883,10 +1832,13 @@ ipv6_handleifa_addrs(int cmd,
struct ipv6_addrhead *addrs, const struct ipv6_addr *addr, pid_t pid)
{
struct ipv6_addr *ia, *ian;
- uint8_t found, alldadcompleted;
+ int found = 0, alldadcompleted = 1;
+
+ if (cmd != RTM_NEWADDR && cmd != RTM_DELADDR) {
+ errno = EINVAL;
+ return -1;
+ }
- alldadcompleted = 1;
- found = 0;
TAILQ_FOREACH_SAFE(ia, addrs, next, ian) {
if (!IN6_ARE_ADDR_EQUAL(&addr->addr, &ia->addr)) {
if (ia->flags & IPV6_AF_ADDED &&
@@ -1894,34 +1846,35 @@ ipv6_handleifa_addrs(int cmd,
alldadcompleted = 0;
continue;
}
- switch (cmd) {
- case RTM_DELADDR:
- if (ia->flags & IPV6_AF_ADDED) {
- logwarnx("%s: pid %d deleted address %s",
- ia->iface->name, pid, ia->saddr);
- ia->flags &= ~IPV6_AF_ADDED;
- }
+
+ ia->addr_flags = addr->addr_flags;
+
+ if (cmd == RTM_DELADDR && ia->flags & IPV6_AF_ADDED)
+ logwarnx("%s: pid %d deleted address %s",
+ ia->iface->name, pid, ia->saddr);
+
+ /* Check DAD.
+ * On Linux we can get IN6_IFF_DUPLICATED via RTM_DELADDR. */
+ if (((ia->addr_flags &
+ (IN6_IFF_DETACHED | IN6_IFF_TENTATIVE)) == 0 ||
+ ia->addr_flags & IN6_IFF_DUPLICATED) &&
+ (ia->flags & IPV6_AF_DADCOMPLETED) == 0)
+ {
+ found++;
+ if (ia->dadcallback)
+ ia->dadcallback(ia);
+ /* We need to set this here in-case the
+ * dadcallback function checks it */
+ ia->flags |= IPV6_AF_DADCOMPLETED;
+ }
+
+ if (cmd == RTM_DELADDR) {
+ ia->flags &= ~IPV6_AF_ADDED;
ipv6_deletedaddr(ia);
if (ia->flags & IPV6_AF_DELEGATED) {
TAILQ_REMOVE(addrs, ia, next);
ipv6_freeaddr(ia);
}
- break;
- case RTM_NEWADDR:
- ia->addr_flags = addr->addr_flags;
- /* Safety - ignore tentative announcements */
- if (ia->addr_flags &
- (IN6_IFF_DETACHED | IN6_IFF_TENTATIVE))
- break;
- if ((ia->flags & IPV6_AF_DADCOMPLETED) == 0) {
- found++;
- if (ia->dadcallback)
- ia->dadcallback(ia);
- /* We need to set this here in-case the
- * dadcallback function checks it */
- ia->flags |= IPV6_AF_DADCOMPLETED;
- }
- break;
}
}
@@ -2093,7 +2046,7 @@ valid:
}
void
-ipv6_addtempaddrs(struct interface *ifp, const struct timespec *now)
+ipv6_addtempaddrs(struct interface *ifp, struct timespec *now)
{
struct ipv6_state *state;
struct ipv6_addr *ia;
@@ -2238,7 +2191,7 @@ inet6_makeprefix(struct interface *ifp,
/* This address is the delegated prefix, so add a reject route for
* it via the loopback interface. */
- if (addr->flags & IPV6_AF_DELEGATEDPFX) {
+ if (addr->flags & IPV6_AF_PFXDELEGATION) {
struct interface *lo0;
TAILQ_FOREACH(lo0, ifp->ctx->ifaces, next) {
@@ -2258,7 +2211,7 @@ inet6_makeprefix(struct interface *ifp,
sa_in6_init(&rt->rt_dest, &addr->prefix);
ipv6_mask(&netmask, addr->prefix_len);
sa_in6_init(&rt->rt_netmask, &netmask);
- if (addr->flags & IPV6_AF_DELEGATEDPFX) {
+ if (addr->flags & IPV6_AF_PFXDELEGATION) {
rt->rt_flags |= RTF_REJECT;
/* Linux does not like a gateway for a reject route. */
#ifndef __linux__
@@ -2321,10 +2274,13 @@ inet6_raroutes(rb_tree_t *routes, struct
const struct routeinfo *rinfo;
const struct ipv6_addr *addr;
struct in6_addr netmask;
+ struct timespec now;
if (ctx->ra_routers == NULL)
return 0;
+ timespecclear(&now);
+
TAILQ_FOREACH(rap, ctx->ra_routers, next) {
if (rap->expired)
continue;
@@ -2341,10 +2297,14 @@ inet6_raroutes(rb_tree_t *routes, struct
sa_in6_init(&rt->rt_dest, &rinfo->prefix);
sa_in6_init(&rt->rt_netmask, &netmask);
sa_in6_init(&rt->rt_gateway, &rap->from);
+ rt->rt_dflags |= RTDF_RA;
#ifdef HAVE_ROUTE_PREF
rt->rt_pref = ipv6nd_rtpref(rinfo->flags);
#endif
-
+#ifdef HAVE_ROUTE_LIFETIME
+ rt->rt_lifetime = lifetime_left(rinfo->lifetime,
+ &rinfo->acquired, &now);
+#endif
rt_proto_add(routes, rt);
}
@@ -2358,6 +2318,12 @@ inet6_raroutes(rb_tree_t *routes, struct
#ifdef HAVE_ROUTE_PREF
rt->rt_pref = ipv6nd_rtpref(rap->flags);
#endif
+#ifdef HAVE_ROUTE_LIFETIME
+ rt->rt_lifetime =
+ lifetime_left(addr->prefix_vltime,
+ &addr->acquired, &now);
+#endif
+
rt_proto_add(routes, rt);
}
}
@@ -2365,6 +2331,21 @@ inet6_raroutes(rb_tree_t *routes, struct
/* add default route */
if (rap->lifetime == 0)
continue;
+ /*
+ * We only want to install a default route if we have
+ * an address that we can use over it.
+ * If we don't have any global addresses then the link-local
+ * address would be used instead and we wouldn't reach
+ * our destination and even if we could, they wouldn't
+ * be able to reply back to us.
+ * This avoids timeouts on badly configured IPv6 setups
+ * where there is a default router but it or a DHCPv6 server
+ * doesn't hand out an address.
+ * If an address appears from anywhere, dhcpcd will spot this
+ * and then add the default like.
+ * Likewise, if all global addresses are removed then dhcpcd
+ * will remove the default route.
+ */
if (ipv6_anyglobal(rap->iface) == NULL)
continue;
rt = inet6_makerouter(rap);
@@ -2374,6 +2355,11 @@ inet6_raroutes(rb_tree_t *routes, struct
#ifdef HAVE_ROUTE_PREF
rt->rt_pref = ipv6nd_rtpref(rap->flags);
#endif
+#ifdef HAVE_ROUTE_LIFETIME
+ rt->rt_lifetime = lifetime_left(rap->lifetime,
+ &rap->acquired, &now);
+#endif
+
rt_proto_add(routes, rt);
}
return 0;
@@ -2386,19 +2372,30 @@ inet6_dhcproutes(rb_tree_t *routes, stru
{
struct interface *ifp;
const struct dhcp6_state *d6_state;
- const struct ipv6_addr *addr;
+ const struct ipv6_addr *ia;
struct rt *rt;
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
d6_state = D6_CSTATE(ifp);
- if (d6_state && d6_state->state == dstate) {
- TAILQ_FOREACH(addr, &d6_state->addrs, next) {
- rt = inet6_makeprefix(ifp, NULL, addr);
- if (rt == NULL)
+ if (d6_state == NULL)
+ continue;
+
+ // Don't test the actual state as we could
+ // be between states with still valid routes
+
+ TAILQ_FOREACH(ia, &d6_state->addrs, next) {
+ if (dstate == DH6S_DELEGATED) {
+ // Reject route won't have IPV6_AF_ADDED
+ if (!(ia->flags & IPV6_AF_PFXDELEGATION))
continue;
- rt->rt_dflags |= RTDF_DHCP;
- rt_proto_add(routes, rt);
- }
+ } else if (!(ia->flags & IPV6_AF_ADDED))
+ continue;
+
+ rt = inet6_makeprefix(ifp, NULL, ia);
+ if (rt == NULL)
+ continue;
+ rt->rt_dflags |= RTDF_DHCP;
+ rt_proto_add(routes, rt);
}
}
return 0;
Index: src/external/bsd/dhcpcd/dist/src/privsep.c
diff -u src/external/bsd/dhcpcd/dist/src/privsep.c:1.19 src/external/bsd/dhcpcd/dist/src/privsep.c:1.20
--- src/external/bsd/dhcpcd/dist/src/privsep.c:1.19 Fri May 24 11:30:29 2024
+++ src/external/bsd/dhcpcd/dist/src/privsep.c Wed Feb 12 19:23:13 2025
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Privilege Separation for dhcpcd
- * Copyright (c) 2006-2023 Roy Marples <[email protected]>
+ * Copyright (c) 2006-2024 Roy Marples <[email protected]>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@@ -125,12 +125,20 @@ static int
ps_dropprivs(struct dhcpcd_ctx *ctx)
{
struct passwd *pw = ctx->ps_user;
+ int fd_out = ctx->options & DHCPCD_DUMPLEASE ?
+ STDOUT_FILENO : STDERR_FILENO;
if (ctx->options & DHCPCD_LAUNCHER)
+#ifdef ASAN
+ logwarnx("not chrooting as compiled for ASAN");
+#else
logdebugx("chrooting as %s to %s", pw->pw_name, pw->pw_dir);
+
if (chroot(pw->pw_dir) == -1 &&
(errno != EPERM || ctx->options & DHCPCD_FORKED))
logerr("%s: chroot: %s", __func__, pw->pw_dir);
+#endif
+
if (chdir("/") == -1)
logerr("%s: chdir: /", __func__);
@@ -172,7 +180,7 @@ ps_dropprivs(struct dhcpcd_ctx *ctx)
* Obviously this won't work if we are using a logfile
* or redirecting stderr to a file. */
if ((ctx->options & DHC_NOCHKIO) == DHC_NOCHKIO ||
- (ctx->logfile == NULL && isatty(STDERR_FILENO) == 1))
+ (ctx->logfile == NULL && isatty(fd_out) == 1))
{
if (setrlimit(RLIMIT_FSIZE, &rzero) == -1)
logerr("setrlimit RLIMIT_FSIZE");
@@ -1131,7 +1139,7 @@ ps_recvpsmsg(struct dhcpcd_ctx *ctx, int
len = read(fd, &psm, sizeof(psm));
#ifdef PRIVSEP_DEBUG
- logdebugx("%s: %zd", __func__, len);
+ logdebugx("%s: fd=%d %zd", __func__, fd, len);
#endif
if (len == -1 || len == 0)
Index: src/external/bsd/dhcpcd/dist/src/ipv6.h
diff -u src/external/bsd/dhcpcd/dist/src/ipv6.h:1.14 src/external/bsd/dhcpcd/dist/src/ipv6.h:1.15
--- src/external/bsd/dhcpcd/dist/src/ipv6.h:1.14 Fri Apr 21 16:54:26 2023
+++ src/external/bsd/dhcpcd/dist/src/ipv6.h Wed Feb 12 19:23:13 2025
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2023 Roy Marples <[email protected]>
+ * Copyright (c) 2006-2024 Roy Marples <[email protected]>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@@ -158,19 +158,6 @@
# define IN6_IFF_DETACHED 0
#endif
-/*
- * ND6 Advertising is only used for IP address sharing to prefer
- * the address on a specific interface.
- * This just fails to work on OpenBSD and causes erroneous duplicate
- * address messages on BSD's other then DragonFly and NetBSD.
- */
-#if !defined(SMALL) && \
- ((defined(__DragonFly_version) && __DragonFly_version >= 500703) || \
- (defined(__NetBSD_Version__) && __NetBSD_Version__ >= 899002800) || \
- defined(__linux__) || defined(__sun))
-# define ND6_ADVERTISE
-#endif
-
#ifdef INET6
TAILQ_HEAD(ipv6_addrhead, ipv6_addr);
struct ipv6_addr {
@@ -217,8 +204,8 @@ struct ipv6_addr {
#define IPV6_AF_ADDED (1U << 3)
#define IPV6_AF_AUTOCONF (1U << 4)
#define IPV6_AF_DADCOMPLETED (1U << 5)
-#define IPV6_AF_DELEGATED (1U << 6)
-#define IPV6_AF_DELEGATEDPFX (1U << 7)
+#define IPV6_AF_PFXDELEGATION (1U << 6)
+#define IPV6_AF_DELEGATED (1U << 7)
#define IPV6_AF_NOREJECT (1U << 8)
#define IPV6_AF_REQUEST (1U << 9)
#define IPV6_AF_STATIC (1U << 10)
@@ -227,8 +214,9 @@ struct ipv6_addr {
#define IPV6_AF_EXTENDED (1U << 13)
#define IPV6_AF_REGEN (1U << 14)
#define IPV6_AF_ROUTER (1U << 15)
+#define IPV6_AF_ADVERTISED (1U << 16)
#ifdef IPV6_MANAGETEMPADDR
-#define IPV6_AF_TEMPORARY (1U << 16)
+#define IPV6_AF_TEMPORARY (1U << 17)
#endif
struct ll_callback {
@@ -266,11 +254,11 @@ int ipv6_userprefix( const struct in6_ad
void ipv6_checkaddrflags(void *);
void ipv6_markaddrsstale(struct interface *, unsigned int);
void ipv6_deletestaleaddrs(struct interface *);
-int ipv6_addaddr(struct ipv6_addr *, const struct timespec *);
+int ipv6_addaddr(struct ipv6_addr *, struct timespec *);
int ipv6_doaddr(struct ipv6_addr *, struct timespec *);
ssize_t ipv6_addaddrs(struct ipv6_addrhead *addrs);
void ipv6_deleteaddr(struct ipv6_addr *);
-void ipv6_freedrop_addrs(struct ipv6_addrhead *, int,
+void ipv6_freedrop_addrs(struct ipv6_addrhead *, int, unsigned int,
const struct interface *);
void ipv6_handleifa(struct dhcpcd_ctx *ctx, int, struct if_head *,
const char *, const struct in6_addr *, uint8_t, int, pid_t);
@@ -301,7 +289,7 @@ void ipv6_freedrop(struct interface *, i
struct ipv6_addr *ipv6_createtempaddr(struct ipv6_addr *,
const struct timespec *);
struct ipv6_addr *ipv6_settemptime(struct ipv6_addr *, int);
-void ipv6_addtempaddrs(struct interface *, const struct timespec *);
+void ipv6_addtempaddrs(struct interface *, struct timespec *);
void ipv6_regentempaddrs(void *);
#endif
Index: src/external/bsd/dhcpcd/dist/src/logerr.c
diff -u src/external/bsd/dhcpcd/dist/src/logerr.c:1.14 src/external/bsd/dhcpcd/dist/src/logerr.c:1.15
--- src/external/bsd/dhcpcd/dist/src/logerr.c:1.14 Fri May 24 11:30:29 2024
+++ src/external/bsd/dhcpcd/dist/src/logerr.c Wed Feb 12 19:23:13 2025
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* logerr: errx with logging
- * Copyright (c) 2006-2023 Roy Marples <[email protected]>
+ * Copyright (c) 2006-2024 Roy Marples <[email protected]>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@@ -447,7 +447,7 @@ int
logopen(const char *path)
{
struct logctx *ctx = &_logctx;
- int opts = 0;
+ int opts = LOG_NDELAY; /* Ensure openlog gets a fd */
/* Cache timezone */
tzset();
Index: src/external/bsd/dhcpcd/dist/src/script.c
diff -u src/external/bsd/dhcpcd/dist/src/script.c:1.17 src/external/bsd/dhcpcd/dist/src/script.c:1.18
--- src/external/bsd/dhcpcd/dist/src/script.c:1.17 Thu Oct 19 11:26:52 2023
+++ src/external/bsd/dhcpcd/dist/src/script.c Wed Feb 12 19:23:13 2025
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2023 Roy Marples <[email protected]>
+ * Copyright (c) 2006-2024 Roy Marples <[email protected]>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@@ -738,6 +738,7 @@ script_dump(const char *env, size_t len)
env += 4;
printf("%s\n", env);
}
+ fflush(stdout);
return 0;
}