Update to dhcpcd-9.2.0 with the following changes:
* route: ensure IPv4LL routes come last in priority * DHCP: fix many issues with extending the last lease * privsep: don't read control group from config in privsep * privsep: only the master process responds to signals * privsep: use a socketpair for stderr/stdin rather than dupping /dev/null * privsep: right limit stdin/stderr/stdout * privsep: dumping a lease is now run in a sandbox * options: check if kernel supports INET or INET6 before enabling default * options: let clientid override a prior duid * options: allow -1 to represent infinity for requested lease time * dhcpcd: fix a crash initing a new interface after route overflow
This commit is contained in:
parent
61b23c6195
commit
cd40ae1fd5
|
@ -29,7 +29,7 @@
|
|||
#define CONFIG_H
|
||||
|
||||
#define PACKAGE "dhcpcd"
|
||||
#define VERSION "9.1.4"
|
||||
#define VERSION "9.2.0"
|
||||
|
||||
#ifndef PRIVSEP_USER
|
||||
# define PRIVSEP_USER "_" PACKAGE
|
||||
|
|
|
@ -777,7 +777,7 @@ make_message(struct bootp **bootpm, const struct interface *ifp, uint8_t type)
|
|||
(type == DHCP_REQUEST &&
|
||||
state->addr->mask.s_addr == lease->mask.s_addr &&
|
||||
(state->new == NULL || IS_DHCP(state->new)) &&
|
||||
!(state->added & STATE_FAKE))))
|
||||
!(state->added & (STATE_FAKE | STATE_EXPIRED)))))
|
||||
bootp->ciaddr = state->addr->addr.s_addr;
|
||||
|
||||
bootp->op = BOOTREQUEST;
|
||||
|
@ -836,7 +836,7 @@ make_message(struct bootp **bootpm, const struct interface *ifp, uint8_t type)
|
|||
if (type == DHCP_DECLINE ||
|
||||
(type == DHCP_REQUEST &&
|
||||
(state->addr == NULL ||
|
||||
state->added & STATE_FAKE ||
|
||||
state->added & (STATE_FAKE | STATE_EXPIRED) ||
|
||||
lease->addr.s_addr != state->addr->addr.s_addr)))
|
||||
{
|
||||
putip = true;
|
||||
|
@ -1745,7 +1745,7 @@ send_message(struct interface *ifp, uint8_t type,
|
|||
goto fail;
|
||||
len = (size_t)r;
|
||||
|
||||
if (!(state->added & STATE_FAKE) &&
|
||||
if (!(state->added & (STATE_FAKE | STATE_EXPIRED)) &&
|
||||
state->addr != NULL &&
|
||||
ipv4_iffindaddr(ifp, &state->lease.addr, NULL) != NULL)
|
||||
from.s_addr = state->lease.addr.s_addr;
|
||||
|
@ -1869,14 +1869,16 @@ dhcp_discover(void *arg)
|
|||
state->state = DHS_DISCOVER;
|
||||
dhcp_new_xid(ifp);
|
||||
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
|
||||
if (ifo->fallback)
|
||||
eloop_timeout_add_sec(ifp->ctx->eloop,
|
||||
ifo->reboot, dhcp_fallback, ifp);
|
||||
if (!(state->added & STATE_EXPIRED)) {
|
||||
if (ifo->fallback)
|
||||
eloop_timeout_add_sec(ifp->ctx->eloop,
|
||||
ifo->reboot, dhcp_fallback, ifp);
|
||||
#ifdef IPV4LL
|
||||
else if (ifo->options & DHCPCD_IPV4LL)
|
||||
eloop_timeout_add_sec(ifp->ctx->eloop,
|
||||
ifo->reboot, ipv4ll_start, ifp);
|
||||
else if (ifo->options & DHCPCD_IPV4LL)
|
||||
eloop_timeout_add_sec(ifp->ctx->eloop,
|
||||
ifo->reboot, ipv4ll_start, ifp);
|
||||
#endif
|
||||
}
|
||||
if (ifo->options & DHCPCD_REQUEST)
|
||||
loginfox("%s: soliciting a DHCP lease (requesting %s)",
|
||||
ifp->name, inet_ntoa(ifo->req_addr));
|
||||
|
@ -1896,31 +1898,22 @@ dhcp_request(void *arg)
|
|||
send_request(ifp);
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp_expire1(struct interface *ifp)
|
||||
{
|
||||
struct dhcp_state *state = D_STATE(ifp);
|
||||
|
||||
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
|
||||
dhcp_drop(ifp, "EXPIRE");
|
||||
dhcp_unlink(ifp->ctx, state->leasefile);
|
||||
state->interval = 0;
|
||||
if (!(ifp->options->options & DHCPCD_LINK) || ifp->carrier > LINK_DOWN)
|
||||
dhcp_discover(ifp);
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp_expire(void *arg)
|
||||
{
|
||||
struct interface *ifp = arg;
|
||||
struct dhcp_state *state = D_STATE(ifp);
|
||||
|
||||
if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND) {
|
||||
logwarnx("%s: DHCP lease expired, extending lease", ifp->name);
|
||||
return;
|
||||
state->added |= STATE_EXPIRED;
|
||||
} else {
|
||||
logerrx("%s: DHCP lease expired", ifp->name);
|
||||
dhcp_drop(ifp, "EXPIRE");
|
||||
dhcp_unlink(ifp->ctx, state->leasefile);
|
||||
}
|
||||
|
||||
logerrx("%s: DHCP lease expired", ifp->name);
|
||||
dhcp_expire1(ifp);
|
||||
state->interval = 0;
|
||||
dhcp_discover(ifp);
|
||||
}
|
||||
|
||||
#if defined(ARP) || defined(IN_IFF_DUPLICATED)
|
||||
|
@ -2291,7 +2284,9 @@ dhcp_bind(struct interface *ifp)
|
|||
return;
|
||||
}
|
||||
if (state->reason == NULL) {
|
||||
if (state->old && !(state->added & STATE_FAKE)) {
|
||||
if (state->old &&
|
||||
!(state->added & (STATE_FAKE | STATE_EXPIRED)))
|
||||
{
|
||||
if (state->old->yiaddr == state->new->yiaddr &&
|
||||
lease->server.s_addr &&
|
||||
state->state != DHS_REBIND)
|
||||
|
@ -2364,19 +2359,6 @@ dhcp_bind(struct interface *ifp)
|
|||
eloop_event_add(ctx->eloop, state->udp_rfd, dhcp_handleifudp, ifp);
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp_lastlease(void *arg)
|
||||
{
|
||||
struct interface *ifp = arg;
|
||||
struct dhcp_state *state = D_STATE(ifp);
|
||||
|
||||
loginfox("%s: timed out contacting a DHCP server, using last lease",
|
||||
ifp->name);
|
||||
dhcp_bind(ifp);
|
||||
state->interval = 0;
|
||||
dhcp_discover(ifp);
|
||||
}
|
||||
|
||||
static size_t
|
||||
dhcp_message_new(struct bootp **bootp,
|
||||
const struct in_addr *addr, const struct in_addr *mask)
|
||||
|
@ -2475,6 +2457,26 @@ dhcp_arp_bind(struct interface *ifp)
|
|||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
dhcp_lastlease(void *arg)
|
||||
{
|
||||
struct interface *ifp = arg;
|
||||
struct dhcp_state *state = D_STATE(ifp);
|
||||
|
||||
loginfox("%s: timed out contacting a DHCP server, using last lease",
|
||||
ifp->name);
|
||||
#if defined(ARP) || defined(KERNEL_RFC5227)
|
||||
dhcp_arp_bind(ifp);
|
||||
#else
|
||||
dhcp_bind(ifp);
|
||||
#endif
|
||||
/* Set expired here because dhcp_bind() -> ipv4_addaddr() will reset
|
||||
* state */
|
||||
state->added |= STATE_EXPIRED;
|
||||
state->interval = 0;
|
||||
dhcp_discover(ifp);
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp_static(struct interface *ifp)
|
||||
{
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd May 31, 2020
|
||||
.Dd September 2, 2020
|
||||
.Dt DHCPCD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -385,8 +385,10 @@ If no interfaces are left running,
|
|||
.Nm
|
||||
will exit.
|
||||
.It Fl l , Fl Fl leasetime Ar seconds
|
||||
Request a specific lease time in
|
||||
Request a lease time of
|
||||
.Ar seconds .
|
||||
.Ar -1
|
||||
represents an infinite lease time.
|
||||
By default
|
||||
.Nm
|
||||
does not request any lease time and leaves it in the hands of the
|
||||
|
|
|
@ -336,7 +336,7 @@ dhcpcd_daemonise(struct dhcpcd_ctx *ctx)
|
|||
#ifdef THERE_IS_NO_FORK
|
||||
eloop_timeout_delete(ctx->eloop, handle_exit_timeout, ctx);
|
||||
errno = ENOSYS;
|
||||
return 0;
|
||||
return;
|
||||
#else
|
||||
int i;
|
||||
unsigned int logopts = loggetopts();
|
||||
|
@ -361,8 +361,8 @@ dhcpcd_daemonise(struct dhcpcd_ctx *ctx)
|
|||
|
||||
/* Don't use loginfo because this makes no sense in a log. */
|
||||
if (!(logopts & LOGERR_QUIET))
|
||||
(void)fprintf(stderr, "forked to background, child pid %d\n",
|
||||
getpid());
|
||||
(void)fprintf(stderr,
|
||||
"forked to background, child pid %d\n", getpid());
|
||||
i = EXIT_SUCCESS;
|
||||
if (write(ctx->fork_fd, &i, sizeof(i)) == -1)
|
||||
logerr("write");
|
||||
|
@ -371,11 +371,18 @@ dhcpcd_daemonise(struct dhcpcd_ctx *ctx)
|
|||
close(ctx->fork_fd);
|
||||
ctx->fork_fd = -1;
|
||||
|
||||
if (isatty(loggeterrfd())) {
|
||||
logopts &= ~LOGERR_ERR;
|
||||
logsetopts(logopts);
|
||||
logseterrfd(-1);
|
||||
}
|
||||
/*
|
||||
* Stop writing to stderr.
|
||||
* On the happy path, only the master process writes to stderr,
|
||||
* so this just stops wasting fprintf calls to nowhere.
|
||||
* All other calls - ie errors in privsep processes or script output,
|
||||
* will error when printing.
|
||||
* If we *really* want to fix that, then we need to suck
|
||||
* stderr/stdout in the master process and either disacrd it or pass
|
||||
* it to the launcher process and then to stderr.
|
||||
*/
|
||||
logopts &= ~LOGERR_ERR;
|
||||
logsetopts(logopts);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1153,6 +1160,15 @@ dhcpcd_setlinkrcvbuf(struct dhcpcd_ctx *ctx)
|
|||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
dhcpcd_runprestartinterface(void *arg)
|
||||
{
|
||||
struct interface *ifp = arg;
|
||||
|
||||
run_preinit(ifp);
|
||||
dhcpcd_prestartinterface(ifp);
|
||||
}
|
||||
|
||||
void
|
||||
dhcpcd_linkoverflow(struct dhcpcd_ctx *ctx)
|
||||
{
|
||||
|
@ -1215,9 +1231,11 @@ dhcpcd_linkoverflow(struct dhcpcd_ctx *ctx)
|
|||
continue;
|
||||
}
|
||||
TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next);
|
||||
if (ifp->active)
|
||||
if (ifp->active) {
|
||||
dhcpcd_initstate(ifp, 0);
|
||||
eloop_timeout_add_sec(ctx->eloop, 0,
|
||||
dhcpcd_prestartinterface, ifp);
|
||||
dhcpcd_runprestartinterface, ifp);
|
||||
}
|
||||
}
|
||||
free(ifaces);
|
||||
|
||||
|
@ -1765,6 +1783,24 @@ dhcpcd_fork_cb(void *arg)
|
|||
eloop_exit(ctx->eloop, exit_code);
|
||||
}
|
||||
|
||||
static void
|
||||
dhcpcd_stderr_cb(void *arg)
|
||||
{
|
||||
struct dhcpcd_ctx *ctx = arg;
|
||||
char log[BUFSIZ];
|
||||
ssize_t len;
|
||||
|
||||
len = read(ctx->stderr_fd, log, sizeof(log));
|
||||
if (len == -1) {
|
||||
if (errno != ECONNRESET)
|
||||
logerr(__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
log[len] = '\0';
|
||||
fprintf(stderr, "%s", log);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
|
@ -1778,7 +1814,7 @@ main(int argc, char **argv)
|
|||
ssize_t len;
|
||||
#if defined(USE_SIGNALS) || !defined(THERE_IS_NO_FORK)
|
||||
pid_t pid;
|
||||
int sigpipe[2];
|
||||
int fork_fd[2], stderr_fd[2];
|
||||
#endif
|
||||
#ifdef USE_SIGNALS
|
||||
int sig = 0;
|
||||
|
@ -2100,11 +2136,20 @@ printpidfile:
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef PRIVSEP
|
||||
ps_init(&ctx);
|
||||
#endif
|
||||
|
||||
#ifndef SMALL
|
||||
if (ctx.options & DHCPCD_DUMPLEASE &&
|
||||
ioctl(fileno(stdin), FIONREAD, &i, sizeof(i)) == 0 &&
|
||||
i > 0)
|
||||
{
|
||||
ctx.options |= DHCPCD_FORKED; /* pretend child process */
|
||||
#ifdef PRIVSEP
|
||||
if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx) == -1)
|
||||
goto exit_failure;
|
||||
#endif
|
||||
ifp = calloc(1, sizeof(*ifp));
|
||||
if (ifp == NULL) {
|
||||
logerr(__func__);
|
||||
|
@ -2153,6 +2198,14 @@ printpidfile:
|
|||
ctx.control_fd = control_open(NULL, AF_UNSPEC,
|
||||
ctx.options & DHCPCD_DUMPLEASE);
|
||||
if (ctx.control_fd != -1) {
|
||||
#ifdef PRIVSEP
|
||||
ctx.options &= ~DHCPCD_FORKED;
|
||||
if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx) == -1) {
|
||||
ctx.options |= DHCPCD_FORKED;
|
||||
goto exit_failure;
|
||||
}
|
||||
ctx.options |= DHCPCD_FORKED;
|
||||
#endif
|
||||
if (!(ctx.options & DHCPCD_DUMPLEASE))
|
||||
loginfox("sending commands to dhcpcd process");
|
||||
len = control_send(&ctx, argc, argv);
|
||||
|
@ -2206,29 +2259,40 @@ printpidfile:
|
|||
if (freopen(_PATH_DEVNULL, "r", stdin) == NULL)
|
||||
logerr("%s: freopen stdin", __func__);
|
||||
|
||||
|
||||
#ifdef PRIVSEP
|
||||
ps_init(&ctx);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SIGNALS
|
||||
if (pipe(sigpipe) == -1) {
|
||||
logerr("pipe");
|
||||
#if defined(USE_SIGNALS) && !defined(THERE_IS_NO_FORK)
|
||||
if (xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, fork_fd) == -1 ||
|
||||
xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, stderr_fd) == -1)
|
||||
{
|
||||
logerr("socketpair");
|
||||
goto exit_failure;
|
||||
}
|
||||
#ifdef HAVE_CAPSICUM
|
||||
if (ps_rights_limit_fdpair(sigpipe) == -1) {
|
||||
logerr("ps_rights_limit_fdpair");
|
||||
goto exit_failure;
|
||||
}
|
||||
#endif
|
||||
switch (pid = fork()) {
|
||||
case -1:
|
||||
logerr("fork");
|
||||
goto exit_failure;
|
||||
case 0:
|
||||
ctx.fork_fd = sigpipe[1];
|
||||
close(sigpipe[0]);
|
||||
ctx.fork_fd = fork_fd[1];
|
||||
close(fork_fd[0]);
|
||||
#ifdef PRIVSEP_RIGHTS
|
||||
if (ps_rights_limit_fd(fork_fd[1]) == -1) {
|
||||
logerr("ps_rights_limit_fdpair");
|
||||
goto exit_failure;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Redirect stderr to the stderr socketpair.
|
||||
* Redirect stdout as well.
|
||||
* dhcpcd doesn't output via stdout, but something in
|
||||
* a called script might.
|
||||
*
|
||||
* Do NOT rights limit this fd as it will affect scripts.
|
||||
* For example, cmp reports insufficient caps on FreeBSD.
|
||||
*/
|
||||
if (dup2(stderr_fd[1], STDERR_FILENO) == -1 ||
|
||||
dup2(stderr_fd[1], STDOUT_FILENO) == -1)
|
||||
logerr("dup2");
|
||||
close(stderr_fd[0]);
|
||||
close(stderr_fd[1]);
|
||||
if (setsid() == -1) {
|
||||
logerr("%s: setsid", __func__);
|
||||
goto exit_failure;
|
||||
|
@ -2248,10 +2312,22 @@ printpidfile:
|
|||
break;
|
||||
default:
|
||||
ctx.options |= DHCPCD_FORKED; /* A lie */
|
||||
ctx.fork_fd = sigpipe[0];
|
||||
close(sigpipe[1]);
|
||||
ctx.fork_fd = fork_fd[0];
|
||||
close(fork_fd[1]);
|
||||
ctx.stderr_fd = stderr_fd[0];
|
||||
close(stderr_fd[1]);
|
||||
#ifdef PRIVSEP_RIGHTS
|
||||
if (ps_rights_limit_fd(fork_fd[0]) == -1 ||
|
||||
ps_rights_limit_fd(stderr_fd[0]) == 1)
|
||||
{
|
||||
logerr("ps_rights_limit_fdpair");
|
||||
goto exit_failure;
|
||||
}
|
||||
#endif
|
||||
setproctitle("[launcher]");
|
||||
eloop_event_add(ctx.eloop, ctx.fork_fd, dhcpcd_fork_cb, &ctx);
|
||||
eloop_event_add(ctx.eloop, ctx.stderr_fd, dhcpcd_stderr_cb,
|
||||
&ctx);
|
||||
goto run_loop;
|
||||
}
|
||||
|
||||
|
@ -2270,22 +2346,6 @@ printpidfile:
|
|||
if_disable_rtadv();
|
||||
#endif
|
||||
|
||||
if (isatty(STDOUT_FILENO) &&
|
||||
freopen(_PATH_DEVNULL, "r", stdout) == NULL)
|
||||
logerr("%s: freopen stdout", __func__);
|
||||
if (isatty(STDERR_FILENO)) {
|
||||
int fd = dup(STDERR_FILENO);
|
||||
|
||||
if (fd == -1)
|
||||
logerr("%s: dup", __func__);
|
||||
else if (logseterrfd(fd) == -1)
|
||||
logerr("%s: logseterrfd", __func__);
|
||||
else if (freopen(_PATH_DEVNULL, "r", stderr) == NULL) {
|
||||
logseterrfd(-1);
|
||||
logerr("%s: freopen stderr", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PRIVSEP
|
||||
if (IN_PRIVSEP(&ctx) && ps_start(&ctx) == -1) {
|
||||
logerr("ps_start");
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd June 18, 2020
|
||||
.Dd September 2, 2020
|
||||
.Dt DHCPCD.CONF 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -448,8 +448,14 @@ Enables IPv6 Router Advertisement solicitation.
|
|||
This is on by default, but is documented here in the case where it is disabled
|
||||
globally but needs to be enabled for one interface.
|
||||
.It Ic leasetime Ar seconds
|
||||
Request a leasetime of
|
||||
Request a lease time of
|
||||
.Ar seconds .
|
||||
.Ar -1
|
||||
represents an infinite lease time.
|
||||
By default
|
||||
.Nm dhcpcd
|
||||
does not request any lease time and leaves it in the hands of the
|
||||
DHCP server.
|
||||
.It Ic link_rcvbuf Ar size
|
||||
Override the size of the link receive buffer from the kernel default.
|
||||
While
|
||||
|
|
|
@ -96,7 +96,6 @@ TAILQ_HEAD(if_head, interface);
|
|||
|
||||
#include "privsep.h"
|
||||
|
||||
#ifdef INET6
|
||||
/* dhcpcd requires CMSG_SPACE to evaluate to a compile time constant. */
|
||||
#if defined(__QNX) || \
|
||||
(defined(__NetBSD_Version__) && __NetBSD_Version__ < 600000000)
|
||||
|
@ -113,16 +112,13 @@ TAILQ_HEAD(if_head, interface);
|
|||
#define CMSG_SPACE(len) (ALIGN(sizeof(struct cmsghdr)) + ALIGN(len))
|
||||
#endif
|
||||
|
||||
#define IP6BUFLEN (CMSG_SPACE(sizeof(struct in6_pktinfo)) + \
|
||||
CMSG_SPACE(sizeof(int)))
|
||||
#endif
|
||||
|
||||
struct passwd;
|
||||
|
||||
struct dhcpcd_ctx {
|
||||
char pidfile[sizeof(PIDFILE) + IF_NAMESIZE + 1];
|
||||
char vendor[256];
|
||||
int fork_fd; /* FD for the fork init signal pipe */
|
||||
int stderr_fd; /* FD for logging to stderr */
|
||||
const char *cffile;
|
||||
unsigned long long options;
|
||||
char *logfile;
|
||||
|
|
|
@ -703,9 +703,10 @@ eloop_start(struct eloop *eloop, sigset_t *signals)
|
|||
if (eloop->exitnow)
|
||||
break;
|
||||
|
||||
if (_eloop_nsig != 0 && eloop->signal_cb != NULL) {
|
||||
if (_eloop_nsig != 0) {
|
||||
n = _eloop_sig[--_eloop_nsig];
|
||||
eloop->signal_cb(n, eloop->signal_cb_ctx);
|
||||
if (eloop->signal_cb != NULL)
|
||||
eloop->signal_cb(n, eloop->signal_cb_ctx);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,8 @@
|
|||
#define SET_CONFIG_BLOCK(ifo) ((ifo)->options |= DHCPCD_FORKED)
|
||||
#define CLEAR_CONFIG_BLOCK(ifo) ((ifo)->options &= ~DHCPCD_FORKED)
|
||||
|
||||
static unsigned long long default_options;
|
||||
|
||||
const struct option cf_options[] = {
|
||||
{"background", no_argument, NULL, 'b'},
|
||||
{"script", required_argument, NULL, 'c'},
|
||||
|
@ -759,6 +761,10 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
|
|||
break;
|
||||
case 'l':
|
||||
ARG_REQUIRED;
|
||||
if (strcmp(arg, "-1") == 0) {
|
||||
ifo->leasetime = DHCP_INFINITE_LIFETIME;
|
||||
break;
|
||||
}
|
||||
ifo->leasetime = (uint32_t)strtou(arg, NULL,
|
||||
0, 0, UINT32_MAX, &e);
|
||||
if (e) {
|
||||
|
@ -1021,6 +1027,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
|
|||
}
|
||||
ifo->options |= DHCPCD_CLIENTID;
|
||||
ifo->clientid[0] = (uint8_t)s;
|
||||
ifo->options &= ~DHCPCD_DUID;
|
||||
break;
|
||||
case 'J':
|
||||
ifo->options |= DHCPCD_BROADCAST;
|
||||
|
@ -1204,13 +1211,23 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
|
|||
ifo->options |= DHCPCD_ONESHOT;
|
||||
break;
|
||||
case '4':
|
||||
#ifdef INET
|
||||
ifo->options &= ~DHCPCD_IPV6;
|
||||
ifo->options |= DHCPCD_IPV4;
|
||||
break;
|
||||
#else
|
||||
logerrx("INET has been compiled out");
|
||||
return -1;
|
||||
#endif
|
||||
case '6':
|
||||
#ifdef INET6
|
||||
ifo->options &= ~DHCPCD_IPV4;
|
||||
ifo->options |= DHCPCD_IPV6;
|
||||
break;
|
||||
#else
|
||||
logerrx("INET6 has been compiled out");
|
||||
return -1;
|
||||
#endif
|
||||
case O_IPV4:
|
||||
ifo->options |= DHCPCD_IPV4;
|
||||
break;
|
||||
|
@ -2090,6 +2107,12 @@ invalid_token:
|
|||
break;
|
||||
case O_CONTROLGRP:
|
||||
ARG_REQUIRED;
|
||||
#ifdef PRIVSEP
|
||||
/* Control group is already set by this point.
|
||||
* We don't need to pledge getpw either with this. */
|
||||
if (IN_PRIVSEP(ctx))
|
||||
break;
|
||||
#endif
|
||||
#ifdef _REENTRANT
|
||||
l = sysconf(_SC_GETGR_R_SIZE_MAX);
|
||||
if (l == -1)
|
||||
|
@ -2326,18 +2349,30 @@ read_config(struct dhcpcd_ctx *ctx,
|
|||
/* Seed our default options */
|
||||
if ((ifo = default_config(ctx)) == NULL)
|
||||
return NULL;
|
||||
ifo->options |= DHCPCD_DAEMONISE | DHCPCD_GATEWAY;
|
||||
#ifdef PLUGIN_DEV
|
||||
ifo->options |= DHCPCD_DEV;
|
||||
#endif
|
||||
if (default_options == 0) {
|
||||
default_options |= DHCPCD_DAEMONISE | DHCPCD_GATEWAY;
|
||||
#ifdef INET
|
||||
ifo->options |= DHCPCD_IPV4 | DHCPCD_ARP | DHCPCD_DHCP | DHCPCD_IPV4LL;
|
||||
skip = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (skip != -1) {
|
||||
close(skip);
|
||||
default_options |= DHCPCD_IPV4 | DHCPCD_ARP |
|
||||
DHCPCD_DHCP | DHCPCD_IPV4LL;
|
||||
}
|
||||
#endif
|
||||
#ifdef INET6
|
||||
ifo->options |= DHCPCD_IPV6 | DHCPCD_IPV6RS;
|
||||
ifo->options |= DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS;
|
||||
ifo->options |= DHCPCD_DHCP6;
|
||||
skip = socket(PF_INET6, SOCK_DGRAM, 0);
|
||||
if (skip != -1) {
|
||||
close(skip);
|
||||
default_options |= DHCPCD_IPV6 | DHCPCD_IPV6RS |
|
||||
DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS |
|
||||
DHCPCD_DHCP6;
|
||||
}
|
||||
#endif
|
||||
#ifdef PLUGIN_DEV
|
||||
default_options |= DHCPCD_DEV;
|
||||
#endif
|
||||
}
|
||||
ifo->options |= default_options;
|
||||
|
||||
CLEAR_CONFIG_BLOCK(ifo);
|
||||
|
||||
|
|
|
@ -995,3 +995,50 @@ out:
|
|||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
xsocketpair(int domain, int type, int protocol, int fd[2])
|
||||
{
|
||||
int s;
|
||||
#if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK)
|
||||
int xflags, xtype = type;
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SOCK_CLOEXEC
|
||||
if (xtype & SOCK_CLOEXEC)
|
||||
type &= ~SOCK_CLOEXEC;
|
||||
#endif
|
||||
#ifndef HAVE_SOCK_NONBLOCK
|
||||
if (xtype & SOCK_NONBLOCK)
|
||||
type &= ~SOCK_NONBLOCK;
|
||||
#endif
|
||||
|
||||
if ((s = socketpair(domain, type, protocol, fd)) == -1)
|
||||
return -1;
|
||||
|
||||
#ifndef HAVE_SOCK_CLOEXEC
|
||||
if ((xtype & SOCK_CLOEXEC) && ((xflags = fcntl(fd[0], F_GETFD)) == -1 ||
|
||||
fcntl(fd[0], F_SETFD, xflags | FD_CLOEXEC) == -1))
|
||||
goto out;
|
||||
if ((xtype & SOCK_CLOEXEC) && ((xflags = fcntl(fd[1], F_GETFD)) == -1 ||
|
||||
fcntl(fd[1], F_SETFD, xflags | FD_CLOEXEC) == -1))
|
||||
goto out;
|
||||
#endif
|
||||
#ifndef HAVE_SOCK_NONBLOCK
|
||||
if ((xtype & SOCK_NONBLOCK) && ((xflags = fcntl(fd[0], F_GETFL)) == -1 ||
|
||||
fcntl(fd[0], F_SETFL, xflags | O_NONBLOCK) == -1))
|
||||
goto out;
|
||||
if ((xtype & SOCK_NONBLOCK) && ((xflags = fcntl(fd[1], F_GETFL)) == -1 ||
|
||||
fcntl(fd[1], F_SETFL, xflags | O_NONBLOCK) == -1))
|
||||
goto out;
|
||||
#endif
|
||||
|
||||
return s;
|
||||
|
||||
#if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK)
|
||||
out:
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -224,6 +224,8 @@ int if_setmac(struct interface *ifp, void *, uint8_t);
|
|||
#ifndef SOCK_CXNB
|
||||
#define SOCK_CXNB SOCK_CLOEXEC | SOCK_NONBLOCK
|
||||
#endif
|
||||
int xsocket(int, int, int);
|
||||
int xsocketpair(int, int, int, int[2]);
|
||||
|
||||
int if_route(unsigned char, const struct rt *rt);
|
||||
int if_initrt(struct dhcpcd_ctx *, rb_tree_t *, int);
|
||||
|
@ -259,7 +261,6 @@ int if_getlifetime6(struct ipv6_addr *);
|
|||
int if_machinearch(char *, size_t);
|
||||
struct interface *if_findifpfromcmsg(struct dhcpcd_ctx *,
|
||||
struct msghdr *, int *);
|
||||
int xsocket(int, int, int);
|
||||
|
||||
#ifdef __linux__
|
||||
int if_linksocket(struct sockaddr_nl *, int, int);
|
||||
|
|
|
@ -661,8 +661,13 @@ ipv4_addaddr(struct interface *ifp, const struct in_addr *addr,
|
|||
ia->mask = *mask;
|
||||
ia->brd = *bcast;
|
||||
#ifdef IP_LIFETIME
|
||||
ia->vltime = vltime;
|
||||
ia->pltime = pltime;
|
||||
if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND) {
|
||||
/* We don't want the kernel to expire the address. */
|
||||
ia->vltime = ia->pltime = DHCP_INFINITE_LIFETIME;
|
||||
} else {
|
||||
ia->vltime = vltime;
|
||||
ia->pltime = pltime;
|
||||
}
|
||||
#else
|
||||
UNUSED(vltime);
|
||||
UNUSED(pltime);
|
||||
|
|
|
@ -129,6 +129,7 @@ bool inet_getroutes(struct dhcpcd_ctx *, rb_tree_t *);
|
|||
|
||||
#define STATE_ADDED 0x01
|
||||
#define STATE_FAKE 0x02
|
||||
#define STATE_EXPIRED 0x04
|
||||
|
||||
int ipv4_deladdr(struct ipv4_addr *, int);
|
||||
struct ipv4_addr *ipv4_addaddr(struct interface *,
|
||||
|
|
|
@ -111,6 +111,7 @@ ipv4ll_subnetroute(rb_tree_t *routes, struct interface *ifp)
|
|||
in.s_addr = INADDR_ANY;
|
||||
sa_in_init(&rt->rt_gateway, &in);
|
||||
sa_in_init(&rt->rt_ifa, &state->addr->addr);
|
||||
rt->rt_dflags |= RTDF_IPV4LL;
|
||||
return rt_proto_add(routes, rt) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
@ -134,6 +135,10 @@ ipv4ll_defaultroute(rb_tree_t *routes, struct interface *ifp)
|
|||
sa_in_init(&rt->rt_netmask, &in);
|
||||
sa_in_init(&rt->rt_gateway, &in);
|
||||
sa_in_init(&rt->rt_ifa, &state->addr->addr);
|
||||
rt->rt_dflags |= RTDF_IPV4LL;
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
rt->rt_metric += 10000;
|
||||
#endif
|
||||
return rt_proto_add(routes, rt) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -679,6 +679,14 @@ ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now)
|
|||
/* Adjust plftime and vltime based on acquired time */
|
||||
pltime = ia->prefix_pltime;
|
||||
vltime = ia->prefix_vltime;
|
||||
|
||||
if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND) {
|
||||
/* We don't want the kernel to expire the address.
|
||||
* The saved times will be re-applied to the ia
|
||||
* before exiting this function. */
|
||||
ia->prefix_vltime = ia->prefix_pltime = ND6_INFINITE_LIFETIME;
|
||||
}
|
||||
|
||||
if (timespecisset(&ia->acquired) &&
|
||||
(ia->prefix_pltime != ND6_INFINITE_LIFETIME ||
|
||||
ia->prefix_vltime != ND6_INFINITE_LIFETIME))
|
||||
|
@ -1092,33 +1100,22 @@ ipv6_anyglobal(struct interface *sifp)
|
|||
struct interface *ifp;
|
||||
struct ipv6_state *state;
|
||||
struct ipv6_addr *ia;
|
||||
#ifdef BSD
|
||||
bool forwarding;
|
||||
|
||||
#if defined(PRIVSEP) && defined(HAVE_PLEDGE)
|
||||
/* BSD forwarding is either on or off.
|
||||
* Linux forwarding is technically the same as it's
|
||||
* configured by the "all" interface.
|
||||
* Per interface only affects IsRouter of NA messages. */
|
||||
#if defined(PRIVSEP) && (defined(HAVE_PLEDGE) || defined(__linux__))
|
||||
if (IN_PRIVSEP(sifp->ctx))
|
||||
forwarding = ps_root_ip6forwarding(sifp->ctx, NULL) == 1;
|
||||
forwarding = ps_root_ip6forwarding(sifp->ctx, NULL) != 0;
|
||||
else
|
||||
#endif
|
||||
forwarding = ip6_forwarding(NULL) == 1;
|
||||
#endif
|
||||
|
||||
forwarding = ip6_forwarding(NULL) != 0;
|
||||
|
||||
TAILQ_FOREACH(ifp, sifp->ctx->ifaces, next) {
|
||||
#ifdef BSD
|
||||
if (ifp != sifp && !forwarding)
|
||||
continue;
|
||||
#else
|
||||
#if defined(PRIVSEP) && defined(__linux__)
|
||||
if (IN_PRIVSEP(sifp->ctx)) {
|
||||
if (ifp != sifp &&
|
||||
ps_root_ip6forwarding(sifp->ctx, ifp->name) != 1)
|
||||
continue;
|
||||
} else
|
||||
#endif
|
||||
if (ifp != sifp && ip6_forwarding(ifp->name) != 1)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
state = IPV6_STATE(ifp);
|
||||
if (state == NULL)
|
||||
|
|
|
@ -544,11 +544,11 @@ ipv6nd_advertise(struct ipv6_addr *ia)
|
|||
na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE;
|
||||
#if defined(PRIVSEP) && (defined(__linux__) || defined(HAVE_PLEDGE))
|
||||
if (IN_PRIVSEP(ctx)) {
|
||||
if (ps_root_ip6forwarding(ctx, ifp->name) == 1)
|
||||
if (ps_root_ip6forwarding(ctx, ifp->name) != 0)
|
||||
na->nd_na_flags_reserved |= ND_NA_FLAG_ROUTER;
|
||||
} else
|
||||
#endif
|
||||
if (ip6_forwarding(ifp->name) == 1)
|
||||
if (ip6_forwarding(ifp->name) != 0)
|
||||
na->nd_na_flags_reserved |= ND_NA_FLAG_ROUTER;
|
||||
na->nd_na_target = ia->addr;
|
||||
|
||||
|
|
|
@ -52,7 +52,6 @@
|
|||
struct logctx {
|
||||
char log_buf[BUFSIZ];
|
||||
unsigned int log_opts;
|
||||
FILE *log_err;
|
||||
#ifndef SMALL
|
||||
FILE *log_file;
|
||||
#ifdef LOGERR_TAG
|
||||
|
@ -120,14 +119,13 @@ vlogprintf_r(struct logctx *ctx, FILE *stream, const char *fmt, va_list args)
|
|||
int len = 0, e;
|
||||
va_list a;
|
||||
#ifndef SMALL
|
||||
FILE *err = ctx->log_err == NULL ? stderr : ctx->log_err;
|
||||
bool log_pid;
|
||||
#ifdef LOGERR_TAG
|
||||
bool log_tag;
|
||||
#endif
|
||||
|
||||
if ((stream == err && ctx->log_opts & LOGERR_ERR_DATE) ||
|
||||
(stream != err && ctx->log_opts & LOGERR_LOG_DATE))
|
||||
if ((stream == stderr && ctx->log_opts & LOGERR_ERR_DATE) ||
|
||||
(stream != stderr && ctx->log_opts & LOGERR_LOG_DATE))
|
||||
{
|
||||
if ((e = logprintdate(stream)) == -1)
|
||||
return -1;
|
||||
|
@ -135,8 +133,8 @@ vlogprintf_r(struct logctx *ctx, FILE *stream, const char *fmt, va_list args)
|
|||
}
|
||||
|
||||
#ifdef LOGERR_TAG
|
||||
log_tag = ((stream == err && ctx->log_opts & LOGERR_ERR_TAG) ||
|
||||
(stream != err && ctx->log_opts & LOGERR_LOG_TAG));
|
||||
log_tag = ((stream == stderr && ctx->log_opts & LOGERR_ERR_TAG) ||
|
||||
(stream != stderr && ctx->log_opts & LOGERR_LOG_TAG));
|
||||
if (log_tag) {
|
||||
if (ctx->log_tag == NULL)
|
||||
ctx->log_tag = getprogname();
|
||||
|
@ -146,8 +144,8 @@ vlogprintf_r(struct logctx *ctx, FILE *stream, const char *fmt, va_list args)
|
|||
}
|
||||
#endif
|
||||
|
||||
log_pid = ((stream == err && ctx->log_opts & LOGERR_ERR_PID) ||
|
||||
(stream != err && ctx->log_opts & LOGERR_LOG_PID));
|
||||
log_pid = ((stream == stderr && ctx->log_opts & LOGERR_ERR_PID) ||
|
||||
(stream != stderr && ctx->log_opts & LOGERR_LOG_PID));
|
||||
if (log_pid) {
|
||||
if ((e = fprintf(stream, "[%d]", getpid())) == -1)
|
||||
return -1;
|
||||
|
@ -204,12 +202,7 @@ vlogmessage(int pri, const char *fmt, va_list args)
|
|||
(pri <= LOG_ERR ||
|
||||
(!(ctx->log_opts & LOGERR_QUIET) && pri <= LOG_INFO) ||
|
||||
(ctx->log_opts & LOGERR_DEBUG && pri <= LOG_DEBUG)))
|
||||
{
|
||||
FILE *err;
|
||||
|
||||
err = ctx->log_err == NULL ? stderr : ctx->log_err;
|
||||
len = vlogprintf_r(ctx, err, fmt, args);
|
||||
}
|
||||
len = vlogprintf_r(ctx, stderr, fmt, args);
|
||||
|
||||
if (!(ctx->log_opts & LOGERR_LOG))
|
||||
return len;
|
||||
|
@ -369,30 +362,6 @@ logsettag(const char *tag)
|
|||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
loggeterrfd(void)
|
||||
{
|
||||
struct logctx *ctx = &_logctx;
|
||||
FILE *err = ctx->log_err == NULL ? stderr : ctx->log_err;
|
||||
|
||||
return fileno(err);
|
||||
}
|
||||
|
||||
int
|
||||
logseterrfd(int fd)
|
||||
{
|
||||
struct logctx *ctx = &_logctx;
|
||||
|
||||
if (ctx->log_err != NULL)
|
||||
fclose(ctx->log_err);
|
||||
if (fd == -1) {
|
||||
ctx->log_err = NULL;
|
||||
return 0;
|
||||
}
|
||||
ctx->log_err = fdopen(fd, "a");
|
||||
return ctx->log_err == NULL ? -1 : 0;
|
||||
}
|
||||
|
||||
int
|
||||
logopen(const char *path)
|
||||
{
|
||||
|
|
|
@ -97,8 +97,6 @@ void logsetopts(unsigned int);
|
|||
void logsettag(const char *);
|
||||
#endif
|
||||
|
||||
int loggeterrfd(void);
|
||||
int logseterrfd(int);
|
||||
int logopen(const char *);
|
||||
void logclose(void);
|
||||
int logreopen(void);
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
#include <assert.h>
|
||||
#include <pwd.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
@ -170,17 +169,6 @@ ps_bpf_start_bpf(void *arg)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
ps_bpf_signal_bpfcb(int sig, void *arg)
|
||||
{
|
||||
struct dhcpcd_ctx *ctx = arg;
|
||||
|
||||
if (sig != SIGTERM)
|
||||
return;
|
||||
|
||||
eloop_exit(ctx->eloop, EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
|
||||
{
|
||||
|
@ -249,7 +237,7 @@ ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
|
|||
start = ps_dostart(ctx,
|
||||
&psp->psp_pid, &psp->psp_fd,
|
||||
ps_bpf_recvmsg, NULL, psp,
|
||||
ps_bpf_start_bpf, ps_bpf_signal_bpfcb,
|
||||
ps_bpf_start_bpf, NULL,
|
||||
PSF_DROPPRIVS);
|
||||
switch (start) {
|
||||
case -1:
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -95,18 +94,6 @@ ps_ctl_recvmsg(void *arg)
|
|||
logerr(__func__);
|
||||
}
|
||||
|
||||
static void
|
||||
ps_ctl_signalcb(int sig, void *arg)
|
||||
{
|
||||
struct dhcpcd_ctx *ctx = arg;
|
||||
|
||||
if (sig != SIGTERM)
|
||||
return;
|
||||
|
||||
shutdown(ctx->ps_control_fd, SHUT_RDWR);
|
||||
eloop_exit(ctx->eloop, EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
ps_ctl_handleargs(struct fd_list *fd, char *data, size_t len)
|
||||
{
|
||||
|
@ -238,20 +225,18 @@ ps_ctl_start(struct dhcpcd_ctx *ctx)
|
|||
int data_fd[2], listen_fd[2];
|
||||
pid_t pid;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0, data_fd) == -1)
|
||||
return -1;
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0, listen_fd) == -1)
|
||||
if (xsocketpair(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0, data_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)
|
||||
return -1;
|
||||
if (ps_rights_limit_fdpair(listen_fd) == -1)
|
||||
if (ps_rights_limit_fdpair(data_fd) == -1 ||
|
||||
ps_rights_limit_fdpair(listen_fd) == -1)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
pid = ps_dostart(ctx, &ctx->ps_control_pid, &ctx->ps_control_fd,
|
||||
ps_ctl_recvmsg, ps_ctl_dodispatch, ctx,
|
||||
ps_ctl_startcb, ps_ctl_signalcb,
|
||||
ps_ctl_startcb, NULL,
|
||||
PSF_DROPPRIVS);
|
||||
|
||||
if (pid == -1)
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
@ -291,18 +290,6 @@ ps_inet_recvmsg(void *arg)
|
|||
logerr(__func__);
|
||||
}
|
||||
|
||||
static void
|
||||
ps_inet_signalcb(int sig, void *arg)
|
||||
{
|
||||
struct dhcpcd_ctx *ctx = arg;
|
||||
|
||||
if (sig != SIGTERM)
|
||||
return;
|
||||
|
||||
shutdown(ctx->ps_inet_fd, SHUT_RDWR);
|
||||
eloop_exit(ctx->eloop, EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
ps_inet_dispatch(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
|
||||
{
|
||||
|
@ -347,7 +334,7 @@ ps_inet_start(struct dhcpcd_ctx *ctx)
|
|||
|
||||
pid = ps_dostart(ctx, &ctx->ps_inet_pid, &ctx->ps_inet_fd,
|
||||
ps_inet_recvmsg, ps_inet_dodispatch, ctx,
|
||||
ps_inet_startcb, ps_inet_signalcb,
|
||||
ps_inet_startcb, NULL,
|
||||
PSF_DROPPRIVS);
|
||||
|
||||
#ifdef HAVE_CAPSICUM
|
||||
|
@ -576,7 +563,7 @@ ps_inet_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
|
|||
start = ps_dostart(ctx,
|
||||
&psp->psp_pid, &psp->psp_fd,
|
||||
ps_inet_recvmsgpsp, NULL, psp,
|
||||
start_func, ps_inet_signalcb,
|
||||
start_func, NULL,
|
||||
PSF_DROPPRIVS);
|
||||
switch (start) {
|
||||
case -1:
|
||||
|
|
|
@ -638,27 +638,46 @@ ps_root_startcb(void *arg)
|
|||
/* Open network sockets for sending.
|
||||
* This is a small bit wasteful for non sandboxed OS's
|
||||
* but makes life very easy for unicasting DHCPv6 in non master
|
||||
* mode as we no longer care about address selection. */
|
||||
* mode as we no longer care about address selection.
|
||||
* We can't call shutdown SHUT_RD on the socket because it's
|
||||
* not connectd. All we can do is try and set a zero sized
|
||||
* receive buffer and just let it overflow.
|
||||
* Reading from it just to drain it is a waste of CPU time. */
|
||||
#ifdef INET
|
||||
if (ctx->options & DHCPCD_IPV4) {
|
||||
int buflen = 1;
|
||||
|
||||
ctx->udp_wfd = xsocket(PF_INET,
|
||||
SOCK_RAW | SOCK_CXNB, IPPROTO_UDP);
|
||||
if (ctx->udp_wfd == -1)
|
||||
logerr("%s: dhcp_openraw", __func__);
|
||||
else if (setsockopt(ctx->udp_wfd, SOL_SOCKET, SO_RCVBUF,
|
||||
&buflen, sizeof(buflen)) == -1)
|
||||
logerr("%s: setsockopt SO_RCVBUF DHCP", __func__);
|
||||
}
|
||||
#endif
|
||||
#ifdef INET6
|
||||
if (ctx->options & DHCPCD_IPV6) {
|
||||
int buflen = 1;
|
||||
|
||||
ctx->nd_fd = ipv6nd_open(false);
|
||||
if (ctx->nd_fd == -1)
|
||||
logerr("%s: ipv6nd_open", __func__);
|
||||
else if (setsockopt(ctx->nd_fd, SOL_SOCKET, SO_RCVBUF,
|
||||
&buflen, sizeof(buflen)) == -1)
|
||||
logerr("%s: setsockopt SO_RCVBUF ND", __func__);
|
||||
}
|
||||
#endif
|
||||
#ifdef DHCP6
|
||||
if (ctx->options & DHCPCD_IPV6) {
|
||||
int buflen = 1;
|
||||
|
||||
ctx->dhcp6_wfd = dhcp6_openraw();
|
||||
if (ctx->dhcp6_wfd == -1)
|
||||
logerr("%s: dhcp6_openraw", __func__);
|
||||
else if (setsockopt(ctx->dhcp6_wfd, SOL_SOCKET, SO_RCVBUF,
|
||||
&buflen, sizeof(buflen)) == -1)
|
||||
logerr("%s: setsockopt SO_RCVBUF DHCP6", __func__);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -674,22 +693,14 @@ ps_root_startcb(void *arg)
|
|||
}
|
||||
|
||||
static void
|
||||
ps_root_signalcb(int sig, void *arg)
|
||||
ps_root_signalcb(int sig, __unused void *arg)
|
||||
{
|
||||
struct dhcpcd_ctx *ctx = arg;
|
||||
|
||||
if (sig == SIGCHLD) {
|
||||
while (waitpid(-1, NULL, WNOHANG) > 0)
|
||||
;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sig != SIGTERM)
|
||||
return;
|
||||
|
||||
shutdown(ctx->ps_root_fd, SHUT_RDWR);
|
||||
shutdown(ctx->ps_data_fd, SHUT_RDWR);
|
||||
eloop_exit(ctx->eloop, EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int (*handle_interface)(void *, int, const char *);
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
* Spawn an unpriv process to send/receive common network data.
|
||||
* Then drop all privs and start running.
|
||||
* Every process aside from the privileged actioneer is chrooted.
|
||||
* All privsep processes ignore signals - only the master process accepts them.
|
||||
*
|
||||
* dhcpcd will maintain the config file in the chroot, no need to handle
|
||||
* this in a script or something.
|
||||
|
@ -74,6 +75,8 @@
|
|||
|
||||
#ifdef HAVE_CAPSICUM
|
||||
#include <sys/capsicum.h>
|
||||
#include <capsicum_helpers.h>
|
||||
#define ps_rights_limit_stdio caph_limit_stdio
|
||||
#endif
|
||||
#ifdef HAVE_UTIL_H
|
||||
#include <util.h>
|
||||
|
@ -109,7 +112,7 @@ ps_init(struct dhcpcd_ctx *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
ps_dropprivs(struct dhcpcd_ctx *ctx)
|
||||
{
|
||||
struct passwd *pw = ctx->ps_user;
|
||||
|
@ -121,9 +124,10 @@ ps_dropprivs(struct dhcpcd_ctx *ctx)
|
|||
if (chdir("/") == -1)
|
||||
logerr("%s: chdir `/'", __func__);
|
||||
|
||||
if (setgroups(1, &pw->pw_gid) == -1 ||
|
||||
if ((setgroups(1, &pw->pw_gid) == -1 ||
|
||||
setgid(pw->pw_gid) == -1 ||
|
||||
setuid(pw->pw_uid) == -1)
|
||||
setuid(pw->pw_uid) == -1) &&
|
||||
(errno != EPERM || ctx->options & DHCPCD_FORKED))
|
||||
{
|
||||
logerr("failed to drop privileges");
|
||||
return -1;
|
||||
|
@ -162,7 +166,7 @@ ps_dropprivs(struct dhcpcd_ctx *ctx)
|
|||
/* Prohibit writing to files.
|
||||
* Obviously this won't work if we are using a logfile
|
||||
* or redirecting stderr to a file. */
|
||||
if (ctx->logfile == NULL && isatty(loggeterrfd())) {
|
||||
if (ctx->logfile == NULL) {
|
||||
if (setrlimit(RLIMIT_FSIZE, &rzero) == -1)
|
||||
logerr("setrlimit RLIMIT_FSIZE");
|
||||
}
|
||||
|
@ -283,12 +287,10 @@ ps_dostart(struct dhcpcd_ctx *ctx,
|
|||
void *recv_ctx, int (*callback)(void *), void (*signal_cb)(int, void *),
|
||||
unsigned int flags)
|
||||
{
|
||||
int stype;
|
||||
int fd[2];
|
||||
pid_t pid;
|
||||
|
||||
stype = SOCK_CLOEXEC | SOCK_NONBLOCK;
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM | stype, 0, fd) == -1) {
|
||||
if (xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, fd) == -1) {
|
||||
logerr("%s: socketpair", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
@ -341,6 +343,14 @@ ps_dostart(struct dhcpcd_ctx *ctx,
|
|||
close(ctx->ps_root_fd);
|
||||
ctx->ps_root_fd = -1;
|
||||
}
|
||||
|
||||
#ifdef PRIVSEP_RIGHTS
|
||||
/* We cannot limit the root process in any way. */
|
||||
if (ps_rights_limit_stdio() == -1) {
|
||||
logerr("ps_rights_limit_stdio");
|
||||
goto errexit;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (priv_fd != &ctx->ps_inet_fd && ctx->ps_inet_fd != -1) {
|
||||
|
@ -471,9 +481,10 @@ ps_mastersandbox(struct dhcpcd_ctx *ctx)
|
|||
}
|
||||
|
||||
#ifdef PRIVSEP_RIGHTS
|
||||
if ((ps_rights_limit_ioctl(ctx->pf_inet_fd) == -1 ||
|
||||
ps_rights_limit_fd(ctx->link_fd) == -1) &&
|
||||
errno != ENOSYS)
|
||||
if ((ctx->pf_inet_fd != -1 &&
|
||||
ps_rights_limit_ioctl(ctx->pf_inet_fd) == -1) ||
|
||||
(ctx->link_fd != -1 && ps_rights_limit_fd(ctx->link_fd) == -1) ||
|
||||
ps_rights_limit_stdio() == -1)
|
||||
{
|
||||
logerr("%s: cap_rights_limit", __func__);
|
||||
return -1;
|
||||
|
@ -645,12 +656,12 @@ ps_sendpsmmsg(struct dhcpcd_ctx *ctx, int fd,
|
|||
iovlen = 1;
|
||||
|
||||
len = writev(fd, iov, iovlen);
|
||||
#ifdef PRIVSEP_DEBUG
|
||||
logdebugx("%s: %zd", __func__, len);
|
||||
#endif
|
||||
if ((len == -1 || len == 0) && ctx->options & DHCPCD_FORKED &&
|
||||
!(ctx->options & DHCPCD_PRIVSEPROOT))
|
||||
eloop_exit(ctx->eloop, len == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
if (len == -1) {
|
||||
logerr(__func__);
|
||||
if (ctx->options & DHCPCD_FORKED &&
|
||||
!(ctx->options & DHCPCD_PRIVSEPROOT))
|
||||
eloop_exit(ctx->eloop, EXIT_FAILURE);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -789,10 +800,9 @@ ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, uint16_t cmd, int wfd)
|
|||
};
|
||||
|
||||
ssize_t len = recvmsg(rfd, &msg, 0);
|
||||
#ifdef PRIVSEP_DEBUG
|
||||
logdebugx("%s: recv fd %d, %zd bytes", __func__, rfd, len);
|
||||
#endif
|
||||
|
||||
if (len == -1)
|
||||
logerr("%s: recvmsg", __func__);
|
||||
if (len == -1 || len == 0) {
|
||||
if (ctx->options & DHCPCD_FORKED &&
|
||||
!(ctx->options & DHCPCD_PRIVSEPROOT))
|
||||
|
@ -803,12 +813,12 @@ ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, uint16_t cmd, int wfd)
|
|||
|
||||
iov[0].iov_len = (size_t)len;
|
||||
len = ps_sendcmdmsg(wfd, cmd, &msg);
|
||||
#ifdef PRIVSEP_DEBUG
|
||||
logdebugx("%s: send fd %d, %zu bytes", __func__, wfd, len);
|
||||
#endif
|
||||
if ((len == -1 || len == 0) && ctx->options & DHCPCD_FORKED &&
|
||||
!(ctx->options & DHCPCD_PRIVSEPROOT))
|
||||
eloop_exit(ctx->eloop, len == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
if (len == -1) {
|
||||
logerr("ps_sendcmdmsg");
|
||||
if (ctx->options & DHCPCD_FORKED &&
|
||||
!(ctx->options & DHCPCD_PRIVSEPROOT))
|
||||
eloop_exit(ctx->eloop, EXIT_FAILURE);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
|
|
@ -166,7 +166,6 @@ TAILQ_HEAD(ps_process_head, ps_process);
|
|||
#endif
|
||||
|
||||
int ps_init(struct dhcpcd_ctx *);
|
||||
int ps_dropprivs(struct dhcpcd_ctx *);
|
||||
int ps_start(struct dhcpcd_ctx *);
|
||||
int ps_stop(struct dhcpcd_ctx *);
|
||||
int ps_mastersandbox(struct dhcpcd_ctx *);
|
||||
|
|
|
@ -168,6 +168,14 @@ rt_compare_proto(void *context, const void *node1, const void *node2)
|
|||
if (c != 0)
|
||||
return -c;
|
||||
|
||||
#ifdef INET
|
||||
/* IPv4LL routes always come last */
|
||||
if (rt1->rt_dflags & RTDF_IPV4LL && !(rt2->rt_dflags & RTDF_IPV4LL))
|
||||
return -1;
|
||||
else if (!(rt1->rt_dflags & RTDF_IPV4LL) && rt2->rt_dflags & RTDF_IPV4LL)
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
/* Lower metric interfaces come first. */
|
||||
c = (int)(ifp1->metric - ifp2->metric);
|
||||
if (c != 0)
|
||||
|
|
|
@ -102,8 +102,9 @@ struct rt {
|
|||
#define RTPREF_RESERVED (-2)
|
||||
#define RTPREF_INVALID (-3) /* internal */
|
||||
unsigned int rt_dflags;
|
||||
#define RTDF_IFA_ROUTE 0x02 /* Address generated route */
|
||||
#define RTDF_FAKE 0x04 /* Maybe us on lease reboot */
|
||||
#define RTDF_IFA_ROUTE 0x01 /* Address generated route */
|
||||
#define RTDF_FAKE 0x02 /* Maybe us on lease reboot */
|
||||
#define RTDF_IPV4LL 0x04 /* IPv4LL route */
|
||||
#define RTDF_RA 0x08 /* Router Advertisement */
|
||||
#define RTDF_DHCP 0x10 /* DHCP route */
|
||||
#define RTDF_STATIC 0x20 /* Configured in dhcpcd */
|
||||
|
|
Loading…
Reference in New Issue