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);