Merge branch 'master' into manager_only

This commit is contained in:
Roy Marples 2024-06-15 14:09:31 +01:00
commit 66811c7b9b
33 changed files with 725 additions and 163 deletions

View File

@ -78,7 +78,14 @@ static int _dhcpcd_rand_fd = -1; /* /dev/urandom fd */
static int _dhcpcd_getentropy(void *, size_t);
static inline int _rs_allocate(struct _rs **, struct _rsx **);
/* dhcpcd needs to hold onto the fd at fork due to privsep */
#if 0
static inline void _rs_forkdetect(void);
#else
#define _rs_forkdetect()
#define _rs_forkhandler()
#endif
/* Inline "arc4random.h" */
#include <sys/types.h>
@ -89,7 +96,6 @@ static inline void _rs_rekey(u_char *dat, size_t datlen);
/* dhcpcd isn't multithreaded */
#define _ARC4_LOCK()
#define _ARC4_UNLOCK()
#define _ARC4_ATFORK(f)
static int
_dhcpcd_getentropy(void *buf, size_t length)
@ -126,6 +132,7 @@ _getentropy_fail(void)
raise(SIGKILL);
}
#if 0
static volatile sig_atomic_t _rs_forked;
static inline void
@ -148,6 +155,7 @@ _rs_forkdetect(void)
memset(rs, 0, sizeof(*rs));
}
}
#endif
static inline int
_rs_allocate(struct _rs **rsp, struct _rsx **rsxp)
@ -163,7 +171,7 @@ _rs_allocate(struct _rs **rsp, struct _rsx **rsxp)
return (-1);
}
_ARC4_ATFORK(_rs_forkhandler);
_rs_forkhandler();
return (0);
}

77
compat/closefrom.c Normal file
View File

@ -0,0 +1,77 @@
/*
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004-2005, 2007, 2010, 2012-2015, 2017-2018
* Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "config.h"
#ifdef __linux__
# include <sys/syscall.h>
# if defined(__NR_close_range) && !defined(SYS_close_range)
# define SYS_close_range __NR_close_range
# endif
#endif
#include <fcntl.h>
#include <unistd.h>
#if defined(__linux__) && defined(SYS_close_range)
static inline int
sys_close_range(unsigned int fd, unsigned int max_fd, unsigned int flags)
{
return (int)syscall(SYS_close_range, fd, max_fd, flags);
}
#endif
/*
* Close all file descriptors greater than or equal to lowfd.
* This is the expensive (fallback) method.
*/
static int
closefrom_fallback(int lowfd)
{
int fd, maxfd;
#ifdef _SC_OPEN_MAX
maxfd = (int)sysconf(_SC_OPEN_MAX);
#else
maxfd = getdtablesize();
#endif
if (maxfd == -1)
return -1;
for (fd = lowfd; fd < maxfd; fd++)
close(fd);
return 0;
}
/*
* * Close all file descriptors greater than or equal to lowfd.
* * We try the fast way first, falling back on the slow method.
* */
void
closefrom(int lowfd)
{
#if defined(__linux__) && defined(SYS_close_range)
if (sys_close_range((unsigned int)lowfd, UINT_MAX, 0) == 0)
return;
#endif
closefrom_fallback(lowfd);
}

24
compat/closefrom.h Normal file
View File

@ -0,0 +1,24 @@
/*
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004-2005, 2007, 2010, 2012-2015, 2017-2018
* Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef CLOSEFROM_H
#define CLOSEFROM_H
void closefrom(int);
#endif

29
configure vendored
View File

@ -33,6 +33,7 @@ STATIC=
DEVS=
EMBEDDED=
AUTH=
NTP=
POLL=
SMALL=
SANITIZE=no
@ -74,6 +75,8 @@ for x do
--enable-privsep) PRIVSEP=yes;;
--disable-seccomp) SECCOMP=no;;
--enable-seccomp) SECCOMP=yes;;
--disable-ntp) NTP=no;;
--enable-ntp) NTP=yes;;
--privsepuser) PRIVSEP_USER=$var;;
--prefix) PREFIX=$var;prefix=$var;; # prefix is set for autotools compat
--sysconfdir) SYSCONFDIR=$var;;
@ -811,6 +814,28 @@ fi
rm -f _clock_gettime.c _clock_gettime
$abort && exit 1
if [ -z "$CLOSEFROM" ]; then
printf "Testing for closefrom ... "
cat <<EOF >_closefrom.c
#include <unistd.h>
int main(void) {
closefrom(3);
return 0;
}
EOF
if $XCC _closefrom.c -o _closefrom 2>&3; then
CLOSEFROM=yes
else
CLOSEFROM=no
fi
echo "$CLOSEFROM"
fi
rm -f _closefrom.c _closefrom
if [ "$CLOSEFROM" = no ]; then
echo "COMPAT_SRCS+= compat/closefrom.c" >>$CONFIG_MK
echo "#include \"compat/closefrom.h\"" >>$CONFIG_H
fi
printf "Testing ioctl request type ... "
cat <<EOF >_ioctl.c
#include <sys/ioctl.h>
@ -1921,6 +1946,10 @@ if ! $HOOKSET; then
fi
fi
fi
if [ "$NTP" = yes ]; then
# --enable-ntp
echo "UNCOMMENT_NTP= yes" >>$CONFIG_MK
fi
echo >>$CONFIG_H
echo "#endif /*CONFIG_H*/">>$CONFIG_H

View File

@ -106,8 +106,8 @@ if [ "$ifwireless" = "1" ] && \
command -v wpa_cli >/dev/null 2>&1
then
case "$reason" in
PREINIT) wpa_supplicant_start;;
RECONFIGURE) wpa_supplicant_reconfigure;;
DEPARTED) wpa_supplicant_stop;;
PREINIT) wpa_supplicant_start;;
RECONFIGURE) wpa_supplicant_reconfigure;;
DEPARTED|STOPPED) wpa_supplicant_stop;;
esac
fi

View File

@ -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

View File

@ -96,8 +96,14 @@ _maninstall: ${MAN5} ${MAN8}
_confinstall:
${INSTALL} -d ${DESTDIR}${SYSCONFDIR}
# Install a new default config if not present
test -e ${DESTDIR}${SYSCONFDIR}/dhcpcd.conf || \
${INSTALL} -m ${CONFMODE} dhcpcd.conf ${DESTDIR}${SYSCONFDIR}
if ! [ -e ${DESTDIR}${SYSCONFDIR}/dhcpcd.conf ]; then \
${INSTALL} -m ${CONFMODE} dhcpcd.conf ${DESTDIR}${SYSCONFDIR}; \
if [ "${UNCOMMENT_NTP}" = yes ]; then \
${SED} -i \
-e 's/#option ntp_servers/option ntp_servers/' \
${DESTDIR}/${SYSCONFDIR}/dhcpcd.conf; \
fi; \
fi
eginstall:

View File

@ -29,7 +29,7 @@
#define DEFS_H
#define PACKAGE "dhcpcd"
#define VERSION "10.0.6"
#define VERSION "10.0.8"
#ifndef PRIVSEP_USER
# define PRIVSEP_USER "_" PACKAGE

View File

@ -1867,13 +1867,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)
@ -1904,11 +1904,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);
}
@ -1934,7 +1936,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
@ -2085,8 +2091,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
@ -2677,7 +2687,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)
@ -3134,8 +3144,8 @@ dhcp_handledhcp(struct interface *ifp, struct bootp *bootp, size_t bootp_len,
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];
@ -3443,12 +3453,6 @@ dhcp_handlebootp(struct interface *ifp, struct bootp *bootp, size_t len,
{
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",
@ -3581,6 +3585,13 @@ dhcp_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg)
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. */

View File

@ -180,6 +180,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_startdecline(struct interface *);
static void dhcp6_startrequest(struct interface *);
#ifdef SMALL
#define dhcp6_hasprefixdelegation(a) (0)
@ -1416,10 +1417,37 @@ dhcp6_sendinform(void *arg)
}
static void
dhcp6_senddiscover(void *arg)
dhcp6_senddiscover2(void *arg)
{
dhcp6_sendmessage(arg, dhcp6_senddiscover);
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,
state->IMD != 0 ? dhcp6_senddiscover : dhcp6_senddiscover1);
}
static void
@ -1878,7 +1906,6 @@ dhcp6_startrebind(void *arg)
#endif
}
static void
dhcp6_startrequest(struct interface *ifp)
{
@ -3431,6 +3458,16 @@ dhcp6_recvif(struct interface *ifp, const char *sfrom,
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 ADVERTISEMENT from %s",
ifp->name, sfrom);
return;
}
/* RFC7083 */
o = dhcp6_findmoption(r, len, D6_OPTION_SOL_MAX_RT, &ol);
if (o && ol == sizeof(uint32_t)) {
@ -3556,7 +3593,7 @@ dhcp6_recvif(struct interface *ifp, const char *sfrom,
else
loginfox("%s: ADV %s from %s",
ifp->name, ia->saddr, sfrom);
dhcp6_startrequest(ifp);
// We will request when the IRT elapses
return;
}
@ -3739,7 +3776,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;
@ -3913,20 +3950,16 @@ dhcp6_start(struct interface *ifp, enum DH6S init_state)
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 &&
@ -4178,6 +4211,7 @@ dhcp6_env(FILE *fp, const char *prefix, const struct interface *ifp,
#ifndef SMALL
const struct dhcp6_state *state;
const struct ipv6_addr *ap;
bool first;
#endif
if (m == NULL)
@ -4279,10 +4313,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;
}

View File

@ -12,7 +12,7 @@ define 1 request ipaddress subnet_mask
# RFC3442 states that the CSR has to come before all other routes
# For completeness we also specify static routes then routers
define 121 rfc3442 classless_static_routes
define 2 uint32 time_offset
define 2 int32 time_offset
define 3 request array ipaddress routers
define 4 array ipaddress time_servers
define 5 array ipaddress ien116_name_servers
@ -333,7 +333,16 @@ encap 255 flag global
# Options 222 and 223 are unused, RFC3942
# Options 224-254 are reserved for Private Use
# Options 224-254 are reserved for site-specific use by RFC3942.
# For historical reasons, some of these options have well known
# definitions and we implement those definitions here.
# Site-specific options are designed to be configured by the end user
# if needed and any configuration here may change in the future.
# Option 245 is an IANA assigned private number used by Azure DHCP
# servers to provide the IPv4 address of the Azure WireServer endpoint
# to virtual machines hosted in Azure.
define 245 ipaddress azureendpoint
# Option 249 is an IANA assigned private number used by Windows DHCP servers
# to provide the exact same information as option 121, classless static routes
@ -344,6 +353,38 @@ define 249 rfc3442 ms_classless_static_routes
# Apparently the code was assigned by agreement of the DHC working group chair.
define 252 uri wpad_url
define 224 binhex site_specific_224
define 225 binhex site_specific_225
define 226 binhex site_specific_226
define 227 binhex site_specific_227
define 228 binhex site_specific_228
define 229 binhex site_specific_229
define 230 binhex site_specific_230
define 231 binhex site_specific_231
define 232 binhex site_specific_232
define 233 binhex site_specific_233
define 234 binhex site_specific_234
define 235 binhex site_specific_235
define 236 binhex site_specific_236
define 237 binhex site_specific_237
define 238 binhex site_specific_238
define 239 binhex site_specific_239
define 240 binhex site_specific_240
define 241 binhex site_specific_241
define 242 binhex site_specific_242
define 243 binhex site_specific_243
define 244 binhex site_specific_244
#Option 245 has a custom definition above.
define 246 binhex site_specific_246
define 247 binhex site_specific_247
define 248 binhex site_specific_248
#Option 249 has a custom definition above.
define 250 binhex site_specific_250
define 251 binhex site_specific_251
#Option 252 has a custom definition above.
define 253 binhex site_specific_253
define 254 binhex site_specific_254
# Option 255 End
##############################################################################

View File

@ -390,30 +390,43 @@ 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)
{
@ -1490,7 +1503,8 @@ dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd,
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;
@ -1619,20 +1633,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;
}
@ -1925,6 +1959,7 @@ main(int argc, char **argv, char **envp)
}
memset(&ctx, 0, sizeof(ctx));
closefrom(STDERR_FILENO + 1);
ifo = NULL;
ctx.cffile = CONFIG;
@ -1954,7 +1989,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
@ -2356,9 +2391,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(PIDFILE)) != 0) {
@ -2555,10 +2595,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

View File

@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd December 21, 2023
.Dd May 24, 2024
.Dt DHCPCD.CONF 5
.Os
.Sh NAME
@ -305,6 +305,10 @@ You can use this option to stop this from happening.
.It Ic fallback Ar profile
Fall back to using this profile if DHCP fails.
This allows you to configure a static profile instead of using ZeroConf.
.It Ic fallback_time Ar seconds
Start fallback after
.Ar seconds .
The default is 5 seconds.
.It Ic hostname Ar name
Sends the hostname
.Ar name
@ -442,6 +446,11 @@ encodes the FQDN hostname as specified in
.It Ic interface Ar interface
Subsequent options are only parsed for this
.Ar interface .
.It Ic ipv4ll_time Ar seconds
Wait for
.Ar seconds
before starting IPv4LL.
The default is 5 seconds.
.It Ic ipv6ra_autoconf
Generate SLAAC addresses for each Prefix advertised by an IPv6
Router Advertisement message with the Auto flag set.
@ -649,6 +658,11 @@ Use
.Ar script
instead of the default
.Pa @SCRIPT@ .
.It Ic request_time Ar seconds
Request the lease for
.Ar seconds
before going back to DISCOVER.
The default is 180 seconds.
.It Ic ssid Ar ssid
Subsequent options are only parsed for this wireless
.Ar ssid .

View File

@ -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 *ctx)
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;

View File

@ -69,7 +69,7 @@ if_getssid_wext(const char *ifname, uint8_t *ssid)
int s, retval;
struct iwreq iwr;
if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
if ((s = xsocket(PF_INET, SOCK_DGRAM, 0)) == -1)
return -1;
memset(&iwr, 0, sizeof(iwr));
strlcpy(iwr.ifr_name, ifname, sizeof(iwr.ifr_name));

View File

@ -500,15 +500,22 @@ setup_priv:
void
if_closesockets_os(struct dhcpcd_ctx *ctx)
{
struct priv *priv;
struct priv *priv = ctx->priv;
if (ctx->priv != NULL) {
priv = (struct priv *)ctx->priv;
if (priv->route_fd != -1)
close(priv->route_fd);
if (priv->generic_fd != -1)
close(priv->generic_fd);
if (priv == NULL)
return;
if (priv->route_fd != -1) {
close(priv->route_fd);
priv->route_fd = -1;
}
if (priv->generic_fd != -1) {
close(priv->generic_fd);
priv->generic_fd = -1;
}
free(priv);
ctx->priv = NULL;
}
int
@ -2154,17 +2161,16 @@ if_setup_inet6(const struct interface *ifp)
int ra;
char path[256];
/* The kernel cannot make stable private addresses.
/* Modern linux kernels can make a stable private address.
* However, a lot of distros ship newer kernel headers than
* the kernel itself so sweep that error under the table. */
* the kernel itself so we sweep that error under the table
* from old kernels and just make them ourself regardless. */
if (if_disable_autolinklocal(ctx, ifp->index) == -1 &&
errno != ENODEV && errno != ENOTSUP && errno != EINVAL)
logdebug("%s: if_disable_autolinklocal", ifp->name);
/*
* If not doing autoconf, don't disable the kernel from doing it.
* If we need to, we should have another option actively disable it.
*/
/* If not doing autoconf, don't disable the kernel from doing it.
* If we need to, we should have another option actively disable it. */
if (!(ifp->options->options & DHCPCD_IPV6RS))
return;

View File

@ -169,6 +169,9 @@ const struct option cf_options[] = {
{"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 +2340,35 @@ invalid_token:
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 +2452,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 +2498,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 +2506,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 |

View File

@ -49,6 +49,9 @@
#define DEFAULT_TIMEOUT 30
#define DEFAULT_REBOOT 5
#define DEFAULT_REQUEST 180 /* secs to request, mirror DHCP6 */
#define DEFAULT_FALLBACK 5 /* secs until fallback */
#define DEFAULT_IPV4LL 5 /* secs until ipv4ll */
#ifndef HOSTNAME_MAX_LEN
#define HOSTNAME_MAX_LEN 250 /* 255 - 3 (FQDN) - 2 (DNS enc) */
@ -185,6 +188,9 @@
#define O_NOCONFIGURE O_BASE + 51
#define O_RANDOMISE_HWADDR O_BASE + 52
#define O_ARP_PERSISTDEFENCE O_BASE + 53
#define O_REQUEST_TIME O_BASE + 54
#define O_FALLBACK_TIME O_BASE + 55
#define O_IPV4LL_TIME O_BASE + 56
extern const struct option cf_options[];
@ -236,6 +242,9 @@ struct if_options {
uint32_t leasetime;
uint32_t timeout;
uint32_t reboot;
uint32_t request_time;
uint32_t fallback_time;
uint32_t ipv4ll_time;
unsigned long long options;
bool randomise_hwaddr;

View File

@ -154,7 +154,7 @@ if_opensockets_os(struct dhcpcd_ctx *ctx)
* We will fail noisily elsewhere anyway. */
#endif
ctx->link_fd = socket(PF_ROUTE,
ctx->link_fd = xsocket(PF_ROUTE,
SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
if (ctx->link_fd == -1) {
@ -180,12 +180,13 @@ if_closesockets_os(struct dhcpcd_ctx *ctx)
struct priv *priv;
priv = (struct priv *)ctx->priv;
if (priv->pf_inet6_fd != -1)
if (priv && priv->pf_inet6_fd != -1)
close(priv->pf_inet6_fd);
#endif
/* each interface should have closed itself */
free(ctx->priv);
ctx->priv = NULL;
}
int
@ -727,7 +728,7 @@ if_route_get(struct dhcpcd_ctx *ctx, struct rt *rt)
if_route0(ctx, &rtm, RTM_GET, rt);
rt = NULL;
s = socket(PF_ROUTE, SOCK_RAW | SOCK_CLOEXEC, 0);
s = xsocket(PF_ROUTE, SOCK_RAW | SOCK_CLOEXEC, 0);
if (s == -1)
return NULL;
if (write(s, &rtm, rtm.hdr.rtm_msglen) == -1)

View File

@ -132,17 +132,18 @@ void
if_closesockets(struct dhcpcd_ctx *ctx)
{
if (ctx->pf_inet_fd != -1)
close(ctx->pf_inet_fd);
#ifdef PF_LINK
if (ctx->pf_link_fd != -1)
close(ctx->pf_link_fd);
#endif
if (ctx->priv) {
if_closesockets_os(ctx);
free(ctx->priv);
if (ctx->link_fd != -1) {
eloop_event_delete(ctx->eloop, ctx->link_fd);
close(ctx->link_fd);
ctx->link_fd = -1;
}
if (ctx->pf_inet_fd != -1) {
close(ctx->pf_inet_fd);
ctx->pf_inet_fd = -1;
}
if_closesockets_os(ctx);
}
int
@ -982,6 +983,10 @@ xsocket(int domain, int type, int protocol)
if ((s = socket(domain, type, protocol)) == -1)
return -1;
#ifdef DEBUG_FD
logerrx("pid %d fd=%d domain=%d type=%d protocol=%d",
getpid(), s, domain, type, protocol);
#endif
#ifndef HAVE_SOCK_CLOEXEC
if ((xtype & SOCK_CLOEXEC) && ((xflags = fcntl(s, F_GETFD)) == -1 ||
@ -1023,6 +1028,10 @@ xsocketpair(int domain, int type, int protocol, int fd[2])
if ((s = socketpair(domain, type, protocol, fd)) == -1)
return -1;
#ifdef DEBUG_FD
logerrx("pid %d fd[0]=%d fd[1]=%d", getpid(), fd[0], fd[1]);
#endif
#ifndef HAVE_SOCK_CLOEXEC
if ((xtype & SOCK_CLOEXEC) && ((xflags = fcntl(fd[0], F_GETFD)) == -1 ||
fcntl(fd[0], F_SETFD, xflags | FD_CLOEXEC) == -1))

View File

@ -2311,7 +2311,9 @@ inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx)
{
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;
@ -2319,6 +2321,27 @@ inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx)
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;
@ -2326,11 +2349,13 @@ inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx)
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)
@ -2340,7 +2365,7 @@ inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx)
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);
}

View File

@ -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) == 8);
//
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 *ctx)
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, int remove_ra, int drop_ra)
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);
@ -1689,7 +1750,7 @@ ipv6nd_env(FILE *fp, const struct interface *ifp)
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" : "",
@ -1794,6 +1855,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;
@ -1813,7 +1875,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) {
@ -1869,6 +1932,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);
@ -2125,3 +2202,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);
}
}

View File

@ -37,6 +37,20 @@
#include "dhcpcd.h"
#include "ipv6.h"
/* rfc4191 */
struct routeinfo {
TAILQ_ENTRY(routeinfo) next;
struct in6_addr prefix;
uint8_t prefix_len;
uint32_t lifetime;
uint8_t flags;
struct timespec acquired;
char sprefix[INET6_ADDRSTRLEN];
};
TAILQ_HEAD(routeinfohead, routeinfo);
struct ra {
TAILQ_ENTRY(ra) next;
struct interface *iface;
@ -45,13 +59,14 @@ struct ra {
uint8_t *data;
size_t data_len;
struct timespec acquired;
unsigned char flags;
uint8_t flags;
uint32_t lifetime;
uint32_t reachable;
uint32_t retrans;
uint32_t mtu;
uint8_t hoplimit;
struct ipv6_addrhead addrs;
struct routeinfohead rinfos;
bool hasdns;
bool expired;
bool willexpire;
@ -105,7 +120,7 @@ int ipv6nd_open(bool);
int ipv6nd_openif(struct interface *);
#endif
void ipv6nd_recvmsg(struct dhcpcd_ctx *, struct msghdr *);
int ipv6nd_rtpref(struct ra *);
int ipv6nd_rtpref(uint8_t);
void ipv6nd_printoptions(const struct dhcpcd_ctx *,
const struct dhcp_opt *, size_t);
void ipv6nd_startrs(struct interface *);

View File

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

View File

@ -53,6 +53,8 @@
#include "logerr.h"
#include "privsep.h"
/* We expect to have open 3 SEQPACKET and one RAW fd */
static void
ps_bpf_recvbpf(void *arg, unsigned short events)
{
@ -160,6 +162,9 @@ ps_bpf_start_bpf(struct ps_process *psp)
ps_freeprocesses(ctx, psp);
psp->psp_bpf = bpf_open(&psp->psp_ifp, psp->psp_filter, ia);
#ifdef DEBUG_FD
logdebugx("pid %d bpf_fd=%d", getpid(), psp->psp_bpf->bpf_fd);
#endif
if (psp->psp_bpf == NULL)
logerr("%s: bpf_open",__func__);
#ifdef PRIVSEP_RIGHTS

View File

@ -36,6 +36,8 @@
#include "logerr.h"
#include "privsep.h"
/* We expect to have open 2 SEQPACKET, 2 STREAM and 2 file STREAM fds */
static int
ps_ctl_startcb(struct ps_process *psp)
{
@ -198,14 +200,16 @@ ps_ctl_start(struct dhcpcd_ctx *ctx)
.psi_cmd = PS_CTL,
};
struct ps_process *psp;
int data_fd[2], listen_fd[2];
int work_fd[2], listen_fd[2];
pid_t pid;
if (xsocketpair(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0, data_fd) == -1 ||
if_closesockets(ctx);
if (xsocketpair(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0, work_fd) == -1 ||
xsocketpair(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0, listen_fd) == -1)
return -1;
#ifdef PRIVSEP_RIGHTS
if (ps_rights_limit_fdpair(data_fd) == -1 ||
if (ps_rights_limit_fdpair(work_fd) == -1 ||
ps_rights_limit_fdpair(listen_fd) == -1)
return -1;
#endif
@ -218,24 +222,25 @@ ps_ctl_start(struct dhcpcd_ctx *ctx)
if (pid == -1)
return -1;
else if (pid != 0) {
psp->psp_work_fd = data_fd[1];
close(data_fd[0]);
psp->psp_work_fd = work_fd[0];
close(work_fd[1]);
close(listen_fd[1]);
ctx->ps_control = control_new(ctx,
listen_fd[1], FD_SENDLEN | FD_LISTEN);
listen_fd[0], FD_SENDLEN | FD_LISTEN);
if (ctx->ps_control == NULL)
return -1;
close(listen_fd[0]);
return pid;
}
psp->psp_work_fd = data_fd[0];
close(data_fd[1]);
close(work_fd[0]);
close(listen_fd[0]);
psp->psp_work_fd = work_fd[1];
if (eloop_event_add(ctx->eloop, psp->psp_work_fd, ELE_READ,
ps_ctl_recv, ctx) == -1)
return -1;
ctx->ps_control = control_new(ctx, listen_fd[0], 0);
close(listen_fd[1]);
ctx->ps_control = control_new(ctx, listen_fd[1], 0);
if (ctx->ps_control == NULL)
return -1;
if (eloop_event_add(ctx->eloop, ctx->ps_control->fd, ELE_READ,

View File

@ -47,6 +47,8 @@
#include "logerr.h"
#include "privsep.h"
/* We expect to have open 2 SEQPACKET, 1 udp, 1 udp6 and 1 raw6 fds */
#ifdef INET
static void
ps_inet_recvbootp(void *arg, unsigned short events)

View File

@ -259,7 +259,7 @@ ps_root_doioctl(unsigned long req, void *data, size_t len)
return -1;
}
s = socket(PF_INET, SOCK_DGRAM, 0);
s = xsocket(PF_INET, SOCK_DGRAM, 0);
if (s != -1)
#ifdef IOCTL_REQUEST_TYPE
{
@ -679,17 +679,6 @@ ps_root_startcb(struct ps_process *psp)
if (if_opensockets(ctx) == -1)
logerr("%s: if_opensockets", __func__);
#ifdef BSD
else {
/* 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
/* Open network sockets for sending.
* This is a small bit wasteful for non sandboxed OS's
@ -892,7 +881,7 @@ ps_root_start(struct dhcpcd_ctx *ctx)
return -1;
#endif
if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CXNB, 0, datafd) == -1)
if (xsocketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CXNB, 0, datafd) == -1)
return -1;
if (ps_setbuf_fdpair(datafd) == -1)
return -1;
@ -930,6 +919,32 @@ ps_root_start(struct dhcpcd_ctx *ctx)
return pid;
}
void
ps_root_close(struct dhcpcd_ctx *ctx)
{
if_closesockets(ctx);
#ifdef INET
if (ctx->udp_wfd != -1) {
close(ctx->udp_wfd);
ctx->udp_wfd = -1;
}
#endif
#ifdef INET6
if (ctx->nd_fd != -1) {
close(ctx->nd_fd);
ctx->nd_fd = -1;
}
#endif
#ifdef DHCP6
if (ctx->dhcp6_wfd != -1) {
close(ctx->dhcp6_wfd);
ctx->dhcp6_wfd = -1;
}
#endif
}
int
ps_root_stop(struct dhcpcd_ctx *ctx)
{

View File

@ -36,6 +36,7 @@
#endif
pid_t ps_root_start(struct dhcpcd_ctx *ctx);
void ps_root_close(struct dhcpcd_ctx *ctx);
int ps_root_stop(struct dhcpcd_ctx *ctx);
void ps_root_signalcb(int, void *);

View File

@ -45,7 +45,7 @@ ps_root_doioctl6(unsigned long req, void *data, size_t len)
{
int s, err;
s = socket(PF_INET6, SOCK_DGRAM, 0);
s = xsocket(PF_INET6, SOCK_DGRAM, 0);
if (s != -1)
err = ioctl(s, req, data, len);
else
@ -63,7 +63,7 @@ ps_root_doroute(void *data, size_t len)
int s;
ssize_t err;
s = socket(PF_ROUTE, SOCK_RAW, 0);
s = xsocket(PF_ROUTE, SOCK_RAW, 0);
if (s != -1)
err = write(s, data, len);
else

View File

@ -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)
{
@ -1206,6 +1202,7 @@ ps_newprocess(struct dhcpcd_ctx *ctx, struct ps_id *psid)
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;

View File

@ -300,11 +300,39 @@ sa_toprefix(const struct sockaddr *sa)
return prefix;
}
static void
ipbytes_fromprefix(uint8_t *ap, int prefix, int max_prefix)
{
int bytes, bits, i;
bytes = prefix / NBBY;
bits = prefix % NBBY;
for (i = 0; i < bytes; i++)
*ap++ = 0xff;
if (bits) {
uint8_t a;
a = 0xff;
a = (uint8_t)(a << (8 - bits));
*ap++ = a;
}
bytes = (max_prefix - prefix) / NBBY;
for (i = 0; i < bytes; i++)
*ap++ = 0x00;
}
void
in6_addr_fromprefix(struct in6_addr *addr, int prefix)
{
ipbytes_fromprefix((uint8_t *)addr, prefix, 128);
}
int
sa_fromprefix(struct sockaddr *sa, int prefix)
{
uint8_t *ap;
int max_prefix, bytes, bits, i;
int max_prefix;
switch (sa->sa_family) {
#ifdef INET
@ -328,22 +356,8 @@ sa_fromprefix(struct sockaddr *sa, int prefix)
return -1;
}
bytes = prefix / NBBY;
bits = prefix % NBBY;
ap = (uint8_t *)sa + sa_addroffset(sa);
for (i = 0; i < bytes; i++)
*ap++ = 0xff;
if (bits) {
uint8_t a;
a = 0xff;
a = (uint8_t)(a << (8 - bits));
*ap++ = a;
}
bytes = (max_prefix - prefix) / NBBY;
for (i = 0; i < bytes; i++)
*ap++ = 0x00;
ipbytes_fromprefix(ap, prefix, max_prefix);
#ifndef NDEBUG
/* Ensure the calculation is correct */

View File

@ -67,6 +67,7 @@ bool sa_is_loopback(const struct sockaddr *);
void *sa_toaddr(struct sockaddr *);
int sa_toprefix(const struct sockaddr *);
int sa_fromprefix(struct sockaddr *, int);
void in6_addr_fromprefix(struct in6_addr *, int);
const char *sa_addrtop(const struct sockaddr *, char *, socklen_t);
int sa_cmp(const struct sockaddr *, const struct sockaddr *);
void sa_in_init(struct sockaddr *, const struct in_addr *);