Module Name:    src
Committed By:   roy
Date:           Fri May 24 11:30:29 UTC 2024

Modified Files:
        src/external/bsd/dhcpcd/dist/hooks: 30-hostname
        src/external/bsd/dhcpcd/dist/src: dhcp.c dhcp6.c dhcpcd.c if-bsd.c
            if-options.c ipv6.c ipv6nd.c logerr.c privsep.c

Log Message:
Sync with dhcpcd-10.0.7


To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 src/external/bsd/dhcpcd/dist/hooks/30-hostname
cvs rdiff -u -r1.50 -r1.51 src/external/bsd/dhcpcd/dist/src/dhcp.c
cvs rdiff -u -r1.32 -r1.33 src/external/bsd/dhcpcd/dist/src/dhcp6.c
cvs rdiff -u -r1.54 -r1.55 src/external/bsd/dhcpcd/dist/src/dhcpcd.c
cvs rdiff -u -r1.30 -r1.31 src/external/bsd/dhcpcd/dist/src/if-bsd.c \
    src/external/bsd/dhcpcd/dist/src/ipv6nd.c
cvs rdiff -u -r1.36 -r1.37 src/external/bsd/dhcpcd/dist/src/if-options.c
cvs rdiff -u -r1.18 -r1.19 src/external/bsd/dhcpcd/dist/src/ipv6.c \
    src/external/bsd/dhcpcd/dist/src/privsep.c
cvs rdiff -u -r1.13 -r1.14 src/external/bsd/dhcpcd/dist/src/logerr.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/hooks/30-hostname
diff -u src/external/bsd/dhcpcd/dist/hooks/30-hostname:1.6 src/external/bsd/dhcpcd/dist/hooks/30-hostname:1.7
--- src/external/bsd/dhcpcd/dist/hooks/30-hostname:1.6	Fri Apr 21 16:54:26 2023
+++ src/external/bsd/dhcpcd/dist/hooks/30-hostname	Fri May 24 11:30:29 2024
@@ -118,7 +118,7 @@ set_hostname()
 	*)					hshort=true;;
 	esac
 
-	need_hostname || return
+	need_hostname || return 0
 
 	if [ -n "$new_fqdn" ]; then
 		if ${hfqdn} || ! ${hshort}; then

Index: src/external/bsd/dhcpcd/dist/src/dhcp.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcp.c:1.50 src/external/bsd/dhcpcd/dist/src/dhcp.c:1.51
--- src/external/bsd/dhcpcd/dist/src/dhcp.c:1.50	Mon Dec 18 15:51:28 2023
+++ src/external/bsd/dhcpcd/dist/src/dhcp.c	Fri May 24 11:30:29 2024
@@ -1877,13 +1877,13 @@ dhcp_discover(void *arg)
 	dhcp_new_xid(ifp);
 	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
 	if (!(state->added & STATE_EXPIRED)) {
-		if (ifo->fallback)
+		if (ifo->fallback && ifo->fallback_time)
 			eloop_timeout_add_sec(ifp->ctx->eloop,
-			    ifo->reboot, dhcp_fallback, ifp);
+			    ifo->fallback_time, dhcp_fallback, ifp);
 #ifdef IPV4LL
 		else if (ifo->options & DHCPCD_IPV4LL)
 			eloop_timeout_add_sec(ifp->ctx->eloop,
-			    ifo->reboot, ipv4ll_start, ifp);
+			    ifo->ipv4ll_time, ipv4ll_start, ifp);
 #endif
 	}
 	if (ifo->options & DHCPCD_REQUEST)
@@ -1914,11 +1914,13 @@ dhcp_request(void *arg)
 {
 	struct interface *ifp = arg;
 	struct dhcp_state *state = D_STATE(ifp);
+	struct if_options *ifo = ifp->options;
 
 	state->state = DHS_REQUEST;
 	// Handle the server being silent to our request.
-	eloop_timeout_add_sec(ifp->ctx->eloop, ifp->options->reboot,
-	    dhcp_requestfailed, ifp);
+	if (ifo->request_time != 0)
+		eloop_timeout_add_sec(ifp->ctx->eloop, ifo->request_time,
+		    dhcp_requestfailed, ifp);
 	send_request(ifp);
 }
 
@@ -1944,7 +1946,11 @@ dhcp_expire(void *arg)
 static void
 dhcp_decline(struct interface *ifp)
 {
+	struct dhcp_state *state = D_STATE(ifp);
 
+	// Set the expired state so we send over BPF as this could be
+	// an address defence failure.
+	state->added |= STATE_EXPIRED;
 	send_message(ifp, DHCP_DECLINE, NULL);
 }
 #endif
@@ -2098,8 +2104,12 @@ static void
 dhcp_arp_defend_failed(struct arp_state *astate)
 {
 	struct interface *ifp = astate->iface;
+	struct dhcp_state *state = D_STATE(ifp);
 
+	if (!(ifp->options->options & (DHCPCD_INFORM | DHCPCD_STATIC)))
+		dhcp_decline(ifp);
 	dhcp_drop(ifp, "EXPIRED");
+	dhcp_unlink(ifp->ctx, state->leasefile);
 	dhcp_start1(ifp);
 }
 #endif
@@ -2740,7 +2750,7 @@ dhcp_reboot(struct interface *ifp)
 	/* Need to add this before dhcp_expire and friends. */
 	if (!ifo->fallback && ifo->options & DHCPCD_IPV4LL)
 		eloop_timeout_add_sec(ifp->ctx->eloop,
-		    ifo->reboot, ipv4ll_start, ifp);
+		    ifo->ipv4ll_time, ipv4ll_start, ifp);
 #endif
 
 	if (ifo->options & DHCPCD_LASTLEASE && state->lease.frominfo)
@@ -3199,8 +3209,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 || state->state == DHS_REBOOT))
+		    DHO_IPV6_PREFERRED_ONLY) == 0 && (state->state == DHS_DISCOVER ||
+		    state->state == DHS_REBOOT || state->state == DHS_NONE))
 		{
 			char v6msg[128];
 
@@ -3524,12 +3534,6 @@ dhcp_handlebootp(struct interface *ifp, 
 {
 	size_t v;
 
-	if (len < offsetof(struct bootp, vend)) {
-		logerrx("%s: truncated packet (%zu) from %s",
-		    ifp->name, len, inet_ntoa(*from));
-		return;
-	}
-
 	/* Unlikely, but appeases sanitizers. */
 	if (len > FRAMELEN_MAX) {
 		logerrx("%s: packet exceeded frame length (%zu) from %s",
@@ -3662,6 +3666,13 @@ dhcp_recvmsg(struct dhcpcd_ctx *ctx, str
 		logerr(__func__);
 		return;
 	}
+
+	if (iov->iov_len < offsetof(struct bootp, vend)) {
+		logerrx("%s: truncated packet (%zu) from %s",
+		    ifp->name, iov->iov_len, inet_ntoa(from->sin_addr));
+		return;
+	}
+
 	state = D_CSTATE(ifp);
 	if (state == NULL) {
 		/* Try re-directing it to another interface. */

Index: src/external/bsd/dhcpcd/dist/src/dhcp6.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.32 src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.33
--- src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.32	Mon Dec 18 15:51:28 2023
+++ src/external/bsd/dhcpcd/dist/src/dhcp6.c	Fri May 24 11:30:29 2024
@@ -181,6 +181,7 @@ static void dhcp6_bind(struct interface 
 static void dhcp6_failinform(void *);
 static void dhcp6_recvaddr(void *, unsigned short);
 static void dhcp6_startdecline(struct interface *);
+static void dhcp6_startrequest(struct interface *);
 
 #ifdef SMALL
 #define dhcp6_hasprefixdelegation(a)	(0)
@@ -1428,10 +1429,37 @@ dhcp6_sendinform(void *arg)
 }
 
 static void
+dhcp6_senddiscover2(void *arg)
+{
+
+	dhcp6_sendmessage(arg, dhcp6_senddiscover2);
+}
+
+static void
+dhcp6_senddiscover1(void *arg)
+{
+	/*
+	 * So the initial RT has elapsed.
+	 * If we have any ADVERTs we can now REQUEST them.
+	 * RFC 8415 15 and 18.2.1
+	 */
+	struct interface *ifp = arg;
+	struct dhcp6_state *state = D6_STATE(ifp);
+
+	if (state->recv == NULL || state->recv->type != DHCP6_ADVERTISE)
+		dhcp6_sendmessage(arg, dhcp6_senddiscover2);
+	else
+		dhcp6_startrequest(ifp);
+}
+
+static void
 dhcp6_senddiscover(void *arg)
 {
+	struct interface *ifp = arg;
+	struct dhcp6_state *state = D6_STATE(ifp);
 
-	dhcp6_sendmessage(arg, dhcp6_senddiscover);
+	dhcp6_sendmessage(arg,
+	    state->IMD != 0 ? dhcp6_senddiscover : dhcp6_senddiscover1);
 }
 
 static void
@@ -1890,7 +1918,6 @@ dhcp6_startrebind(void *arg)
 #endif
 }
 
-
 static void
 dhcp6_startrequest(struct interface *ifp)
 {
@@ -3461,6 +3488,16 @@ dhcp6_recvif(struct interface *ifp, cons
 			valid_op = false;
 			break;
 		}
+		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 ADVERTISMENT from %s",
+			    ifp->name, sfrom);
+			return;
+		}
 		/* RFC7083 */
 		o = dhcp6_findmoption(r, len, D6_OPTION_SOL_MAX_RT, &ol);
 		if (o && ol == sizeof(uint32_t)) {
@@ -3586,7 +3623,7 @@ dhcp6_recvif(struct interface *ifp, cons
 		else
 			loginfox("%s: ADV %s from %s",
 			    ifp->name, ia->saddr, sfrom);
-		dhcp6_startrequest(ifp);
+		// We will request when the IRT elapses
 		return;
 	}
 
@@ -3791,7 +3828,7 @@ dhcp6_openraw(void)
 {
 	int fd, v;
 
-	fd = socket(PF_INET6, SOCK_RAW | SOCK_CXNB, IPPROTO_UDP);
+	fd = xsocket(PF_INET6, SOCK_RAW | SOCK_CXNB, IPPROTO_UDP);
 	if (fd == -1)
 		return -1;
 
@@ -3965,20 +4002,16 @@ dhcp6_start(struct interface *ifp, enum 
 		case DH6S_INIT:
 			goto gogogo;
 		case DH6S_INFORM:
+			/* RFC 8415 21.23
+			 * If D6_OPTION_INFO_REFRESH_TIME does not exist
+			 * then we MUST refresh by IRT_DEFAULT seconds
+			 * and should not be influenced by only the
+			 * pl/vl time of the RA changing. */
 			if (state->state == DH6S_INIT ||
-			    state->state == DH6S_INFORMED ||
 			    (state->state == DH6S_DISCOVER &&
 			    !(ifp->options->options & DHCPCD_IA_FORCED) &&
 			    !ipv6nd_hasradhcp(ifp, true)))
-			{
-				/* We don't want log spam when the RA
-				 * has just adjusted it's prefix times. */
-				if (state->state != DH6S_INFORMED) {
-					state->new_start = true;
-					state->failed = false;
-				}
 				dhcp6_startinform(ifp);
-			}
 			break;
 		case DH6S_REQUEST:
 			if (ifp->options->options & DHCPCD_DHCP6 &&
@@ -4254,6 +4287,7 @@ dhcp6_env(FILE *fp, const char *prefix, 
 #ifndef SMALL
 	const struct dhcp6_state *state;
 	const struct ipv6_addr *ap;
+	bool first;
 #endif
 
 	if (m == NULL)
@@ -4355,10 +4389,13 @@ delegated:
 		return 1;
 	if (fprintf(fp, "%s_delegated_dhcp6_prefix=", prefix) == -1)
 		return -1;
+	first = true;
 	TAILQ_FOREACH(ap, &state->addrs, next) {
 		if (ap->delegating_prefix == NULL)
 			continue;
-		if (ap != TAILQ_FIRST(&state->addrs)) {
+		if (first)
+			first = false;
+		else {
 			if (fputc(' ', fp) == EOF)
 				return -1;
 		}

Index: src/external/bsd/dhcpcd/dist/src/dhcpcd.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.54 src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.55
--- src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.54	Mon Dec 18 15:51:28 2023
+++ src/external/bsd/dhcpcd/dist/src/dhcpcd.c	Fri May 24 11:30:29 2024
@@ -401,31 +401,44 @@ dhcpcd_daemonise(struct dhcpcd_ctx *ctx)
 }
 
 static void
-dhcpcd_drop(struct interface *ifp, int stop)
+dhcpcd_drop_af(struct interface *ifp, int stop, int af)
 {
 
+	if (af == AF_UNSPEC || af == AF_INET6) {
 #ifdef DHCP6
-	dhcp6_drop(ifp, stop ? NULL : "EXPIRE6");
+		dhcp6_drop(ifp, stop ? NULL : "EXPIRE6");
 #endif
 #ifdef INET6
-	ipv6nd_drop(ifp);
-	ipv6_drop(ifp);
+		ipv6nd_drop(ifp);
+		ipv6_drop(ifp);
 #endif
+	}
+
+	if (af == AF_UNSPEC || af == AF_INET) {
 #ifdef IPV4LL
-	ipv4ll_drop(ifp);
+		ipv4ll_drop(ifp);
 #endif
 #ifdef INET
-	dhcp_drop(ifp, stop ? "STOP" : "EXPIRE");
+		dhcp_drop(ifp, stop ? "STOP" : "EXPIRE");
 #endif
 #ifdef ARP
-	arp_drop(ifp);
+		arp_drop(ifp);
+	}
 #endif
+
 #if !defined(DHCP6) && !defined(DHCP)
 	UNUSED(stop);
 #endif
 }
 
 static void
+dhcpcd_drop(struct interface *ifp, int stop)
+{
+
+	dhcpcd_drop_af(ifp, stop, AF_UNSPEC);
+}
+
+static void
 stop_interface(struct interface *ifp, const char *reason)
 {
 	struct dhcpcd_ctx *ctx;
@@ -1512,7 +1525,8 @@ dhcpcd_handleargs(struct dhcpcd_ctx *ctx
     int argc, char **argv)
 {
 	struct interface *ifp;
-	unsigned long long opts;
+	struct if_options *ifo;
+	unsigned long long opts, orig_opts;
 	int opt, oi, oifind, do_reboot, do_renew, af = AF_UNSPEC;
 	size_t len, l, nifaces;
 	char *tmp, *p;
@@ -1641,20 +1655,40 @@ dumperr:
 	}
 
 	if (opts & (DHCPCD_EXITING | DHCPCD_RELEASE)) {
-		if (oifind == argc) {
+		if (oifind == argc && af == AF_UNSPEC) {
 			stop_all_interfaces(ctx, opts);
 			eloop_exit(ctx->eloop, EXIT_SUCCESS);
 			return 0;
 		}
-		for (oi = oifind; oi < argc; oi++) {
-			if ((ifp = if_find(ctx->ifaces, argv[oi])) == NULL)
-				continue;
+
+		TAILQ_FOREACH(ifp, ctx->ifaces, next) {
 			if (!ifp->active)
 				continue;
-			ifp->options->options |= opts;
+			for (oi = oifind; oi < argc; oi++) {
+				if (strcmp(ifp->name, argv[oi]) == 0)
+					break;
+			}
+			if (oi == argc)
+				continue;
+
+			ifo = ifp->options;
+			orig_opts = ifo->options;
+			ifo->options |= opts;
 			if (opts & DHCPCD_RELEASE)
-				ifp->options->options &= ~DHCPCD_PERSISTENT;
-			stop_interface(ifp, NULL);
+				ifo->options &= ~DHCPCD_PERSISTENT;
+			switch (af) {
+			case AF_INET:
+				ifo->options &= ~DHCPCD_IPV4;
+				break;
+			case AF_INET6:
+				ifo->options &= ~DHCPCD_IPV6;
+				break;
+			}
+			if (af != AF_UNSPEC)
+				dhcpcd_drop_af(ifp, 1, af);
+			else
+				stop_interface(ifp, NULL);
+			ifo->options = orig_opts;
 		}
 		return 0;
 	}
@@ -1947,6 +1981,7 @@ main(int argc, char **argv, char **envp)
 	}
 
 	memset(&ctx, 0, sizeof(ctx));
+	closefrom(STDERR_FILENO + 1);
 
 	ifo = NULL;
 	ctx.cffile = CONFIG;
@@ -1976,7 +2011,7 @@ main(int argc, char **argv, char **envp)
 	ctx.dhcp6_wfd = -1;
 #endif
 #ifdef PRIVSEP
-	ctx.ps_log_fd = -1;
+	ctx.ps_log_fd = ctx.ps_log_root_fd = -1;
 	TAILQ_INIT(&ctx.ps_processes);
 #endif
 
@@ -2173,11 +2208,11 @@ printpidfile:
 			ctx.options |= DHCPCD_MANAGER;
 
 			/*
-			 * If we are given any interfaces, we
+			 * If we are given any interfaces or a family, we
 			 * cannot send a signal as that would impact
 			 * other interfaces.
 			 */
-			if (optind != argc)
+			if (optind != argc || family != AF_UNSPEC)
 				sig = 0;
 		}
 		if (ctx.options & DHCPCD_PRINT_PIDFILE) {
@@ -2427,9 +2462,14 @@ printpidfile:
 		goto run_loop;
 	}
 
+#ifdef DEBUG_FD
+	loginfox("forkfd %d", ctx.fork_fd);
+#endif
+
 	/* We have now forked, setsid, forked once more.
 	 * From this point on, we are the controlling daemon. */
 	logdebugx("spawned manager process on PID %d", getpid());
+
 start_manager:
 	ctx.options |= DHCPCD_STARTED;
 	if ((pid = pidfile_lock(ctx.pidfile)) != 0) {
@@ -2647,10 +2687,6 @@ exit1:
 	free(ctx.script_env);
 	rt_dispose(&ctx);
 	free(ctx.duid);
-	if (ctx.link_fd != -1) {
-		eloop_event_delete(ctx.eloop, ctx.link_fd);
-		close(ctx.link_fd);
-	}
 	if_closesockets(&ctx);
 	free_globals(&ctx);
 #ifdef INET6

Index: src/external/bsd/dhcpcd/dist/src/if-bsd.c
diff -u src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.30 src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.31
--- src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.30	Wed Jul 19 13:53:03 2023
+++ src/external/bsd/dhcpcd/dist/src/if-bsd.c	Fri May 24 11:30:29 2024
@@ -197,6 +197,18 @@ if_opensockets_os(struct dhcpcd_ctx *ctx
 	    &n, sizeof(n)) == -1)
 		logerr("%s: SO_USELOOPBACK", __func__);
 
+#ifdef PRIVSEP
+	if (ctx->options & DHCPCD_PRIVSEPROOT) {
+		/* We only want to write to this socket, so set
+		 * a small as possible buffer size. */
+		socklen_t smallbuf = 1;
+
+		if (setsockopt(ctx->link_fd, SOL_SOCKET, SO_RCVBUF,
+		    &smallbuf, (socklen_t)sizeof(smallbuf)) == -1)
+			logerr("%s: setsockopt(SO_RCVBUF)", __func__);
+	}
+#endif
+
 #if defined(RO_MSGFILTER)
 	if (setsockopt(ctx->link_fd, PF_ROUTE, RO_MSGFILTER,
 	    &msgfilter, sizeof(msgfilter)) == -1)
@@ -220,9 +232,8 @@ if_opensockets_os(struct dhcpcd_ctx *ctx
 		ps_rights_limit_fd_sockopt(ctx->link_fd);
 #endif
 
-
 #if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */
-	priv->pf_link_fd = socket(PF_LINK, SOCK_DGRAM, 0);
+	priv->pf_link_fd = xsocket(PF_LINK, SOCK_DGRAM, 0);
 	if (priv->pf_link_fd == -1)
 		logerr("%s: socket(PF_LINK)", __func__);
 #endif
@@ -235,13 +246,20 @@ if_closesockets_os(struct dhcpcd_ctx *ct
 	struct priv *priv;
 
 	priv = (struct priv *)ctx->priv;
+	if (priv == NULL)
+		return;
+
 #ifdef INET6
-	if (priv->pf_inet6_fd != -1)
+	if (priv->pf_inet6_fd != -1) {
 		close(priv->pf_inet6_fd);
+		priv->pf_inet6_fd = -1;
+	}
 #endif
 #if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */
-	if (priv->pf_link_fd != -1)
+	if (priv->pf_link_fd != -1) {
 		close(priv->pf_link_fd);
+		priv->pf_link_fd = -1;
+	}
 #endif
 	free(priv);
 	ctx->priv = NULL;
Index: src/external/bsd/dhcpcd/dist/src/ipv6nd.c
diff -u src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.30 src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.31
--- src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.30	Fri Oct  6 08:49:42 2023
+++ src/external/bsd/dhcpcd/dist/src/ipv6nd.c	Fri May 24 11:30:29 2024
@@ -71,6 +71,20 @@
 #define	ND_OPT_PI_FLAG_ROUTER	0x20	/* Router flag in PI */
 #endif
 
+#ifndef ND_OPT_RI
+#define ND_OPT_RI	24
+struct nd_opt_ri {		/* Route Information option RFC4191 */
+	uint8_t	 nd_opt_ri_type;
+	uint8_t	 nd_opt_ri_len;
+	uint8_t	 nd_opt_ri_prefixlen;
+	uint8_t	 nd_opt_ri_flags_reserved;
+	uint32_t nd_opt_ri_lifetime;
+	struct in6_addr nd_opt_ri_prefix;
+};
+__CTASSERT(sizeof(struct nd_opt_ri) == 24);
+#define OPT_RI_FLAG_PREFERENCE(flags) ((flags & 0x18) >> 3)
+#endif
+
 #ifndef ND_OPT_RDNSS
 #define ND_OPT_RDNSS			25
 struct nd_opt_rdnss {           /* RDNSS option RFC 6106 */
@@ -132,6 +146,8 @@ __CTASSERT(sizeof(struct nd_opt_dnssl) =
 //
 
 static void ipv6nd_handledata(void *, unsigned short);
+static struct routeinfo *routeinfo_findalloc(struct ra *, const struct in6_addr *, uint8_t);
+static void routeinfohead_free(struct routeinfohead *);
 
 /*
  * Android ships buggy ICMP6 filter headers.
@@ -612,10 +628,10 @@ ipv6nd_startexpire(struct interface *ifp
 }
 
 int
-ipv6nd_rtpref(struct ra *rap)
+ipv6nd_rtpref(uint8_t flags)
 {
 
-	switch (rap->flags & ND_RA_FLAG_RTPREF_MASK) {
+	switch (flags & ND_RA_FLAG_RTPREF_MASK) {
 	case ND_RA_FLAG_RTPREF_HIGH:
 		return RTPREF_HIGH;
 	case ND_RA_FLAG_RTPREF_MEDIUM:
@@ -624,7 +640,7 @@ ipv6nd_rtpref(struct ra *rap)
 	case ND_RA_FLAG_RTPREF_LOW:
 		return RTPREF_LOW;
 	default:
-		logerrx("%s: impossible RA flag %x", __func__, rap->flags);
+		logerrx("%s: impossible RA flag %x", __func__, flags);
 		return RTPREF_INVALID;
 	}
 	/* NOTREACHED */
@@ -649,7 +665,7 @@ ipv6nd_sortrouters(struct dhcpcd_ctx *ct
 				continue;
 			if (!ra1->isreachable && ra2->reachable)
 				continue;
-			if (ipv6nd_rtpref(ra1) <= ipv6nd_rtpref(ra2))
+			if (ipv6nd_rtpref(ra1->flags) <= ipv6nd_rtpref(ra2->flags))
 				continue;
 			/* All things being equal, prefer older routers. */
 			/* We don't need to check time, becase newer
@@ -827,6 +843,7 @@ ipv6nd_removefreedrop_ra(struct ra *rap,
 	if (remove_ra)
 		TAILQ_REMOVE(rap->iface->ctx->ra_routers, rap, next);
 	ipv6_freedrop_addrs(&rap->addrs, drop_ra, NULL);
+	routeinfohead_free(&rap->rinfos);
 	free(rap->data);
 	free(rap);
 }
@@ -1105,6 +1122,8 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 	struct nd_opt_prefix_info pi;
 	struct nd_opt_mtu mtu;
 	struct nd_opt_rdnss rdnss;
+	struct nd_opt_ri ri;
+	struct routeinfo *rinfo;
 	uint8_t *p;
 	struct ra *rap;
 	struct in6_addr pi_prefix;
@@ -1206,6 +1225,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 		rap->from = from->sin6_addr;
 		strlcpy(rap->sfrom, sfrom, sizeof(rap->sfrom));
 		TAILQ_INIT(&rap->addrs);
+		TAILQ_INIT(&rap->rinfos);
 		new_rap = true;
 		rap->isreachable = true;
 	} else
@@ -1237,9 +1257,6 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 	rap->flags = nd_ra->nd_ra_flags_reserved;
 	old_lifetime = rap->lifetime;
 	rap->lifetime = ntohs(nd_ra->nd_ra_router_lifetime);
-	if (!new_rap && rap->lifetime == 0 && old_lifetime != 0)
-		logwarnx("%s: %s: no longer a default router (lifetime = 0)",
-		    ifp->name, rap->sfrom);
 	if (nd_ra->nd_ra_curhoplimit != 0)
 		rap->hoplimit = nd_ra->nd_ra_curhoplimit;
 	else
@@ -1502,6 +1519,46 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 			    rdnss.nd_opt_rdnss_len > 1)
 				rap->hasdns = 1;
 			break;
+		case ND_OPT_RI:
+			if (ndo.nd_opt_len > 3) {
+				logmessage(loglevel, "%s: invalid route info option",
+				    ifp->name);
+				break;
+			}
+			memset(&ri, 0, sizeof(ri));
+			memcpy(&ri, p, olen); /* may be smaller than sizeof(ri), pad with zero */
+			if(ri.nd_opt_ri_prefixlen > 128) {
+				logmessage(loglevel, "%s: invalid route info prefix length",
+				    ifp->name);
+				break;
+			}
+
+			/* rfc4191 3.1 - RI for ::/0 applies to default route */
+			if(ri.nd_opt_ri_prefixlen == 0) {
+				rap->lifetime = ntohl(ri.nd_opt_ri_lifetime);
+
+				/* Update preference leaving other flags intact */
+				rap->flags = ((rap->flags & (~ (unsigned int)ND_RA_FLAG_RTPREF_MASK))
+					| ri.nd_opt_ri_flags_reserved) & 0xff;
+
+				break;
+			}
+
+			/* Update existing route info instead of rebuilding all routes so that
+			previously announced but now absent routes can stay alive.  To kill a
+			route early, an RI with lifetime=0 needs to be received (rfc4191 3.1)*/
+			rinfo = routeinfo_findalloc(rap, &ri.nd_opt_ri_prefix, ri.nd_opt_ri_prefixlen);
+			if(rinfo == NULL) {
+				logerr(__func__);
+				break;
+			}
+
+			/* Update/initialize other route info params */
+			rinfo->flags = ri.nd_opt_ri_flags_reserved;
+			rinfo->lifetime = ntohl(ri.nd_opt_ri_lifetime);
+			rinfo->acquired = rap->acquired;
+
+			break;
 		default:
 			continue;
 		}
@@ -1537,6 +1594,10 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 		ia->prefix_pltime = 0;
 	}
 
+	if (!new_rap && rap->lifetime == 0 && old_lifetime != 0)
+		logwarnx("%s: %s: no longer a default router (lifetime = 0)",
+		    ifp->name, rap->sfrom);
+
 	if (new_data && !has_address && rap->lifetime && !ipv6_anyglobal(ifp))
 		logwarnx("%s: no global addresses for default route",
 		    ifp->name);
@@ -1699,7 +1760,7 @@ ipv6nd_env(FILE *fp, const struct interf
 			return -1;
 		if (efprintf(fp, "%s_hoplimit=%u", ndprefix, rap->hoplimit) == -1)
 			return -1;
-		pref = ipv6nd_rtpref(rap);
+		pref = ipv6nd_rtpref(rap->flags);
 		if (efprintf(fp, "%s_flags=%s%s%s%s%s", ndprefix,
 		    rap->flags & ND_RA_FLAG_MANAGED    ? "M" : "",
 		    rap->flags & ND_RA_FLAG_OTHER      ? "O" : "",
@@ -1804,6 +1865,7 @@ ipv6nd_expirera(void *arg)
 	uint32_t elapsed;
 	bool expired, valid;
 	struct ipv6_addr *ia;
+	struct routeinfo *rinfo, *rinfob;
 	size_t len, olen;
 	uint8_t *p;
 	struct nd_opt_hdr ndo;
@@ -1823,7 +1885,8 @@ ipv6nd_expirera(void *arg)
 		if (rap->iface != ifp || rap->expired)
 			continue;
 		valid = false;
-		if (rap->lifetime) {
+		/* 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) {
@@ -1879,6 +1942,20 @@ 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) {
+				logwarnx("%s: expired route %s",
+				    rap->iface->name, rinfo->sprefix);
+				TAILQ_REMOVE(&rap->rinfos, rinfo, next);
+			}
+		}
+
 		/* Work out expiry for ND options */
 		elapsed = (uint32_t)eloop_timespec_diff(&now,
 		    &rap->acquired, NULL);
@@ -2135,3 +2212,43 @@ ipv6nd_startrs(struct interface *ifp)
 	eloop_timeout_add_msec(ifp->ctx->eloop, delay, ipv6nd_startrs1, ifp);
 	return;
 }
+
+static struct routeinfo *routeinfo_findalloc(struct ra *rap, const struct in6_addr *prefix, uint8_t prefix_len)
+{
+	struct routeinfo *ri;
+	char buf[INET6_ADDRSTRLEN];
+	const char *p;
+
+	TAILQ_FOREACH(ri, &rap->rinfos, next) {
+		if (ri->prefix_len == prefix_len &&
+		    IN6_ARE_ADDR_EQUAL(&ri->prefix, prefix))
+			return ri;
+	}
+
+	ri = malloc(sizeof(struct routeinfo));
+	if (ri == NULL)
+		return NULL;
+
+	memcpy(&ri->prefix, prefix, sizeof(ri->prefix));
+	ri->prefix_len = prefix_len;
+	p = inet_ntop(AF_INET6, prefix, buf, sizeof(buf));
+	if (p)
+		snprintf(ri->sprefix,
+			sizeof(ri->sprefix),
+			"%s/%d",
+			p, prefix_len);
+	else
+		ri->sprefix[0] = '\0';
+	TAILQ_INSERT_TAIL(&rap->rinfos, ri, next);
+	return ri;
+}
+
+static void routeinfohead_free(struct routeinfohead *head)
+{
+	struct routeinfo *ri;
+
+	while ((ri = TAILQ_FIRST(head))) {
+		TAILQ_REMOVE(head, ri, next);
+		free(ri);
+	}
+}

Index: src/external/bsd/dhcpcd/dist/src/if-options.c
diff -u src/external/bsd/dhcpcd/dist/src/if-options.c:1.36 src/external/bsd/dhcpcd/dist/src/if-options.c:1.37
--- src/external/bsd/dhcpcd/dist/src/if-options.c:1.36	Mon Dec 18 15:51:28 2023
+++ src/external/bsd/dhcpcd/dist/src/if-options.c	Fri May 24 11:30:29 2024
@@ -168,6 +168,10 @@ const struct option cf_options[] = {
 	{"link_rcvbuf",     required_argument, NULL, O_LINK_RCVBUF},
 	{"configure",       no_argument,       NULL, O_CONFIGURE},
 	{"noconfigure",     no_argument,       NULL, O_NOCONFIGURE},
+	{"arp_persistdefence", no_argument,    NULL, O_ARP_PERSISTDEFENCE},
+	{"request_time",    required_argument, NULL, O_REQUEST_TIME},
+	{"fallback_time",   required_argument, NULL, O_FALLBACK_TIME},
+	{"ipv4ll_time",     required_argument, NULL, O_IPV4LL_TIME},
 	{NULL,              0,                 NULL, '\0'}
 };
 
@@ -2337,6 +2341,38 @@ invalid_token:
 	case O_NOCONFIGURE:
 		ifo->options &= ~DHCPCD_CONFIGURE;
 		break;
+	case O_ARP_PERSISTDEFENCE:
+		ifo->options |= DHCPCD_ARP_PERSISTDEFENCE;
+		break;
+	case O_REQUEST_TIME:
+		ARG_REQUIRED;
+		ifo->request_time =
+		    (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
+		if (e) {
+			logerrx("invalid request time: %s", arg);
+			return -1;
+		}
+		break;
+#ifdef INET
+	case O_FALLBACK_TIME:
+		ARG_REQUIRED;
+		ifo->request_time =
+		    (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
+		if (e) {
+			logerrx("invalid fallback time: %s", arg);
+			return -1;
+		}
+		break;
+	case O_IPV4LL_TIME:
+		ARG_REQUIRED;
+		ifo->ipv4ll_time =
+		    (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
+		if (e) {
+			logerrx("invalid ipv4ll time: %s", arg);
+			return -1;
+		}
+		break;
+#endif
 	default:
 		return 0;
 	}
@@ -2420,6 +2456,11 @@ default_config(struct dhcpcd_ctx *ctx)
 	ifo->options |= DHCPCD_IF_UP | DHCPCD_LINK | DHCPCD_INITIAL_DELAY;
 	ifo->timeout = DEFAULT_TIMEOUT;
 	ifo->reboot = DEFAULT_REBOOT;
+	ifo->request_time = DEFAULT_REQUEST;
+#ifdef INET
+	ifo->fallback_time = DEFAULT_FALLBACK;
+	ifo->ipv4ll_time = DEFAULT_IPV4LL;
+#endif
 	ifo->metric = -1;
 	ifo->auth.options |= DHCPCD_AUTH_REQUIRE;
 	rb_tree_init(&ifo->routes, &rt_compare_list_ops);
@@ -2461,7 +2502,7 @@ read_config(struct dhcpcd_ctx *ctx,
 		default_options |= DHCPCD_CONFIGURE | DHCPCD_DAEMONISE |
 		    DHCPCD_GATEWAY;
 #ifdef INET
-		skip = socket(PF_INET, SOCK_DGRAM, 0);
+		skip = xsocket(PF_INET, SOCK_DGRAM, 0);
 		if (skip != -1) {
 			close(skip);
 			default_options |= DHCPCD_IPV4 | DHCPCD_ARP |
@@ -2469,7 +2510,7 @@ read_config(struct dhcpcd_ctx *ctx,
 		}
 #endif
 #ifdef INET6
-		skip = socket(PF_INET6, SOCK_DGRAM, 0);
+		skip = xsocket(PF_INET6, SOCK_DGRAM, 0);
 		if (skip != -1) {
 			close(skip);
 			default_options |= DHCPCD_IPV6 | DHCPCD_IPV6RS |

Index: src/external/bsd/dhcpcd/dist/src/ipv6.c
diff -u src/external/bsd/dhcpcd/dist/src/ipv6.c:1.18 src/external/bsd/dhcpcd/dist/src/ipv6.c:1.19
--- src/external/bsd/dhcpcd/dist/src/ipv6.c:1.18	Fri Apr 21 16:54:26 2023
+++ src/external/bsd/dhcpcd/dist/src/ipv6.c	Fri May 24 11:30:29 2024
@@ -2318,7 +2318,9 @@ inet6_raroutes(rb_tree_t *routes, struct
 {
 	struct rt *rt;
 	struct ra *rap;
+	const struct routeinfo *rinfo;
 	const struct ipv6_addr *addr;
+	struct in6_addr netmask;
 
 	if (ctx->ra_routers == NULL)
 		return 0;
@@ -2326,6 +2328,27 @@ inet6_raroutes(rb_tree_t *routes, struct
 	TAILQ_FOREACH(rap, ctx->ra_routers, next) {
 		if (rap->expired)
 			continue;
+
+		/* add rfc4191 route information routes */
+		TAILQ_FOREACH (rinfo, &rap->rinfos, next) {
+			if(rinfo->lifetime == 0)
+				continue;
+			if ((rt = inet6_makeroute(rap->iface, rap)) == NULL)
+				continue;
+
+			in6_addr_fromprefix(&netmask, rinfo->prefix_len);
+
+			sa_in6_init(&rt->rt_dest, &rinfo->prefix);
+			sa_in6_init(&rt->rt_netmask, &netmask);
+			sa_in6_init(&rt->rt_gateway, &rap->from);
+#ifdef HAVE_ROUTE_PREF
+			rt->rt_pref = ipv6nd_rtpref(rinfo->flags);
+#endif
+
+			rt_proto_add(routes, rt);
+		}
+
+		/* add subnet routes */
 		TAILQ_FOREACH(addr, &rap->addrs, next) {
 			if (addr->prefix_vltime == 0)
 				continue;
@@ -2333,11 +2356,13 @@ inet6_raroutes(rb_tree_t *routes, struct
 			if (rt) {
 				rt->rt_dflags |= RTDF_RA;
 #ifdef HAVE_ROUTE_PREF
-				rt->rt_pref = ipv6nd_rtpref(rap);
+				rt->rt_pref = ipv6nd_rtpref(rap->flags);
 #endif
 				rt_proto_add(routes, rt);
 			}
 		}
+
+		/* add default route */
 		if (rap->lifetime == 0)
 			continue;
 		if (ipv6_anyglobal(rap->iface) == NULL)
@@ -2347,7 +2372,7 @@ inet6_raroutes(rb_tree_t *routes, struct
 			continue;
 		rt->rt_dflags |= RTDF_RA;
 #ifdef HAVE_ROUTE_PREF
-		rt->rt_pref = ipv6nd_rtpref(rap);
+		rt->rt_pref = ipv6nd_rtpref(rap->flags);
 #endif
 		rt_proto_add(routes, rt);
 	}
Index: src/external/bsd/dhcpcd/dist/src/privsep.c
diff -u src/external/bsd/dhcpcd/dist/src/privsep.c:1.18 src/external/bsd/dhcpcd/dist/src/privsep.c:1.19
--- src/external/bsd/dhcpcd/dist/src/privsep.c:1.18	Mon Dec 18 15:51:28 2023
+++ src/external/bsd/dhcpcd/dist/src/privsep.c	Fri May 24 11:30:29 2024
@@ -408,15 +408,23 @@ ps_startprocess(struct ps_process *psp,
 		return pid;
 	}
 
+	/* If we are not the root process, close un-needed stuff. */
+	if (ctx->ps_root != psp) {
+		ps_root_close(ctx);
 #ifdef PLUGIN_DEV
-	/* If we are not the root process, stop listening to devices. */
-	if (ctx->ps_root != psp)
 		dev_stop(ctx);
 #endif
+	}
 
 	ctx->options |= DHCPCD_FORKED;
 	if (ctx->ps_log_fd != -1)
 		logsetfd(ctx->ps_log_fd);
+
+#ifdef DEBUG_FD
+	logerrx("pid %d log_fd=%d data_fd=%d psp_fd=%d",
+	    getpid(), ctx->ps_log_fd, ctx->ps_data_fd, psp->psp_fd);
+#endif
+
 	eloop_clear(ctx->eloop, -1);
 	eloop_forked(ctx->eloop);
 	eloop_signal_set_cb(ctx->eloop,
@@ -459,18 +467,6 @@ ps_startprocess(struct ps_process *psp,
 #endif
 	}
 
-	if (ctx->ps_inet != psp)
-		ctx->ps_inet = NULL;
-	if (ctx->ps_ctl != psp)
-		ctx->ps_ctl = NULL;
-
-#if 0
-	char buf[1024];
-	errno = 0;
-	ssize_t xx = recv(psp->psp_fd, buf, sizeof(buf), MSG_PEEK);
-	logerr("pid %d test fd %d recv peek %zd", getpid(), psp->psp_fd, xx);
-#endif
-
 	if (eloop_event_add(ctx->eloop, psp->psp_fd, ELE_READ,
 	    recv_msg, psp) == -1)
 	{
@@ -1215,6 +1211,7 @@ ps_newprocess(struct dhcpcd_ctx *ctx, st
 		return NULL;
 	psp->psp_ctx = ctx;
 	memcpy(&psp->psp_id, psid, sizeof(psp->psp_id));
+	psp->psp_fd = -1;
 	psp->psp_work_fd = -1;
 #ifdef HAVE_CAPSICUM
 	psp->psp_pfd = -1;

Index: src/external/bsd/dhcpcd/dist/src/logerr.c
diff -u src/external/bsd/dhcpcd/dist/src/logerr.c:1.13 src/external/bsd/dhcpcd/dist/src/logerr.c:1.14
--- src/external/bsd/dhcpcd/dist/src/logerr.c:1.13	Fri Apr 21 16:54:26 2023
+++ src/external/bsd/dhcpcd/dist/src/logerr.c	Fri May 24 11:30:29 2024
@@ -376,6 +376,8 @@ logsetfd(int fd)
 	struct logctx *ctx = &_logctx;
 
 	ctx->log_fd = fd;
+	if (fd != -1)
+		closelog();
 #ifndef SMALL
 	if (fd != -1 && ctx->log_file != NULL) {
 		fclose(ctx->log_file);

Reply via email to