Module Name: src Committed By: roy Date: Fri Apr 21 16:54:26 UTC 2023
Modified Files: src/external/bsd/dhcpcd/dist/hooks: 20-resolv.conf 29-lookup-hostname 30-hostname 50-ntp.conf 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: Merge changes To generate a diff of this commit: cvs rdiff -u -r1.6 -r1.7 src/external/bsd/dhcpcd/dist/hooks/20-resolv.conf cvs rdiff -u -r1.2 -r1.3 \ src/external/bsd/dhcpcd/dist/hooks/29-lookup-hostname cvs rdiff -u -r1.5 -r1.6 src/external/bsd/dhcpcd/dist/hooks/30-hostname \ src/external/bsd/dhcpcd/dist/hooks/50-ntp.conf cvs rdiff -u -r1.18 -r1.19 src/external/bsd/dhcpcd/dist/src/bpf.c cvs rdiff -u -r1.46 -r1.47 src/external/bsd/dhcpcd/dist/src/dhcp.c cvs rdiff -u -r1.28 -r1.29 src/external/bsd/dhcpcd/dist/src/dhcp6.c \ src/external/bsd/dhcpcd/dist/src/ipv6nd.c cvs rdiff -u -r1.49 -r1.50 src/external/bsd/dhcpcd/dist/src/dhcpcd.c cvs rdiff -u -r1.27 -r1.28 src/external/bsd/dhcpcd/dist/src/if-bsd.c cvs rdiff -u -r1.32 -r1.33 src/external/bsd/dhcpcd/dist/src/if-options.c cvs rdiff -u -r1.17 -r1.18 src/external/bsd/dhcpcd/dist/src/ipv6.c cvs rdiff -u -r1.13 -r1.14 src/external/bsd/dhcpcd/dist/src/ipv6.h \ src/external/bsd/dhcpcd/dist/src/privsep.c cvs rdiff -u -r1.12 -r1.13 src/external/bsd/dhcpcd/dist/src/logerr.c cvs rdiff -u -r1.14 -r1.15 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/hooks/20-resolv.conf diff -u src/external/bsd/dhcpcd/dist/hooks/20-resolv.conf:1.6 src/external/bsd/dhcpcd/dist/hooks/20-resolv.conf:1.7 --- src/external/bsd/dhcpcd/dist/hooks/20-resolv.conf:1.6 Mon Dec 28 13:57:40 2020 +++ src/external/bsd/dhcpcd/dist/hooks/20-resolv.conf Fri Apr 21 16:54:26 2023 @@ -11,7 +11,7 @@ nocarrier_roaming_dir="$state_dir/roamin NL=" " : ${resolvconf:=resolvconf} -if type "$resolvconf" >/dev/null 2>&1; then +if command -v "$resolvconf" >/dev/null 2>&1; then have_resolvconf=true else have_resolvconf=false Index: src/external/bsd/dhcpcd/dist/hooks/29-lookup-hostname diff -u src/external/bsd/dhcpcd/dist/hooks/29-lookup-hostname:1.2 src/external/bsd/dhcpcd/dist/hooks/29-lookup-hostname:1.3 --- src/external/bsd/dhcpcd/dist/hooks/29-lookup-hostname:1.2 Sat Sep 22 13:17:46 2018 +++ src/external/bsd/dhcpcd/dist/hooks/29-lookup-hostname Fri Apr 21 16:54:26 2023 @@ -4,20 +4,20 @@ lookup_hostname() { [ -z "$new_ip_address" ] && return 1 # Silly ISC programs love to send error text to stdout - if type dig >/dev/null 2>&1; then + if command -v dig >/dev/null 2>&1; then h=$(dig +short -x $new_ip_address) if [ $? = 0 ]; then echo "$h" | sed 's/\.$//' return 0 fi - elif type host >/dev/null 2>&1; then + elif command -v host >/dev/null 2>&1; then h=$(host $new_ip_address) if [ $? = 0 ]; then echo "$h" \ | sed 's/.* domain name pointer \(.*\)./\1/' return 0 fi - elif type getent >/dev/null 2>&1; then + elif command -v getent >/dev/null 2>&1; then h=$(getent hosts $new_ip_address) if [ $? = 0 ]; then echo "$h" | sed 's/[^ ]* *\([^ ]*\).*/\1/' Index: src/external/bsd/dhcpcd/dist/hooks/30-hostname diff -u src/external/bsd/dhcpcd/dist/hooks/30-hostname:1.5 src/external/bsd/dhcpcd/dist/hooks/30-hostname:1.6 --- src/external/bsd/dhcpcd/dist/hooks/30-hostname:1.5 Fri Oct 22 13:23:20 2021 +++ src/external/bsd/dhcpcd/dist/hooks/30-hostname Fri Apr 21 16:54:26 2023 @@ -25,7 +25,7 @@ _hostname() if [ -z "${1+x}" ]; then if [ -r /proc/sys/kernel/hostname ]; then read name </proc/sys/kernel/hostname && echo "$name" - elif type hostname >/dev/null 2>/dev/null; then + elif command -v hostname >/dev/null 2>/dev/null; then hostname elif sysctl kern.hostname >/dev/null 2>&1; then sysctl -n kern.hostname @@ -39,7 +39,7 @@ _hostname() if [ -w /proc/sys/kernel/hostname ]; then echo "$1" >/proc/sys/kernel/hostname - elif [ -n "$1" ] && type hostname >/dev/null 2>&1; then + elif [ -n "$1" ] && command -v hostname >/dev/null 2>&1; then hostname "$1" elif sysctl kern.hostname >/dev/null 2>&1; then sysctl -w "kern.hostname=$1" >/dev/null Index: src/external/bsd/dhcpcd/dist/hooks/50-ntp.conf diff -u src/external/bsd/dhcpcd/dist/hooks/50-ntp.conf:1.5 src/external/bsd/dhcpcd/dist/hooks/50-ntp.conf:1.6 --- src/external/bsd/dhcpcd/dist/hooks/50-ntp.conf:1.5 Fri Nov 20 13:24:58 2020 +++ src/external/bsd/dhcpcd/dist/hooks/50-ntp.conf Fri Apr 21 16:54:26 2023 @@ -43,7 +43,7 @@ fi # Debian has a separate file for DHCP config to avoid stamping on # the master. -if [ "$ntp_service" = ntpd ] && type invoke-rc.d >/dev/null 2>&1; then +if [ "$ntp_service" = ntpd ] && command -v invoke-rc.d >/dev/null 2>&1; then [ -e /var/lib/ntp ] || mkdir /var/lib/ntp : ${ntp_service:=ntp} : ${NTP_DHCP_CONF:=/var/lib/ntp/ntp.conf.dhcp} @@ -113,7 +113,7 @@ add_ntp_conf() [ -e "$cf" ] && rm "$cf" [ -d "$ntp_conf_dir" ] || mkdir -p "$ntp_conf_dir" if [ -n "$new_ntp_servers" ]; then - for x in $new_ntp_servers; do + for x in $(uniqify $new_ntp_servers); do echo "server $x" >> "$cf" done fi @@ -131,7 +131,7 @@ remove_ntp_conf() # For ease of use, map DHCP6 names onto our DHCP4 names case "$reason" in BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6) - new_ntp_servers="$new_dhcp6_sntp_servers" + new_ntp_servers="$new_dhcp6_sntp_servers $new_dhcp6_ntp_server_addr $new_dhcp6_ntp_server_fqdn" ;; esac Index: src/external/bsd/dhcpcd/dist/src/bpf.c diff -u src/external/bsd/dhcpcd/dist/src/bpf.c:1.18 src/external/bsd/dhcpcd/dist/src/bpf.c:1.19 --- src/external/bsd/dhcpcd/dist/src/bpf.c:1.18 Fri Oct 22 13:23:20 2021 +++ src/external/bsd/dhcpcd/dist/src/bpf.c Fri Apr 21 16:54:26 2023 @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-2-Clause */ /* * dhcpcd: BPF arp and bootp filtering - * Copyright (c) 2006-2021 Roy Marples <r...@marples.name> + * Copyright (c) 2006-2023 Roy Marples <r...@marples.name> * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -45,7 +45,6 @@ #include <errno.h> #include <fcntl.h> -#include <paths.h> #include <stddef.h> #include <stdlib.h> #include <string.h> @@ -155,6 +154,11 @@ bpf_open(const struct interface *ifp, struct bpf_version pv = { .bv_major = 0, .bv_minor = 0 }; struct ifreq ifr = { .ifr_flags = 0 }; int ibuf_len = 0; +#ifdef O_CLOEXEC +#define BPF_OPEN_FLAGS O_RDWR | O_NONBLOCK | O_CLOEXEC +#else +#define BPF_OPEN_FLAGS O_RDWR | O_NONBLOCK +#endif #ifdef BIOCIMMEDIATE unsigned int flags; #endif @@ -167,25 +171,19 @@ bpf_open(const struct interface *ifp, return NULL; bpf->bpf_ifp = ifp; -#ifdef _PATH_BPF - bpf->bpf_fd = open(_PATH_BPF, O_RDWR | O_NONBLOCK -#ifdef O_CLOEXEC - | O_CLOEXEC -#endif - ); -#else - char device[32]; - int n = 0; + /* /dev/bpf is a cloner on modern kernels */ + bpf->bpf_fd = open("/dev/bpf", BPF_OPEN_FLAGS); - do { - snprintf(device, sizeof(device), "/dev/bpf%d", n++); - bpf->bpf_fd = open(device, O_RDWR | O_NONBLOCK -#ifdef O_CLOEXEC - | O_CLOEXEC -#endif - ); - } while (bpf->bpf_fd == -1 && errno == EBUSY); -#endif + /* Support older kernels where /dev/bpf is not a cloner */ + if (bpf->bpf_fd == -1) { + char device[32]; + int n = 0; + + do { + snprintf(device, sizeof(device), "/dev/bpf%d", n++); + bpf->bpf_fd = open(device, BPF_OPEN_FLAGS); + } while (bpf->bpf_fd == -1 && errno == EBUSY); + } if (bpf->bpf_fd == -1) goto eexit; Index: src/external/bsd/dhcpcd/dist/src/dhcp.c diff -u src/external/bsd/dhcpcd/dist/src/dhcp.c:1.46 src/external/bsd/dhcpcd/dist/src/dhcp.c:1.47 --- src/external/bsd/dhcpcd/dist/src/dhcp.c:1.46 Fri Oct 22 13:23:20 2021 +++ src/external/bsd/dhcpcd/dist/src/dhcp.c Fri Apr 21 16:54:26 2023 @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-2-Clause */ /* * dhcpcd - DHCP client daemon - * Copyright (c) 2006-2021 Roy Marples <r...@marples.name> + * Copyright (c) 2006-2023 Roy Marples <r...@marples.name> * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -84,11 +84,6 @@ /* We should define a maximum for the NAK exponential backoff */ #define NAKOFF_MAX 60 -/* Wait N nanoseconds between sending a RELEASE and dropping the address. - * This gives the kernel enough time to actually send it. */ -#define RELEASE_DELAY_S 0 -#define RELEASE_DELAY_NS 10000000 - #ifndef IPDEFTTL #define IPDEFTTL 64 /* RFC1340 */ #endif @@ -137,7 +132,7 @@ static void dhcp_arp_found(struct arp_st #endif static void dhcp_handledhcp(struct interface *, struct bootp *, size_t, const struct in_addr *); -static void dhcp_handleifudp(void *); +static void dhcp_handleifudp(void *, unsigned short); static int dhcp_initstate(struct interface *); void @@ -400,7 +395,7 @@ print_rfc3442(FILE *fp, const uint8_t *d static int decode_rfc3442_rt(rb_tree_t *routes, struct interface *ifp, - const uint8_t *data, size_t dl, const struct bootp *bootp) + const uint8_t *data, size_t dl) { const uint8_t *p = data; const uint8_t *e; @@ -447,15 +442,6 @@ decode_rfc3442_rt(rb_tree_t *routes, str memcpy(&gateway.s_addr, p, 4); p += 4; - /* An on-link host route is normally set by having the - * gateway match the destination or assigned address */ - if (gateway.s_addr == dest.s_addr || - (gateway.s_addr == bootp->yiaddr || - gateway.s_addr == bootp->ciaddr)) - { - gateway.s_addr = INADDR_ANY; - netmask.s_addr = INADDR_BROADCAST; - } if (netmask.s_addr == INADDR_BROADCAST) rt->rt_flags = RTF_HOST; @@ -594,7 +580,7 @@ get_option_routes(rb_tree_t *routes, str if (p) csr = "MS "; } - if (p && (n = decode_rfc3442_rt(routes, ifp, p, len, bootp)) != -1) { + if (p && (n = decode_rfc3442_rt(routes, ifp, p, len)) != -1) { const struct dhcp_state *state; state = D_CSTATE(ifp); @@ -782,7 +768,7 @@ make_message(struct bootp **bootpm, cons bootp->op = BOOTREQUEST; bootp->htype = (uint8_t)ifp->hwtype; - if (ifp->hwlen != 0 && ifp->hwlen < sizeof(bootp->chaddr)) { + if (ifp->hwlen != 0 && ifp->hwlen <= sizeof(bootp->chaddr)) { bootp->hlen = (uint8_t)ifp->hwlen; memcpy(&bootp->chaddr, &ifp->hwaddr, ifp->hwlen); } @@ -2005,7 +1991,7 @@ dhcp_finish_dad(struct interface *ifp, s { struct dhcp_state *state = D_STATE(ifp); - if (state->state != DHS_PROBE) + if (state->state == DHS_BOUND) return; if (state->offer == NULL || state->offer->yiaddr != ia->s_addr) return; @@ -2407,7 +2393,9 @@ openudp: dhcp_openbpf(ifp); return; } - eloop_event_add(ctx->eloop, state->udp_rfd, dhcp_handleifudp, ifp); + if (eloop_event_add(ctx->eloop, state->udp_rfd, ELE_READ, + dhcp_handleifudp, ifp) == -1) + logerr("%s: eloop_event_add", __func__); } static size_t @@ -2753,12 +2741,8 @@ dhcp_reboot(struct interface *ifp) void dhcp_drop(struct interface *ifp, const char *reason) { - struct dhcp_state *state; -#ifdef RELEASE_SLOW - struct timespec ts; -#endif + struct dhcp_state *state = D_STATE(ifp); - state = D_STATE(ifp); /* dhcp_start may just have been called and we don't yet have a state * but we do have a timeout, so punt it. */ if (state == NULL || state->state == DHS_NONE) { @@ -2792,12 +2776,6 @@ dhcp_drop(struct interface *ifp, const c ifp->name, inet_ntoa(state->lease.addr)); dhcp_new_xid(ifp); send_message(ifp, DHCP_RELEASE, NULL); -#ifdef RELEASE_SLOW - /* Give the packet a chance to go */ - ts.tv_sec = RELEASE_DELAY_S; - ts.tv_nsec = RELEASE_DELAY_NS; - nanosleep(&ts, NULL); -#endif } } #ifdef AUTH @@ -2818,10 +2796,6 @@ dhcp_drop(struct interface *ifp, const c dhcp_auth_reset(&state->auth); #endif - /* Close DHCP ports so a changed interface family is picked - * up by a new BPF state. */ - dhcp_close(ifp); - state->state = DHS_NONE; free(state->offer); state->offer = NULL; @@ -2845,6 +2819,10 @@ dhcp_drop(struct interface *ifp, const c state->lease.addr.s_addr = 0; ifp->options->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. */ + dhcp_close(ifp); } static int @@ -3623,7 +3601,7 @@ dhcp_packet(struct interface *ifp, uint8 } static void -dhcp_readbpf(void *arg) +dhcp_readbpf(void *arg, unsigned short events) { struct interface *ifp = arg; uint8_t buf[FRAMELEN_MAX]; @@ -3631,6 +3609,9 @@ dhcp_readbpf(void *arg) struct dhcp_state *state = D_STATE(ifp); struct bpf *bpf = state->bpf; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + bpf->bpf_flags &= ~BPF_EOF; while (!(bpf->bpf_flags & BPF_EOF)) { bytes = bpf_read(bpf, buf, sizeof(buf)); @@ -3694,7 +3675,8 @@ dhcp_recvmsg(struct dhcpcd_ctx *ctx, str } static void -dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp) +dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp, + unsigned short events) { const struct dhcp_state *state; struct sockaddr_in from; @@ -3722,6 +3704,9 @@ dhcp_readudp(struct dhcpcd_ctx *ctx, str int s; ssize_t bytes; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + if (ifp != NULL) { state = D_CSTATE(ifp); s = state->udp_rfd; @@ -3739,19 +3724,19 @@ dhcp_readudp(struct dhcpcd_ctx *ctx, str } static void -dhcp_handleudp(void *arg) +dhcp_handleudp(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; - dhcp_readudp(ctx, NULL); + dhcp_readudp(ctx, NULL, events); } static void -dhcp_handleifudp(void *arg) +dhcp_handleifudp(void *arg, unsigned short events) { struct interface *ifp = arg; - dhcp_readudp(ifp->ctx, ifp); + dhcp_readudp(ifp->ctx, ifp, events); } static int @@ -3786,8 +3771,9 @@ dhcp_openbpf(struct interface *ifp) return -1; } - eloop_event_add(ifp->ctx->eloop, - state->bpf->bpf_fd, dhcp_readbpf, ifp); + if (eloop_event_add(ifp->ctx->eloop, state->bpf->bpf_fd, ELE_READ, + dhcp_readbpf, ifp) == -1) + logerr("%s: eloop_event_add", __func__); return 0; } @@ -3833,6 +3819,7 @@ dhcp_free(struct interface *ifp) free(ctx->opt_buffer); ctx->opt_buffer = NULL; + ctx->opt_buffer_len = 0; } } @@ -3963,7 +3950,9 @@ dhcp_start1(void *arg) logerr(__func__); return; } - eloop_event_add(ctx->eloop, ctx->udp_rfd, dhcp_handleudp, ctx); + if (eloop_event_add(ctx->eloop, ctx->udp_rfd, ELE_READ, + dhcp_handleudp, ctx) == -1) + logerr("%s: eloop_event_add", __func__); } if (!IN_PRIVSEP(ctx) && ctx->udp_wfd == -1) { ctx->udp_wfd = xsocket(PF_INET, SOCK_RAW|SOCK_CXNB,IPPROTO_UDP); Index: src/external/bsd/dhcpcd/dist/src/dhcp6.c diff -u src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.28 src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.29 --- src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.28 Fri Oct 22 13:23:20 2021 +++ src/external/bsd/dhcpcd/dist/src/dhcp6.c Fri Apr 21 16:54:26 2023 @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-2-Clause */ /* * dhcpcd - DHCP client daemon - * Copyright (c) 2006-2021 Roy Marples <r...@marples.name> + * Copyright (c) 2006-2023 Roy Marples <r...@marples.name> * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -147,12 +147,18 @@ struct dhcp_compat { uint16_t dhcp6_opt; }; +/* + * RFC 5908 deprecates OPTION_SNTP_SERVERS. + * But we can support both as the hook scripts will uniqify the + * results if the server returns both options. + */ static const struct dhcp_compat dhcp_compats[] = { { DHO_DNSSERVER, D6_OPTION_DNS_SERVERS }, { DHO_HOSTNAME, D6_OPTION_FQDN }, { DHO_DNSDOMAIN, D6_OPTION_FQDN }, { DHO_NISSERVER, D6_OPTION_NIS_SERVERS }, { DHO_NTPSERVER, D6_OPTION_SNTP_SERVERS }, + { DHO_NTPSERVER, D6_OPTION_NTP_SERVER }, { DHO_RAPIDCOMMIT, D6_OPTION_RAPID_COMMIT }, { DHO_FQDN, D6_OPTION_FQDN }, { DHO_VIVCO, D6_OPTION_VENDOR_CLASS }, @@ -173,7 +179,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_recvaddr(void *); +static void dhcp6_recvaddr(void *, unsigned short); static void dhcp6_startdecline(struct interface *); #ifdef SMALL @@ -962,6 +968,8 @@ dhcp6_makemessage(struct interface *ifp) else ia_na_len = sizeof(ia_na); memcpy(ia_na.iaid, ifia->iaid, sizeof(ia_na.iaid)); + /* RFC 8415 21.4 and 21.21 state that T1 and T2 should be zero. + * An RFC compliant server MUST ignore them anyway. */ ia_na.t1 = 0; ia_na.t2 = 0; COPYIN(ifia->ia_type, &ia_na, ia_na_len); @@ -980,11 +988,16 @@ dhcp6_makemessage(struct interface *ifp) continue; if (ap->ia_type == D6_OPTION_IA_PD) { #ifndef SMALL - struct dhcp6_pd_addr pdp; + 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. + */ + }; - pdp.pltime = htonl(ap->prefix_pltime); - pdp.vltime = htonl(ap->prefix_vltime); - pdp.prefix_len = ap->prefix_len; /* pdp.prefix is not aligned, so copy it in. */ memcpy(&pdp.prefix, &ap->prefix, sizeof(pdp.prefix)); COPYIN(D6_OPTION_IAPREFIX, &pdp, sizeof(pdp)); @@ -1019,11 +1032,16 @@ dhcp6_makemessage(struct interface *ifp) } #endif } else { - struct dhcp6_ia_addr ia; + struct dhcp6_ia_addr ia = { + .addr = ap->addr, + /* + * RFC 8415 21.6 states that the + * valid and preferred lifetimes sent by + * the client SHOULD be zero and MUST + * be ignored by the server. + */ + }; - ia.addr = ap->addr; - ia.pltime = htonl(ap->prefix_pltime); - ia.vltime = htonl(ap->prefix_vltime); COPYIN(D6_OPTION_IA_ADDR, &ia, sizeof(ia)); ia_na_len = (uint16_t) (ia_na_len + sizeof(o) + sizeof(ia)); @@ -1219,7 +1237,7 @@ dhcp6_sendmessage(struct interface *ifp, struct dhcp6_state *state = D6_STATE(ifp); struct dhcpcd_ctx *ctx = ifp->ctx; unsigned int RT; - bool broadcast = true; + bool multicast = true; struct sockaddr_in6 dst = { .sin6_family = AF_INET6, /* Setting the port on Linux gives EINVAL when sending. @@ -1259,24 +1277,24 @@ dhcp6_sendmessage(struct interface *ifp, /* Unicasting is denied for these types. */ break; default: - broadcast = false; + multicast = false; inet_ntop(AF_INET6, &state->unicast, uaddr, sizeof(uaddr)); break; } } - dst.sin6_addr = broadcast ? alldhcp : state->unicast; + dst.sin6_addr = multicast ? alldhcp : state->unicast; if (!callback) { logdebugx("%s: %s %s with xid 0x%02x%02x%02x%s%s", ifp->name, - broadcast ? "broadcasting" : "unicasting", + multicast ? "multicasting" : "unicasting", dhcp6_get_op(state->send->type), state->send->xid[0], state->send->xid[1], state->send->xid[2], - !broadcast ? " " : "", - !broadcast ? uaddr : ""); + !multicast ? " " : "", + !multicast ? uaddr : ""); RT = 0; } else { if (state->IMD && @@ -1314,13 +1332,13 @@ dhcp6_sendmessage(struct interface *ifp, " next in %0.1f seconds", ifp->name, state->IMD != 0 ? "delaying" : - broadcast ? "broadcasting" : "unicasting", + multicast ? "multicasting" : "unicasting", dhcp6_get_op(state->send->type), state->send->xid[0], state->send->xid[1], state->send->xid[2], - state->IMD == 0 && !broadcast ? " " : "", - state->IMD == 0 && !broadcast ? uaddr : "", + state->IMD == 0 && !multicast ? " " : "", + state->IMD == 0 && !multicast ? uaddr : "", (float)RT / MSEC_PER_SEC); /* Wait the initial delay */ @@ -1347,7 +1365,7 @@ dhcp6_sendmessage(struct interface *ifp, #endif /* Set the outbound interface */ - if (broadcast) { + if (multicast) { struct cmsghdr *cm; struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index }; @@ -2254,8 +2272,8 @@ dhcp6_findpd(struct interface *ifp, cons if (!(a->flags & IPV6_AF_DELEGATEDPFX)) a->flags |= IPV6_AF_NEW | IPV6_AF_DELEGATEDPFX; a->flags &= ~(IPV6_AF_STALE | - IPV6_AF_EXTENDED | - IPV6_AF_REQUEST); + IPV6_AF_EXTENDED | + IPV6_AF_REQUEST); if (a->prefix_vltime != pdp.vltime) a->flags |= IPV6_AF_NEW; } @@ -2407,7 +2425,7 @@ dhcp6_findia(struct interface *ifp, stru logwarnx("%s: IAID %s T1(%d) > T2(%d) from %s", ifp->name, hwaddr_ntoa(iaid, sizeof(iaid), buf, - sizeof(buf)), + sizeof(buf)), ia.t1, ia.t2, sfrom); continue; } @@ -2840,7 +2858,7 @@ dhcp6_script_try_run(struct interface *i if (ap->flags & IPV6_AF_ONLINK) { if (!(ap->flags & IPV6_AF_DADCOMPLETED) && ipv6_iffindaddr(ap->iface, &ap->addr, - IN6_IFF_TENTATIVE)) + IN6_IFF_TENTATIVE)) ap->flags |= IPV6_AF_DADCOMPLETED; if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0 #ifndef SMALL @@ -3091,7 +3109,7 @@ dhcp6_bind(struct interface *ifp, const if (state->reason == NULL) state->reason = "INFORM6"; o = dhcp6_findmoption(state->new, state->new_len, - D6_OPTION_INFO_REFRESH_TIME, &ol); + D6_OPTION_INFO_REFRESH_TIME, &ol); if (o == NULL || ol != sizeof(uint32_t)) state->renew = IRT_DEFAULT; else { @@ -3711,7 +3729,7 @@ recvif: } static void -dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia) +dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia, unsigned short events) { struct sockaddr_in6 from; union { @@ -3733,6 +3751,9 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struc int s; ssize_t bytes; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + s = ia != NULL ? ia->dhcp6_fd : ctx->dhcp6_rfd; bytes = recvmsg(s, &msg, 0); if (bytes == -1) { @@ -3745,19 +3766,20 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struc } static void -dhcp6_recvaddr(void *arg) + +dhcp6_recvaddr(void *arg, unsigned short events) { struct ipv6_addr *ia = arg; - dhcp6_recv(ia->iface->ctx, ia); + dhcp6_recv(ia->iface->ctx, ia, events); } static void -dhcp6_recvctx(void *arg) +dhcp6_recvctx(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; - dhcp6_recv(ctx, NULL); + dhcp6_recv(ctx, NULL, events); } int @@ -3878,7 +3900,9 @@ dhcp6_start1(void *arg) logerr(__func__); return; } - eloop_event_add(ctx->eloop, ctx->dhcp6_rfd, dhcp6_recvctx, ctx); + if (eloop_event_add(ctx->eloop, ctx->dhcp6_rfd, ELE_READ, + dhcp6_recvctx, ctx) == -1) + logerr("%s: eloop_event_add", __func__); } if (!IN_PRIVSEP(ctx) && ctx->dhcp6_wfd == -1) { @@ -4197,13 +4221,13 @@ dhcp6_handleifa(int cmd, struct ipv6_add if (ia->dhcp6_fd == -1) ia->dhcp6_fd = dhcp6_openudp(ia->iface->index, &ia->addr); - if (ia->dhcp6_fd != -1) - eloop_event_add(ia->iface->ctx->eloop, - ia->dhcp6_fd, dhcp6_recvaddr, ia); + if (ia->dhcp6_fd != -1 && + eloop_event_add(ia->iface->ctx->eloop, + ia->dhcp6_fd, ELE_READ, dhcp6_recvaddr, ia) == -1) + logerr("%s: eloop_event_add", __func__); } } - if ((state = D6_STATE(ifp)) != NULL) ipv6_handleifa_addrs(cmd, &state->addrs, ia, pid); } @@ -4314,7 +4338,7 @@ dhcp6_env(FILE *fp, const char *prefix, delegated: #ifndef SMALL - /* Needed for Delegated Prefixes */ + /* Needed for Delegated Prefixes */ state = D6_CSTATE(ifp); TAILQ_FOREACH(ap, &state->addrs, next) { if (ap->delegating_prefix) @@ -4333,7 +4357,7 @@ delegated: } if (fprintf(fp, "%s", ap->saddr) == -1) return -1; - } + } if (fputc('\0', fp) == EOF) return -1; #endif Index: src/external/bsd/dhcpcd/dist/src/ipv6nd.c diff -u src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.28 src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.29 --- src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.28 Fri Oct 22 13:23:20 2021 +++ src/external/bsd/dhcpcd/dist/src/ipv6nd.c Fri Apr 21 16:54:26 2023 @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-2-Clause */ /* * dhcpcd - IPv6 ND handling - * Copyright (c) 2006-2021 Roy Marples <r...@marples.name> + * Copyright (c) 2006-2023 Roy Marples <r...@marples.name> * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -78,7 +78,7 @@ struct nd_opt_rdnss { /* RDNSS uint8_t nd_opt_rdnss_len; uint16_t nd_opt_rdnss_reserved; uint32_t nd_opt_rdnss_lifetime; - /* followed by list of IP prefixes */ + /* followed by list of IP prefixes */ }; __CTASSERT(sizeof(struct nd_opt_rdnss) == 8); #endif @@ -92,7 +92,7 @@ struct nd_opt_dnssl { /* DNSSL option R uint32_t nd_opt_dnssl_lifetime; /* followed by list of DNS servers */ }; -__CTASSERT(sizeof(struct nd_opt_rdnss) == 8); +__CTASSERT(sizeof(struct nd_opt_dnssl) == 8); #endif /* Impossible options, so we can easily add extras */ @@ -131,7 +131,7 @@ __CTASSERT(sizeof(struct nd_opt_rdnss) = //#define DEBUG_NS // -static void ipv6nd_handledata(void *); +static void ipv6nd_handledata(void *, unsigned short); /* * Android ships buggy ICMP6 filter headers. @@ -281,8 +281,14 @@ ipv6nd_openif(struct interface *ifp) return -1; } + if (eloop_event_add(ifp->ctx->eloop, fd, ELE_READ, + ipv6nd_handledata, ifp) == -1) + { + close(fd); + return -1; + } + state->nd_fd = fd; - eloop_event_add(ifp->ctx->eloop, fd, ipv6nd_handledata, ifp); return fd; } #endif @@ -388,7 +394,9 @@ ipv6nd_sendrsprobe(void *arg) logerr(__func__); return; } - eloop_event_add(ctx->eloop, ctx->nd_fd, ipv6nd_handledata, ctx); + if (eloop_event_add(ctx->eloop, ctx->nd_fd, ELE_READ, + ipv6nd_handledata, ctx) == -1) + logerr("%s: eloop_event_add", __func__); } s = ifp->ctx->nd_fd; #endif @@ -1306,6 +1314,9 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, switch (ndo.nd_opt_type) { case ND_OPT_PREFIX_INFORMATION: + { + uint32_t vltime, pltime; + loglevel = new_data ? LOG_ERR : LOG_DEBUG; if (ndo.nd_opt_len != 4) { logmessage(loglevel, @@ -1329,9 +1340,10 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, ifp->name); continue; } - if (ntohl(pi.nd_opt_pi_preferred_time) > - ntohl(pi.nd_opt_pi_valid_time)) - { + + vltime = ntohl(pi.nd_opt_pi_valid_time); + pltime = ntohl(pi.nd_opt_pi_preferred_time); + if (pltime > vltime) { logmessage(loglevel, "%s: pltime > vltime", ifp->name); continue; @@ -1356,10 +1368,15 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, &pi_prefix, pi.nd_opt_pi_prefix_len, flags); if (ia == NULL) break; + ia->prefix = pi_prefix; + ia->created = ia->acquired = rap->acquired; + ia->prefix_vltime = vltime; + ia->prefix_pltime = pltime; + if (flags & IPV6_AF_AUTOCONF) ia->dadcallback = ipv6nd_dadcallback; - ia->created = ia->acquired = rap->acquired; + TAILQ_INSERT_TAIL(&rap->addrs, ia, next); #ifdef IPV6_MANAGETEMPADDR @@ -1376,18 +1393,58 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, else new_ia = true; #endif + } else { -#ifdef IPV6_MANAGETEMPADDR - new_ia = false; -#endif + uint32_t rmtime; + + /* + * RFC 4862 5.5.3.e + * Don't terminate existing connections. + * This means that to actually remove the + * existing prefix, the RA needs to stop + * broadcasting the prefix and just let it + * expire in 2 hours. + * It might want to broadcast it to reduce + * the vltime if it was greater than 2 hours + * to start with/ + */ + ia->prefix_pltime = pltime; + if (ia->prefix_vltime) { + uint32_t elapsed; + + elapsed = (uint32_t)eloop_timespec_diff( + &rap->acquired, &ia->acquired, + NULL); + rmtime = ia->prefix_vltime - elapsed; + if (rmtime > ia->prefix_vltime) + rmtime = 0; + } else + rmtime = 0; + if (vltime > MIN_EXTENDED_VLTIME || + vltime > rmtime) + ia->prefix_vltime = vltime; + else if (rmtime <= MIN_EXTENDED_VLTIME) + /* No SEND support from RFC 3971 so + * leave vltime alone */ + ia->prefix_vltime = rmtime; + else + ia->prefix_vltime = MIN_EXTENDED_VLTIME; + + /* Ensure pltime still fits */ + if (pltime < ia->prefix_vltime) + ia->prefix_pltime = pltime; + else + ia->prefix_pltime = ia->prefix_vltime; + ia->flags |= flags; ia->flags &= ~IPV6_AF_STALE; ia->acquired = rap->acquired; + +#ifdef IPV6_MANAGETEMPADDR + new_ia = false; +#endif } - ia->prefix_vltime = - ntohl(pi.nd_opt_pi_valid_time); - ia->prefix_pltime = - ntohl(pi.nd_opt_pi_preferred_time); + if (ia->prefix_vltime != 0 && ia->flags & IPV6_AF_AUTOCONF) has_address = true; @@ -1410,6 +1467,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, } #endif break; + } case ND_OPT_MTU: if (len < sizeof(mtu)) { @@ -1977,7 +2035,7 @@ ipv6nd_recvmsg(struct dhcpcd_ctx *ctx, s } static void -ipv6nd_handledata(void *arg) +ipv6nd_handledata(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx; int fd; @@ -2013,6 +2071,10 @@ ipv6nd_handledata(void *arg) ctx = arg; fd = ctx->nd_fd; #endif + + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + len = recvmsg(fd, &msg, 0); if (len == -1) { logerr(__func__); Index: src/external/bsd/dhcpcd/dist/src/dhcpcd.c diff -u src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.49 src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.50 --- src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.49 Fri Oct 22 13:23:20 2021 +++ src/external/bsd/dhcpcd/dist/src/dhcpcd.c Fri Apr 21 16:54:26 2023 @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-2-Clause */ /* * dhcpcd - DHCP client daemon - * Copyright (c) 2006-2021 Roy Marples <r...@marples.name> + * Copyright (c) 2006-2023 Roy Marples <r...@marples.name> * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -26,7 +26,7 @@ * SUCH DAMAGE. */ -static const char dhcpcd_copyright[] = "Copyright (c) 2006-2021 Roy Marples"; +static const char dhcpcd_copyright[] = "Copyright (c) 2006-2023 Roy Marples"; #include <sys/file.h> #include <sys/ioctl.h> @@ -1105,15 +1105,19 @@ out: if_free(ifp); } free(ifs); + if_freeifaddrs(ctx, &ifaddrs); return e; } static void -dhcpcd_handlelink(void *arg) +dhcpcd_handlelink(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + if (if_handlelink(ctx) == -1) { if (errno == ENOBUFS || errno == ENOMEM) { dhcpcd_linkoverflow(ctx); @@ -1241,6 +1245,7 @@ dhcpcd_linkoverflow(struct dhcpcd_ctx *c if_markaddrsstale(ctx->ifaces); if_learnaddrs(ctx, ctx->ifaces, &ifaddrs); if_deletestaleaddrs(ctx->ifaces); + if_freeifaddrs(ctx, &ifaddrs); } void @@ -1406,7 +1411,7 @@ dhcpcd_renew(struct dhcpcd_ctx *ctx) #ifdef USE_SIGNALS #define sigmsg "received %s, %s" -static void +void dhcpcd_signal_cb(int sig, void *arg) { struct dhcpcd_ctx *ctx = arg; @@ -1465,8 +1470,12 @@ dhcpcd_signal_cb(int sig, void *arg) logerr("logopen"); return; case SIGCHLD: +#ifdef PRIVSEP + ps_root_signalcb(sig, ctx); +#else while (waitpid(-1, NULL, WNOHANG) > 0) ; +#endif return; default: logerrx("received signal %d but don't know what to do with it", @@ -1648,15 +1657,18 @@ dumperr: return 0; } -static void dhcpcd_readdump1(void *); +static void dhcpcd_readdump1(void *, unsigned short); static void -dhcpcd_readdump2(void *arg) +dhcpcd_readdump2(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; ssize_t len; int exit_code = EXIT_FAILURE; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + len = read(ctx->control_fd, ctx->ctl_buf + ctx->ctl_bufpos, ctx->ctl_buflen - ctx->ctl_bufpos); if (len == -1) { @@ -1675,8 +1687,9 @@ dhcpcd_readdump2(void *arg) fflush(stdout); if (--ctx->ctl_extra != 0) { putchar('\n'); - eloop_event_add(ctx->eloop, ctx->control_fd, - dhcpcd_readdump1, ctx); + if (eloop_event_add(ctx->eloop, ctx->control_fd, ELE_READ, + dhcpcd_readdump1, ctx) == -1) + logerr("%s: eloop_event_add", __func__); return; } exit_code = EXIT_SUCCESS; @@ -1687,11 +1700,14 @@ finished: } static void -dhcpcd_readdump1(void *arg) +dhcpcd_readdump1(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; ssize_t len; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + len = read(ctx->control_fd, &ctx->ctl_buflen, sizeof(ctx->ctl_buflen)); if (len != sizeof(ctx->ctl_buflen)) { if (len != -1) @@ -1709,8 +1725,9 @@ dhcpcd_readdump1(void *arg) goto err; ctx->ctl_bufpos = 0; - eloop_event_add(ctx->eloop, ctx->control_fd, - dhcpcd_readdump2, ctx); + if (eloop_event_add(ctx->eloop, ctx->control_fd, ELE_READ, + dhcpcd_readdump2, ctx) == -1) + logerr("%s: eloop_event_add", __func__); return; err: @@ -1719,11 +1736,14 @@ err: } static void -dhcpcd_readdump0(void *arg) +dhcpcd_readdump0(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; ssize_t len; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + len = read(ctx->control_fd, &ctx->ctl_extra, sizeof(ctx->ctl_extra)); if (len != sizeof(ctx->ctl_extra)) { if (len != -1) @@ -1738,8 +1758,9 @@ dhcpcd_readdump0(void *arg) return; } - eloop_event_add(ctx->eloop, ctx->control_fd, - dhcpcd_readdump1, ctx); + if (eloop_event_add(ctx->eloop, ctx->control_fd, ELE_READ, + dhcpcd_readdump1, ctx) == -1) + logerr("%s: eloop_event_add", __func__); } static void @@ -1759,17 +1780,20 @@ dhcpcd_readdump(struct dhcpcd_ctx *ctx) if (eloop_timeout_add_sec(ctx->eloop, 5, dhcpcd_readdumptimeout, ctx) == -1) return -1; - return eloop_event_add(ctx->eloop, ctx->control_fd, + return eloop_event_add(ctx->eloop, ctx->control_fd, ELE_READ, dhcpcd_readdump0, ctx); } static void -dhcpcd_fork_cb(void *arg) +dhcpcd_fork_cb(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; int exit_code; ssize_t len; + if (!(events & ELE_READ)) + logerrx("%s: unexpected event 0x%04x", __func__, events); + len = read(ctx->fork_fd, &exit_code, sizeof(exit_code)); if (len == -1) { logerr(__func__); @@ -1786,12 +1810,15 @@ dhcpcd_fork_cb(void *arg) } static void -dhcpcd_stderr_cb(void *arg) +dhcpcd_stderr_cb(void *arg, unsigned short events) { struct dhcpcd_ctx *ctx = arg; char log[BUFSIZ]; ssize_t len; + if (events != ELE_READ) + logerrx("%s: unexpected event 0x%04x", __func__, events); + len = read(ctx->stderr_fd, log, sizeof(log)); if (len == -1) { if (errno != ECONNRESET) @@ -1803,6 +1830,24 @@ dhcpcd_stderr_cb(void *arg) fprintf(stderr, "%s", log); } +static void +dhcpcd_pidfile_timeout(void *arg) +{ + struct dhcpcd_ctx *ctx = arg; + pid_t pid; + + pid = pidfile_read(ctx->pidfile); + + if(pid == -1) + eloop_exit(ctx->eloop, EXIT_SUCCESS); + else if (++ctx->duid_len >= 100) { /* overload duid_len */ + logerrx("pid %d failed to exit", pid); + eloop_exit(ctx->eloop, EXIT_FAILURE); + } else + eloop_timeout_add_msec(ctx->eloop, 100, + dhcpcd_pidfile_timeout, ctx); +} + int main(int argc, char **argv, char **envp) { @@ -1897,8 +1942,7 @@ main(int argc, char **argv, char **envp) ctx.dhcp6_wfd = -1; #endif #ifdef PRIVSEP - ctx.ps_root_fd = ctx.ps_log_fd = ctx.ps_data_fd = -1; - ctx.ps_inet_fd = ctx.ps_control_fd = -1; + ctx.ps_log_fd = -1; TAILQ_INIT(&ctx.ps_processes); #endif @@ -1940,12 +1984,6 @@ main(int argc, char **argv, char **envp) sig = SIGHUP; siga = "HUP"; break; - case 'g': - case 'p': - /* Force going via command socket as we're - * out of user definable signals. */ - i = 4; - break; case 'q': /* -qq disables console output entirely. * This is important for systemd because it logs @@ -2095,6 +2133,14 @@ printpidfile: snprintf(ctx.pidfile, sizeof(ctx.pidfile), PIDFILE, "", "", ""); ctx.options |= DHCPCD_MANAGER; + + /* + * If we are given any interfaces, we + * cannot send a signal as that would impact + * other interfaces. + */ + if (optind != argc) + sig = 0; } if (ctx.options & DHCPCD_PRINT_PIDFILE) { printf("%s\n", ctx.pidfile); @@ -2130,31 +2176,20 @@ printpidfile: if (pid != 0 && pid != -1) loginfox("sending signal %s to pid %d", siga, pid); if (pid == 0 || pid == -1 || kill(pid, sig) != 0) { - if (sig != SIGHUP && sig != SIGUSR1 && errno != EPERM) - logerrx(PACKAGE" not running"); if (pid != 0 && pid != -1 && errno != ESRCH) { logerr("kill"); goto exit_failure; } unlink(ctx.pidfile); - if (sig != SIGHUP && sig != SIGUSR1) - goto exit_failure; + /* We can still continue and send the command + * via the control socket. */ } else { - struct timespec ts; - if (sig == SIGHUP || sig == SIGUSR1) goto exit_success; /* Spin until it exits */ loginfox("waiting for pid %d to exit", pid); - ts.tv_sec = 0; - ts.tv_nsec = 100000000; /* 10th of a second */ - for(i = 0; i < 100; i++) { - nanosleep(&ts, NULL); - if (pidfile_read(ctx.pidfile) == -1) - goto exit_success; - } - logerrx("pid %d failed to exit", pid); - goto exit_failure; + dhcpcd_pidfile_timeout(&ctx); + goto run_loop; } } #endif @@ -2207,12 +2242,8 @@ printpidfile: } #endif - /* Test against siga instead of sig to avoid gcc - * warning about a bogus potential signed overflow. - * The end result will be the same. */ - if ((siga == NULL || i == 4 || ctx.ifc != 0) && - !(ctx.options & DHCPCD_TEST)) - { + /* Try and contact the manager process to send the instruction. */ + if (!(ctx.options & DHCPCD_TEST)) { ctx.options |= DHCPCD_FORKED; /* avoid socket unlink */ if (!(ctx.options & DHCPCD_MANAGER)) ctx.control_fd = control_open(argv[optind], family, @@ -2249,9 +2280,14 @@ printpidfile: } else { if (errno != ENOENT) logerr("%s: control_open", __func__); - if (ctx.options & DHCPCD_DUMPLEASE) { + /* If asking dhcpcd to exit and we failed to + * send a signal or a message then we + * don't proceed past here. */ + if (ctx.options & DHCPCD_DUMPLEASE || + sig == SIGTERM || sig == SIGALRM) + { if (errno == ENOENT) - logerrx("dhcpcd is not running"); + logerrx(PACKAGE" is not running"); goto exit_failure; } if (errno == EPERM || errno == EACCES) @@ -2286,9 +2322,9 @@ printpidfile: if (!(ctx.options & DHCPCD_DAEMONISE)) goto start_manager; - if (xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, fork_fd) == -1 || + if (xsocketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CXNB, 0, fork_fd) == -1 || (ctx.stderr_valid && - xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, stderr_fd) == -1)) + xsocketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CXNB, 0, stderr_fd) == -1)) { logerr("socketpair"); goto exit_failure; @@ -2306,7 +2342,9 @@ printpidfile: goto exit_failure; } #endif - eloop_event_add(ctx.eloop, ctx.fork_fd, dhcpcd_fork_cb, &ctx); + if (eloop_event_add(ctx.eloop, ctx.fork_fd, ELE_READ, + dhcpcd_fork_cb, &ctx) == -1) + logerr("%s: eloop_event_add", __func__); /* * Redirect stderr to the stderr socketpair. @@ -2335,6 +2373,7 @@ printpidfile: logerr("fork"); goto exit_failure; case 0: + eloop_forked(ctx.eloop); break; default: ctx.options |= DHCPCD_FORKED; /* A lie */ @@ -2353,7 +2392,9 @@ printpidfile: goto exit_failure; } #endif - eloop_event_add(ctx.eloop, ctx.fork_fd, dhcpcd_fork_cb, &ctx); + if (eloop_event_add(ctx.eloop, ctx.fork_fd, ELE_READ, + dhcpcd_fork_cb, &ctx) == -1) + logerr("%s: eloop_event_add", __func__); if (ctx.stderr_valid) { ctx.stderr_fd = stderr_fd[0]; @@ -2364,8 +2405,9 @@ printpidfile: goto exit_failure; } #endif - eloop_event_add(ctx.eloop, ctx.stderr_fd, - dhcpcd_stderr_cb, &ctx); + if (eloop_event_add(ctx.eloop, ctx.stderr_fd, ELE_READ, + dhcpcd_stderr_cb, &ctx) == -1) + logerr("%s: eloop_event_add", __func__); } #ifdef PRIVSEP if (IN_PRIVSEP(&ctx) && ps_managersandbox(&ctx, NULL) == -1) @@ -2447,7 +2489,9 @@ start_manager: /* Start handling kernel messages for interfaces, addresses and * routes. */ - eloop_event_add(ctx.eloop, ctx.link_fd, dhcpcd_handlelink, &ctx); + if (eloop_event_add(ctx.eloop, ctx.link_fd, ELE_READ, + dhcpcd_handlelink, &ctx) == -1) + logerr("%s: eloop_event_add", __func__); #ifdef PRIVSEP if (IN_PRIVSEP(&ctx) && ps_managersandbox(&ctx, "stdio route") == -1) @@ -2497,6 +2541,8 @@ start_manager: dhcpcd_initstate1(ifp, argc, argv, 0); } if_learnaddrs(&ctx, ctx.ifaces, &ifaddrs); + if_freeifaddrs(&ctx, &ifaddrs); + ifaddrs = NULL; if (ctx.options & DHCPCD_BACKGROUND) dhcpcd_daemonise(&ctx); @@ -2567,17 +2613,7 @@ exit_failure: exit1: if (!(ctx.options & DHCPCD_TEST) && control_stop(&ctx) == -1) logerr("%s: control_stop", __func__); - if (ifaddrs != NULL) { -#ifdef PRIVSEP_GETIFADDRS - if (IN_PRIVSEP(&ctx)) - free(ifaddrs); - else -#endif - freeifaddrs(ifaddrs); - } - /* ps_stop will clear DHCPCD_PRIVSEP but we need to - * remember it to avoid attemping to remove the pidfile */ - oi = ctx.options & DHCPCD_PRIVSEP ? 1 : 0; + if_freeifaddrs(&ctx, &ifaddrs); #ifdef PRIVSEP ps_stop(&ctx); #endif @@ -2611,14 +2647,20 @@ exit1: #ifdef PLUGIN_DEV dev_stop(&ctx); #endif -#ifdef PRIVSEP - eloop_free(ctx.ps_eloop); -#endif - eloop_free(ctx.eloop); if (ctx.script != dhcpcd_default_script) free(ctx.script); +#ifdef PRIVSEP + if (ps_stopwait(&ctx) != EXIT_SUCCESS) + i = EXIT_FAILURE; +#endif if (ctx.options & DHCPCD_STARTED && !(ctx.options & DHCPCD_FORKED)) loginfox(PACKAGE " exited"); +#ifdef PRIVSEP + if (ps_root_stop(&ctx) == -1) + i = EXIT_FAILURE; + eloop_free(ctx.ps_eloop); +#endif + eloop_free(ctx.eloop); logclose(); free(ctx.logfile); free(ctx.ctl_buf); @@ -2632,7 +2674,7 @@ exit1: write(ctx.fork_fd, &i, sizeof(i)) == -1) logerr("%s: write", __func__); } - if (ctx.options & DHCPCD_FORKED || oi != 0) + if (ctx.options & (DHCPCD_FORKED | DHCPCD_PRIVSEP)) _exit(i); /* so atexit won't remove our pidfile */ #endif return i; Index: src/external/bsd/dhcpcd/dist/src/if-bsd.c diff -u src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.27 src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.28 --- src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.27 Fri Oct 22 13:23:20 2021 +++ src/external/bsd/dhcpcd/dist/src/if-bsd.c Fri Apr 21 16:54:26 2023 @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-2-Clause */ /* * BSD interface driver for dhcpcd - * Copyright (c) 2006-2021 Roy Marples <r...@marples.name> + * Copyright (c) 2006-2023 Roy Marples <r...@marples.name> * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -104,6 +104,7 @@ * just won't work without explicit configuration. */ static const char * const ifnames_ignore[] = { "bridge", + "epair", /* Virtual patch cable */ "fwe", /* Firewire */ "fwip", /* Firewire */ "tap", @@ -112,10 +113,6 @@ static const char * const ifnames_ignore NULL }; -struct priv { - int pf_inet6_fd; -}; - struct rtm { struct rt_msghdr hdr; @@ -222,6 +219,12 @@ 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); + if (priv->pf_link_fd == -1) + logerr("%s: socket(PF_LINK)", __func__); +#endif return 0; } @@ -233,6 +236,10 @@ if_closesockets_os(struct dhcpcd_ctx *ct priv = (struct priv *)ctx->priv; if (priv->pf_inet6_fd != -1) close(priv->pf_inet6_fd); +#if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */ + if (priv->pf_link_fd != -1) + close(priv->pf_link_fd); +#endif free(priv); ctx->priv = NULL; free(ctx->rt_missfilter); @@ -242,22 +249,14 @@ if_closesockets_os(struct dhcpcd_ctx *ct static int if_ioctllink(struct dhcpcd_ctx *ctx, unsigned long req, void *data, size_t len) { - int s; - int retval; + struct priv *priv = (struct priv *)ctx->priv; #ifdef PRIVSEP if (ctx->options & DHCPCD_PRIVSEP) return (int)ps_root_ioctllink(ctx, req, data, len); -#else - UNUSED(ctx); #endif - s = socket(PF_LINK, SOCK_DGRAM, 0); - if (s == -1) - return -1; - retval = ioctl(s, req, data, len); - close(s); - return retval; + return ioctl(priv->pf_link_fd, req, data, len); } #endif @@ -914,37 +913,47 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct return 0; } +static int +if_sysctl(struct dhcpcd_ctx *ctx, + const int *name, u_int namelen, + void *oldp, size_t *oldlenp, void *newp, size_t newlen) +{ +#if defined(PRIVSEP) && defined(HAVE_CAPSICUM) + if (IN_PRIVSEP(ctx)) + return (int)ps_root_sysctl(ctx, name, namelen, + oldp, oldlenp, newp, newlen); +#else + UNUSED(ctx); +#endif + + return sysctl(name, namelen, oldp, oldlenp, newp, newlen); +} + int if_initrt(struct dhcpcd_ctx *ctx, rb_tree_t *kroutes, int af) { struct rt_msghdr *rtm; - int mib[6]; - size_t needed; + int mib[6] = { CTL_NET, PF_ROUTE, 0, af, NET_RT_DUMP, 0 }; + size_t bufl; char *buf, *p, *end; struct rt rt, *rtn; - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; - mib[3] = af; - mib[4] = NET_RT_DUMP; - mib[5] = 0; - - if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) + if (if_sysctl(ctx, mib, __arraycount(mib), NULL, &bufl, NULL, 0) == -1) return -1; - if (needed == 0) + if (bufl == 0) return 0; - if ((buf = malloc(needed)) == NULL) + if ((buf = malloc(bufl)) == NULL) return -1; - if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) { + if (if_sysctl(ctx, mib, __arraycount(mib), buf, &bufl, NULL, 0) == -1) + { free(buf); return -1; } - end = buf + needed; + end = buf + bufl; for (p = buf; p < end; p += rtm->rtm_msglen) { rtm = (void *)p; - if (p + rtm->rtm_msglen >= end) { + if (p + sizeof(*rtm) > end || p + rtm->rtm_msglen > end) { errno = EINVAL; break; } @@ -1246,8 +1255,8 @@ if_rtm(struct dhcpcd_ctx *ctx, const str /* Ignore messages from ourself. */ #ifdef PRIVSEP - if (ctx->ps_root_pid != 0) { - if (rtm->rtm_pid == ctx->ps_root_pid) + if (ctx->ps_root != NULL) { + if (rtm->rtm_pid == ctx->ps_root->psp_pid) return 0; } #endif @@ -1298,8 +1307,8 @@ if_ifa(struct dhcpcd_ctx *ctx, const str * We need to process address flag changes though. */ if (ifam->ifam_type == RTM_DELADDR) { #ifdef PRIVSEP - if (ctx->ps_root_pid != 0) { - if (ifam->ifam_pid == ctx->ps_root_pid) + if (ctx->ps_root != NULL) { + if (ifam->ifam_pid == ctx->ps_root->psp_pid) return 0; } else #endif @@ -1649,12 +1658,11 @@ inet6_sysctl(int code, int val, int acti mib[3] = code; size = sizeof(val); if (action) { - if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), - NULL, 0, &val, size) == -1) + if (sysctl(mib, __arraycount(mib), NULL, 0, &val, size) == -1) return -1; return 0; } - if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &val, &size, NULL, 0) == -1) + if (sysctl(mib, __arraycount(mib), &val, &size, NULL, 0) == -1) return -1; return val; } Index: src/external/bsd/dhcpcd/dist/src/if-options.c diff -u src/external/bsd/dhcpcd/dist/src/if-options.c:1.32 src/external/bsd/dhcpcd/dist/src/if-options.c:1.33 --- src/external/bsd/dhcpcd/dist/src/if-options.c:1.32 Fri Oct 22 13:23:20 2021 +++ src/external/bsd/dhcpcd/dist/src/if-options.c Fri Apr 21 16:54:26 2023 @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-2-Clause */ /* * dhcpcd - DHCP client daemon - * Copyright (c) 2006-2021 Roy Marples <r...@marples.name> + * Copyright (c) 2006-2023 Roy Marples <r...@marples.name> * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -193,7 +193,10 @@ add_environ(char ***array, const char *v l = strlen(match); while (list && list[i]) { - if (match && strncmp(list[i], match, l) == 0) { + /* We know that it must contain '=' due to the above test */ + size_t listl = (size_t)(strchr(list[i], '=') - list[i]); + + if (l == listl && strncmp(list[i], match, l) == 0) { if (uniq) { n = strdup(value); if (n == NULL) { @@ -266,7 +269,13 @@ parse_str(char *sbuf, size_t slen, const } } else { l = (size_t)hwaddr_aton(NULL, str); - if ((ssize_t) l != -1 && l > 1) { + if (l > 0) { + if ((ssize_t)l == -1) { + errno = ENOBUFS; + return -1; + } + if (sbuf == NULL) + return (ssize_t)l; if (l > slen) { errno = ENOBUFS; return -1; @@ -1108,8 +1117,13 @@ parse_option(struct dhcpcd_ctx *ctx, con logerrx("static assignment required"); return -1; } - p++; + p = strskipwhite(++p); if (strncmp(arg, "ip_address=", strlen("ip_address=")) == 0) { + if (p == NULL) { + ifo->options &= ~DHCPCD_STATIC; + ifo->req_addr.s_addr = INADDR_ANY; + break; + } if (parse_addr(&ifo->req_addr, ifo->req_mask.s_addr == 0 ? &ifo->req_mask : NULL, p) != 0) @@ -1120,11 +1134,19 @@ parse_option(struct dhcpcd_ctx *ctx, con } else if (strncmp(arg, "subnet_mask=", strlen("subnet_mask=")) == 0) { + if (p == NULL) { + ifo->req_mask.s_addr = INADDR_ANY; + break; + } if (parse_addr(&ifo->req_mask, NULL, p) != 0) return -1; } else if (strncmp(arg, "broadcast_address=", strlen("broadcast_address=")) == 0) { + if (p == NULL) { + ifo->req_brd.s_addr = INADDR_ANY; + break; + } if (parse_addr(&ifo->req_brd, NULL, p) != 0) return -1; } else if (strncmp(arg, "routes=", strlen("routes=")) == 0 || @@ -1137,6 +1159,12 @@ parse_option(struct dhcpcd_ctx *ctx, con { struct in_addr addr3; + if (p == NULL) { + rt_headclear(&ifo->routes, AF_INET); + add_environ(&ifo->config, arg, 1); + break; + } + fp = np = strwhite(p); if (np == NULL) { logerrx("all routes need a gateway"); @@ -1159,6 +1187,11 @@ parse_option(struct dhcpcd_ctx *ctx, con if (rt_proto_add_ctx(&ifo->routes, rt, ctx)) add_environ(&ifo->config, arg, 0); } else if (strncmp(arg, "routers=", strlen("routers=")) == 0) { + if (p == NULL) { + rt_headclear(&ifo->routes, AF_INET); + add_environ(&ifo->config, arg, 1); + break; + } if (parse_addr(&addr, NULL, p) == -1) return -1; if ((rt = rt_new0(ctx)) == NULL) @@ -1173,6 +1206,8 @@ parse_option(struct dhcpcd_ctx *ctx, con strlen("interface_mtu=")) == 0 || strncmp(arg, "mtu=", strlen("mtu=")) == 0) { + if (p == NULL) + break; ifo->mtu = (unsigned int)strtou(p, NULL, 0, MTU_MIN, MTU_MAX, &e); if (e) { @@ -1180,6 +1215,12 @@ parse_option(struct dhcpcd_ctx *ctx, con return -1; } } else if (strncmp(arg, "ip6_address=", strlen("ip6_address=")) == 0) { + if (p == NULL) { + memset(&ifo->req_addr6, 0, + sizeof(ifo->req_addr6)); + break; + } + np = strchr(p, '/'); if (np) *np++ = '\0'; @@ -1205,8 +1246,9 @@ parse_option(struct dhcpcd_ctx *ctx, con return -1; } } else - add_environ(&ifo->config, arg, 1); + add_environ(&ifo->config, arg, p == NULL ? 1 : 0); break; + case 'W': if (parse_addr(&addr, &addr2, arg) != 0) return -1; @@ -2061,7 +2103,7 @@ err_sla: arg = fp; fp = strend(arg); if (fp == NULL) { - logerrx("authtoken requies an a key"); + logerrx("authtoken requires a realm"); goto invalid_token; } *fp++ = '\0'; @@ -2114,7 +2156,7 @@ err_sla: if (s == -1) logerr("token_len"); else - logerrx("authtoken needs a key"); + logerrx("authtoken requires a key"); goto invalid_token; } token->key_len = (size_t)s; @@ -2229,6 +2271,24 @@ invalid_token: ifo->options |= DHCPCD_SLAACPRIVATE; else ifo->options &= ~DHCPCD_SLAACPRIVATE; +#ifdef INET6 + if (strcmp(arg, "token") == 0) { + if (np == NULL) { + logerrx("slaac token: no token specified"); + return -1; + } + arg = np; + np = strwhite(np); + if (np != NULL) { + *np++ = '\0'; + np = strskipwhite(np); + } + if (inet_pton(AF_INET6, arg, &ifo->token) != 1) { + logerrx("slaac token: invalid token"); + return -1; + } + } +#endif if (np != NULL && (strcmp(np, "temp") == 0 || strcmp(np, "temporary") == 0)) ifo->options |= DHCPCD_SLAACTEMP; Index: src/external/bsd/dhcpcd/dist/src/ipv6.c diff -u src/external/bsd/dhcpcd/dist/src/ipv6.c:1.17 src/external/bsd/dhcpcd/dist/src/ipv6.c:1.18 --- src/external/bsd/dhcpcd/dist/src/ipv6.c:1.17 Fri Oct 22 13:23:20 2021 +++ src/external/bsd/dhcpcd/dist/src/ipv6.c Fri Apr 21 16:54:26 2023 @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-2-Clause */ /* * dhcpcd - DHCP client daemon - * Copyright (c) 2006-2021 Roy Marples <r...@marples.name> + * Copyright (c) 2006-2023 Roy Marples <r...@marples.name> * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -359,51 +359,6 @@ again: } #endif -int -ipv6_makeaddr(struct in6_addr *addr, struct interface *ifp, - const struct in6_addr *prefix, int prefix_len, unsigned int flags) -{ - const struct ipv6_addr *ap; - int dad; - - if (prefix_len < 0 || prefix_len > 120) { - errno = EINVAL; - return -1; - } - -#ifdef IPV6_AF_TEMPORARY - if (flags & IPV6_AF_TEMPORARY) - return ipv6_maketemporaryaddress(addr, prefix, prefix_len, ifp); -#else - UNUSED(flags); -#endif - - if (ifp->options->options & DHCPCD_SLAACPRIVATE) { - dad = 0; - if (ipv6_makestableprivate(addr, - prefix, prefix_len, ifp, &dad) == -1) - return -1; - return dad; - } - - if (prefix_len > 64) { - errno = EINVAL; - return -1; - } - if ((ap = ipv6_linklocal(ifp)) == NULL) { - /* We delay a few functions until we get a local-link address - * so this should never be hit. */ - errno = ENOENT; - return -1; - } - - /* Make the address from the first local-link address */ - memcpy(addr, prefix, sizeof(*prefix)); - addr->s6_addr32[2] = ap->addr.s6_addr32[2]; - addr->s6_addr32[3] = ap->addr.s6_addr32[3]; - return 0; -} - static int ipv6_makeprefix(struct in6_addr *prefix, const struct in6_addr *addr, int len) { @@ -478,6 +433,68 @@ ipv6_prefixlen(const struct in6_addr *ma return (uint8_t)(x * NBBY + y); } +int +ipv6_makeaddr(struct in6_addr *addr, struct interface *ifp, + const struct in6_addr *prefix, int prefix_len, unsigned int flags) +{ + const struct ipv6_addr *ap; + const struct if_options *ifo = ifp->options; + int dad; + + if (prefix_len < 0 || prefix_len > 120) { + errno = EINVAL; + return -1; + } + +#ifdef IPV6_AF_TEMPORARY + if (flags & IPV6_AF_TEMPORARY) + return ipv6_maketemporaryaddress(addr, prefix, prefix_len, ifp); +#else + UNUSED(flags); +#endif + + if (ifo->options & DHCPCD_SLAACPRIVATE) { + dad = 0; + if (ipv6_makestableprivate(addr, + prefix, prefix_len, ifp, &dad) == -1) + return -1; + return dad; + } else if (!IN6_IS_ADDR_UNSPECIFIED(&ifo->token)) { + int bytes = prefix_len / NBBY; + int bits = prefix_len % NBBY; + + // Copy the token into the address. + *addr = ifo->token; + + // If we have any dangling bits, just copy that in also. + // XXX Can we preserve part of the token still? + if (bits != 0) + bytes++; + + // Copy the prefix in. + if (bytes > 0) + memcpy(addr->s6_addr, prefix->s6_addr, (size_t)bytes); + return 0; + } + + if (prefix_len > 64) { + errno = EINVAL; + return -1; + } + if ((ap = ipv6_linklocal(ifp)) == NULL) { + /* We delay a few functions until we get a local-link address + * so this should never be hit. */ + errno = ENOENT; + return -1; + } + + /* Make the address from the first local-link address */ + memcpy(addr, prefix, sizeof(*prefix)); + addr->s6_addr32[2] = ap->addr.s6_addr32[2]; + addr->s6_addr32[3] = ap->addr.s6_addr32[3]; + return 0; +} + static void in6_to_h64(uint64_t *vhigh, uint64_t *vlow, const struct in6_addr *addr) { Index: src/external/bsd/dhcpcd/dist/src/ipv6.h diff -u src/external/bsd/dhcpcd/dist/src/ipv6.h:1.13 src/external/bsd/dhcpcd/dist/src/ipv6.h:1.14 --- src/external/bsd/dhcpcd/dist/src/ipv6.h:1.13 Fri Oct 22 13:23:20 2021 +++ src/external/bsd/dhcpcd/dist/src/ipv6.h Fri Apr 21 16:54:26 2023 @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-2-Clause */ /* * dhcpcd - DHCP client daemon - * Copyright (c) 2006-2021 Roy Marples <r...@marples.name> + * Copyright (c) 2006-2023 Roy Marples <r...@marples.name> * All rights reserved * Redistribution and use in source and binary forms, with or without Index: src/external/bsd/dhcpcd/dist/src/privsep.c diff -u src/external/bsd/dhcpcd/dist/src/privsep.c:1.13 src/external/bsd/dhcpcd/dist/src/privsep.c:1.14 --- src/external/bsd/dhcpcd/dist/src/privsep.c:1.13 Fri Oct 22 13:23:20 2021 +++ src/external/bsd/dhcpcd/dist/src/privsep.c Fri Apr 21 16:54:26 2023 @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-2-Clause */ /* * Privilege Separation for dhcpcd - * Copyright (c) 2006-2021 Roy Marples <r...@marples.name> + * Copyright (c) 2006-2023 Roy Marples <r...@marples.name> * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -75,6 +75,7 @@ #ifdef HAVE_CAPSICUM #include <sys/capsicum.h> +#include <sys/procdesc.h> #include <capsicum_helpers.h> #endif #ifdef HAVE_UTIL_H @@ -144,33 +145,27 @@ ps_dropprivs(struct dhcpcd_ctx *ctx) struct rlimit rzero = { .rlim_cur = 0, .rlim_max = 0 }; - if (ctx->ps_control_pid != getpid()) { - /* Prohibit new files, sockets, etc */ -#if defined(__linux__) || defined(__sun) || defined(__OpenBSD__) - /* - * If poll(2) is called with nfds > RLIMIT_NOFILE - * then it returns EINVAL. - * This blows. - * Do the best we can and limit to what we need. - * An attacker could potentially close a file and - * open a new one still, but that cannot be helped. - */ - unsigned long maxfd; - maxfd = (unsigned long)eloop_event_count(ctx->eloop); - if (IN_PRIVSEP_SE(ctx)) - maxfd++; /* XXX why? */ - - struct rlimit rmaxfd = { - .rlim_cur = maxfd, - .rlim_max = maxfd - }; - if (setrlimit(RLIMIT_NOFILE, &rmaxfd) == -1) - logerr("setrlimit RLIMIT_NOFILE"); -#else + /* Prohibit new files, sockets, etc */ + /* + * If poll(2) is called with nfds>RLIMIT_NOFILE then it returns EINVAL. + * We don't know the final value of nfds at this point *easily*. + * Sadly, this is a POSIX limitation and most platforms adhere to it. + * However, some are not that strict and are whitelisted below. + * Also, if we're not using poll then we can be restrictive. + * + * For the non whitelisted platforms there should be a sandbox to + * fallback to where we don't allow new files, etc: + * Linux:seccomp, FreeBSD:capsicum, OpenBSD:pledge + * Solaris users are sadly out of luck on both counts. + */ +#if defined(__NetBSD__) || defined(__DragonFly__) || \ + defined(HAVE_KQUEUE) || defined(HAVE_EPOLL) + /* The control proxy *does* need to create new fd's via accept(2). */ + if (ctx->ps_ctl == NULL || ctx->ps_ctl->psp_pid != getpid()) { if (setrlimit(RLIMIT_NOFILE, &rzero) == -1) logerr("setrlimit RLIMIT_NOFILE"); -#endif } +#endif #define DHC_NOCHKIO (DHCPCD_STARTED | DHCPCD_DAEMONISE) /* Prohibit writing to files. @@ -324,17 +319,41 @@ ps_rights_limit_stdio(struct dhcpcd_ctx } #endif +#ifdef HAVE_CAPSICUM +static void +ps_processhangup(void *arg, unsigned short events) +{ + struct ps_process *psp = arg; + struct dhcpcd_ctx *ctx = psp->psp_ctx; + + if (!(events & ELE_HANGUP)) + logerrx("%s: unexpected event 0x%04x", __func__, events); + + logdebugx("%s%s%s exited from PID %d", + psp->psp_ifname, psp->psp_ifname[0] != '\0' ? ": " : "", + psp->psp_name, psp->psp_pid); + + ps_freeprocess(psp); + + if (!(ctx->options & DHCPCD_EXITING)) + return; + if (!(ps_waitforprocs(ctx))) + eloop_exit(ctx->ps_eloop, EXIT_SUCCESS); +} +#endif + pid_t -ps_dostart(struct dhcpcd_ctx *ctx, - pid_t *priv_pid, int *priv_fd, - void (*recv_msg)(void *), void (*recv_unpriv_msg), - void *recv_ctx, int (*callback)(void *), void (*signal_cb)(int, void *), +ps_startprocess(struct ps_process *psp, + void (*recv_msg)(void *, unsigned short), + void (*recv_unpriv_msg)(void *, unsigned short), + int (*callback)(struct ps_process *), void (*signal_cb)(int, void *), unsigned int flags) { + struct dhcpcd_ctx *ctx = psp->psp_ctx; int fd[2]; pid_t pid; - if (xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, fd) == -1) { + if (xsocketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CXNB, 0, fd) == -1) { logerr("%s: socketpair", __func__); return -1; } @@ -349,37 +368,62 @@ ps_dostart(struct dhcpcd_ctx *ctx, } #endif - switch (pid = fork()) { +#ifdef HAVE_CAPSICUM + pid = pdfork(&psp->psp_pfd, PD_CLOEXEC); +#else + pid = fork(); +#endif + switch (pid) { case -1: +#ifdef HAVE_CAPSICUM + logerr("pdfork"); +#else logerr("fork"); +#endif return -1; case 0: - *priv_fd = fd[1]; + psp->psp_pid = getpid(); + psp->psp_fd = fd[1]; close(fd[0]); break; default: - *priv_pid = pid; - *priv_fd = fd[0]; + psp->psp_pid = pid; + psp->psp_fd = fd[0]; close(fd[1]); if (recv_unpriv_msg == NULL) ; - else if (eloop_event_add(ctx->eloop, *priv_fd, - recv_unpriv_msg, recv_ctx) == -1) + else if (eloop_event_add(ctx->eloop, psp->psp_fd, ELE_READ, + recv_unpriv_msg, psp) == -1) { - logerr("%s: eloop_event_add", __func__); + logerr("%s: eloop_event_add fd %d", + __func__, psp->psp_fd); return -1; } +#ifdef HAVE_CAPSICUM + if (eloop_event_add(ctx->eloop, psp->psp_pfd, ELE_HANGUP, + ps_processhangup, psp) == -1) + { + logerr("%s: eloop_event_add pfd %d", + __func__, psp->psp_pfd); + return -1; + } +#endif + psp->psp_started = true; return pid; } - ctx->options |= DHCPCD_FORKED; - if (ctx->fork_fd != -1) { - close(ctx->fork_fd); - ctx->fork_fd = -1; - } - pidfile_clean(); - eloop_clear(ctx->eloop); +#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); + eloop_clear(ctx->eloop, -1); + eloop_forked(ctx->eloop); eloop_signal_set_cb(ctx->eloop, dhcpcd_signals, dhcpcd_signals_len, signal_cb, ctx); /* ctx->sigset aready has the initial sigmask set in main() */ @@ -388,16 +432,31 @@ ps_dostart(struct dhcpcd_ctx *ctx, goto errexit; } - /* We are not root */ - if (priv_fd != &ctx->ps_root_fd) { - ps_freeprocesses(ctx, recv_ctx); - if (ctx->ps_root_fd != -1) { - close(ctx->ps_root_fd); - ctx->ps_root_fd = -1; - } + if (ctx->fork_fd != -1) { + /* Already removed from eloop thanks to above clear. */ + close(ctx->fork_fd); + ctx->fork_fd = -1; + } + /* This process has no need of the blocking inner eloop. */ + if (!(flags & PSF_ELOOP)) { + eloop_free(ctx->ps_eloop); + ctx->ps_eloop = NULL; + } else + eloop_forked(ctx->ps_eloop); + + pidfile_clean(); + ps_freeprocesses(ctx, psp); + + if (ctx->ps_root != psp) { + ctx->options &= ~DHCPCD_PRIVSEPROOT; + ctx->ps_root = NULL; + if (ctx->ps_log_root_fd != -1) { + /* Already removed from eloop thanks to above clear. */ + close(ctx->ps_log_root_fd); + ctx->ps_log_root_fd = -1; + } #ifdef PRIVSEP_RIGHTS - /* We cannot limit the root process in any way. */ if (ps_rights_limit_stdio(ctx) == -1) { logerr("ps_rights_limit_stdio"); goto errexit; @@ -405,58 +464,88 @@ ps_dostart(struct dhcpcd_ctx *ctx, #endif } - if (priv_fd != &ctx->ps_inet_fd && ctx->ps_inet_fd != -1) { - close(ctx->ps_inet_fd); - ctx->ps_inet_fd = -1; - } + 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, *priv_fd, recv_msg, recv_ctx) == -1) + if (eloop_event_add(ctx->eloop, psp->psp_fd, ELE_READ, + recv_msg, psp) == -1) { - logerr("%s: eloop_event_add", __func__); + logerr("%d %s: eloop_event_add XX fd %d", getpid(), __func__, psp->psp_fd); goto errexit; } - if (callback(recv_ctx) == -1) + if (callback(psp) == -1) goto errexit; if (flags & PSF_DROPPRIVS) ps_dropprivs(ctx); + psp->psp_started = true; return 0; errexit: - /* Failure to start root or inet processes is fatal. */ - if (priv_fd == &ctx->ps_root_fd || priv_fd == &ctx->ps_inet_fd) - (void)ps_sendcmd(ctx, *priv_fd, PS_STOP, 0, NULL, 0); - shutdown(*priv_fd, SHUT_RDWR); - *priv_fd = -1; + if (psp->psp_fd != -1) { + close(psp->psp_fd); + psp->psp_fd = -1; + } eloop_exit(ctx->eloop, EXIT_FAILURE); return -1; } +void +ps_process_timeout(void *arg) +{ + struct dhcpcd_ctx *ctx = arg; + + logerrx("%s: timed out", __func__); + eloop_exit(ctx->eloop, EXIT_FAILURE); +} + int -ps_dostop(struct dhcpcd_ctx *ctx, pid_t *pid, int *fd) +ps_stopprocess(struct ps_process *psp) { int err = 0; + if (psp == NULL) + return 0; + + psp->psp_started = false; + #ifdef PRIVSEP_DEBUG - logdebugx("%s: pid=%d fd=%d", __func__, *pid, *fd); + logdebugx("%s: me=%d pid=%d fd=%d %s", __func__, + getpid(), psp->psp_pid, psp->psp_fd, psp->psp_name); #endif - if (*fd != -1) { - eloop_event_delete(ctx->eloop, *fd); - if (ps_sendcmd(ctx, *fd, PS_STOP, 0, NULL, 0) == -1) { + if (psp->psp_fd != -1) { + eloop_event_delete(psp->psp_ctx->eloop, psp->psp_fd); +#if 0 + if (ps_sendcmd(psp->psp_ctx, psp->psp_fd, PS_STOP, 0, + NULL, 0) == -1) + { + logerr("%d %d %s %s", getpid(), psp->psp_pid, psp->psp_name, __func__); + err = -1; + } + shutdown(psp->psp_fd, SHUT_WR); +#else + if (shutdown(psp->psp_fd, SHUT_WR) == -1) { logerr(__func__); err = -1; } - (void)shutdown(*fd, SHUT_RDWR); - close(*fd); - *fd = -1; +#endif + psp->psp_fd = -1; } /* Don't wait for the process as it may not respond to the shutdown * request. We'll reap the process on receipt of SIGCHLD. */ - *pid = 0; return err; } @@ -467,6 +556,13 @@ ps_start(struct dhcpcd_ctx *ctx) TAILQ_INIT(&ctx->ps_processes); + /* We need an inner eloop to block with. */ + if ((ctx->ps_eloop = eloop_new()) == NULL) + return -1; + eloop_signal_set_cb(ctx->ps_eloop, + dhcpcd_signals, dhcpcd_signals_len, + dhcpcd_signal_cb, ctx); + switch (pid = ps_root_start(ctx)) { case -1: logerr("ps_root_start"); @@ -557,7 +653,7 @@ ps_managersandbox(struct dhcpcd_ctx *ctx * If it cannot be opened before chrooting then syslog(3) will fail. * openlog(3) does not return an error which doubly sucks. */ - if (ctx->ps_root_fd == -1) { + if (ctx->ps_root == NULL) { unsigned int logopts = loggetopts(); logopts &= ~LOGERR_LOG; @@ -606,39 +702,106 @@ ps_stop(struct dhcpcd_ctx *ctx) ctx->eloop == NULL) return 0; - r = ps_ctl_stop(ctx); - if (r != 0) - ret = r; - - r = ps_inet_stop(ctx); - if (r != 0) - ret = r; - - /* We've been chrooted, so we need to tell the - * privileged proxy to remove the pidfile. */ - ps_root_unlink(ctx, ctx->pidfile); - - r = ps_root_stop(ctx); - if (r != 0) - ret = r; + if (ctx->ps_ctl != NULL) { + r = ps_ctl_stop(ctx); + if (r != 0) + ret = r; + } + + if (ctx->ps_inet != NULL) { + r = ps_inet_stop(ctx); + if (r != 0) + ret = r; + } + + if (ctx->ps_root != NULL) { + if (ps_root_stopprocesses(ctx) == -1) + ret = -1; + } - ctx->options &= ~DHCPCD_PRIVSEP; return ret; } +bool +ps_waitforprocs(struct dhcpcd_ctx *ctx) +{ + struct ps_process *psp = TAILQ_FIRST(&ctx->ps_processes); + + if (psp == NULL) + return false; + + /* Different processes */ + if (psp != TAILQ_LAST(&ctx->ps_processes, ps_process_head)) + return true; + + return !psp->psp_started; +} + +int +ps_stopwait(struct dhcpcd_ctx *ctx) +{ + int error = EXIT_SUCCESS; + + if (ctx->ps_eloop == NULL || !ps_waitforprocs(ctx)) + return 0; + + ctx->options |= DHCPCD_EXITING; + if (eloop_timeout_add_sec(ctx->ps_eloop, PS_PROCESS_TIMEOUT, + ps_process_timeout, ctx) == -1) + logerr("%s: eloop_timeout_add_sec", __func__); + eloop_enter(ctx->ps_eloop); + +#ifdef HAVE_CAPSICUM + struct ps_process *psp; + + TAILQ_FOREACH(psp, &ctx->ps_processes, next) { + if (psp->psp_pfd == -1) + continue; + if (eloop_event_add(ctx->ps_eloop, psp->psp_pfd, + ELE_HANGUP, ps_processhangup, psp) == -1) + logerr("%s: eloop_event_add pfd %d", + __func__, psp->psp_pfd); + } +#endif + + error = eloop_start(ctx->ps_eloop, &ctx->sigset); + if (error != EXIT_SUCCESS) + logerr("%s: eloop_start", __func__); + + eloop_timeout_delete(ctx->ps_eloop, ps_process_timeout, ctx); + + return error; +} + void ps_freeprocess(struct ps_process *psp) { + struct dhcpcd_ctx *ctx = psp->psp_ctx; + + TAILQ_REMOVE(&ctx->ps_processes, psp, next); - TAILQ_REMOVE(&psp->psp_ctx->ps_processes, psp, next); if (psp->psp_fd != -1) { - eloop_event_delete(psp->psp_ctx->eloop, psp->psp_fd); + eloop_event_delete(ctx->eloop, psp->psp_fd); close(psp->psp_fd); } if (psp->psp_work_fd != -1) { - eloop_event_delete(psp->psp_ctx->eloop, psp->psp_work_fd); + eloop_event_delete(ctx->eloop, psp->psp_work_fd); close(psp->psp_work_fd); } +#ifdef HAVE_CAPSICUM + if (psp->psp_pfd != -1) { + eloop_event_delete(ctx->eloop, psp->psp_pfd); + if (ctx->ps_eloop != NULL) + eloop_event_delete(ctx->ps_eloop, psp->psp_pfd); + close(psp->psp_pfd); + } +#endif + if (ctx->ps_root == psp) + ctx->ps_root = NULL; + if (ctx->ps_inet == psp) + ctx->ps_inet = NULL; + if (ctx->ps_ctl == psp) + ctx->ps_ctl = NULL; #ifdef INET if (psp->psp_bpf != NULL) bpf_close(psp->psp_bpf); @@ -649,12 +812,23 @@ ps_freeprocess(struct ps_process *psp) static void ps_free(struct dhcpcd_ctx *ctx) { - struct ps_process *psp; - bool stop = ctx->ps_root_pid == getpid(); + struct ps_process *ppsp, *psp; + bool stop; + + if (ctx->ps_root != NULL) + ppsp = ctx->ps_root; + else if (ctx->ps_ctl != NULL) + ppsp = ctx->ps_ctl; + else + ppsp = NULL; + if (ppsp != NULL) + stop = ppsp->psp_pid == getpid(); + else + stop = false; while ((psp = TAILQ_FIRST(&ctx->ps_processes)) != NULL) { - if (stop) - ps_dostop(ctx, &psp->psp_pid, &psp->psp_fd); + if (stop && psp != ppsp) + ps_stopprocess(psp); ps_freeprocess(psp); } } @@ -760,7 +934,6 @@ ps_sendpsmmsg(struct dhcpcd_ctx *ctx, in len = writev(fd, iov, iovlen); if (len == -1) { - logerr(__func__); if (ctx->options & DHCPCD_FORKED && !(ctx->options & DHCPCD_PRIVSEPROOT)) eloop_exit(ctx->eloop, EXIT_FAILURE); @@ -896,7 +1069,8 @@ nobufs: } ssize_t -ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, uint16_t cmd, int wfd) +ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, unsigned short events, + uint16_t cmd, int wfd) { struct sockaddr_storage ss = { .ss_family = AF_UNSPEC }; uint8_t controlbuf[sizeof(struct sockaddr_storage)] = { 0 }; @@ -909,32 +1083,33 @@ ps_recvmsg(struct dhcpcd_ctx *ctx, int r .msg_control = controlbuf, .msg_controllen = sizeof(controlbuf), .msg_iov = iov, .msg_iovlen = 1, }; + ssize_t len; - ssize_t len = recvmsg(rfd, &msg, 0); + if (!(events & ELE_READ)) + logerrx("%s: unexpected event 0x%04x", __func__, events); + len = recvmsg(rfd, &msg, 0); if (len == -1) logerr("%s: recvmsg", __func__); if (len == -1 || len == 0) { - if (ctx->options & DHCPCD_FORKED && - !(ctx->options & DHCPCD_PRIVSEPROOT)) + if (ctx->options & DHCPCD_FORKED) eloop_exit(ctx->eloop, - len == 0 ? EXIT_SUCCESS : EXIT_FAILURE); + len != -1 ? EXIT_SUCCESS : EXIT_FAILURE); return len; } iov[0].iov_len = (size_t)len; len = ps_sendcmdmsg(wfd, cmd, &msg); if (len == -1) { - logerr("ps_sendcmdmsg"); - if (ctx->options & DHCPCD_FORKED && - !(ctx->options & DHCPCD_PRIVSEPROOT)) + logerr("%s: ps_sendcmdmsg", __func__); + if (ctx->options & DHCPCD_FORKED) eloop_exit(ctx->eloop, EXIT_FAILURE); } return len; } ssize_t -ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd, +ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd, unsigned short events, ssize_t (*callback)(void *, struct ps_msghdr *, struct msghdr *), void *cbctx) { @@ -945,6 +1120,9 @@ ps_recvpsmsg(struct dhcpcd_ctx *ctx, int struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1 }; bool stop = false; + if (!(events & ELE_READ)) + logerrx("%s: unexpected event 0x%04x", __func__, events); + len = read(fd, &psm, sizeof(psm)); #ifdef PRIVSEP_DEBUG logdebugx("%s: %zd", __func__, len); @@ -966,13 +1144,11 @@ ps_recvpsmsg(struct dhcpcd_ctx *ctx, int } if (stop) { + ctx->options |= DHCPCD_EXITING; #ifdef PRIVSEP_DEBUG logdebugx("process %d stopping", getpid()); #endif ps_free(ctx); -#ifdef PLUGIN_DEV - dev_stop(ctx); -#endif eloop_exit(ctx->eloop, len != -1 ? EXIT_SUCCESS : EXIT_FAILURE); return len; } @@ -994,6 +1170,8 @@ ps_findprocess(struct dhcpcd_ctx *ctx, s struct ps_process *psp; TAILQ_FOREACH(psp, &ctx->ps_processes, next) { + if (!(psp->psp_started)) + continue; if (memcmp(&psp->psp_id, psid, sizeof(psp->psp_id)) == 0) return psp; } @@ -1002,6 +1180,19 @@ ps_findprocess(struct dhcpcd_ctx *ctx, s } struct ps_process * +ps_findprocesspid(struct dhcpcd_ctx *ctx, pid_t pid) +{ + struct ps_process *psp; + + TAILQ_FOREACH(psp, &ctx->ps_processes, next) { + if (psp->psp_pid == pid) + return psp; + } + errno = ESRCH; + return NULL; +} + +struct ps_process * ps_newprocess(struct dhcpcd_ctx *ctx, struct ps_id *psid) { struct ps_process *psp; @@ -1012,6 +1203,12 @@ ps_newprocess(struct dhcpcd_ctx *ctx, st psp->psp_ctx = ctx; memcpy(&psp->psp_id, psid, sizeof(psp->psp_id)); psp->psp_work_fd = -1; +#ifdef HAVE_CAPSICUM + psp->psp_pfd = -1; +#endif + + if (!(ctx->options & DHCPCD_MANAGER)) + strlcpy(psp->psp_ifname, ctx->ifv[0], sizeof(psp->psp_name)); TAILQ_INSERT_TAIL(&ctx->ps_processes, psp, next); return psp; } Index: src/external/bsd/dhcpcd/dist/src/logerr.c diff -u src/external/bsd/dhcpcd/dist/src/logerr.c:1.12 src/external/bsd/dhcpcd/dist/src/logerr.c:1.13 --- src/external/bsd/dhcpcd/dist/src/logerr.c:1.12 Fri Oct 22 13:23:20 2021 +++ src/external/bsd/dhcpcd/dist/src/logerr.c Fri Apr 21 16:54:26 2023 @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-2-Clause */ /* * logerr: errx with logging - * Copyright (c) 2006-2021 Roy Marples <r...@marples.name> + * Copyright (c) 2006-2023 Roy Marples <r...@marples.name> * All rights reserved * Redistribution and use in source and binary forms, with or without Index: src/external/bsd/dhcpcd/dist/src/script.c diff -u src/external/bsd/dhcpcd/dist/src/script.c:1.14 src/external/bsd/dhcpcd/dist/src/script.c:1.15 --- src/external/bsd/dhcpcd/dist/src/script.c:1.14 Fri Oct 22 13:23:20 2021 +++ src/external/bsd/dhcpcd/dist/src/script.c Fri Apr 21 16:54:26 2023 @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-2-Clause */ /* * dhcpcd - DHCP client daemon - * Copyright (c) 2006-2021 Roy Marples <r...@marples.name> + * Copyright (c) 2006-2023 Roy Marples <r...@marples.name> * All rights reserved * Redistribution and use in source and binary forms, with or without