Update to dhcpcd-9.1.0 with the following changes:

* Leases are stored outside the chroot again
 * The chroot directory can now be (and should be) empty [1]
 * ARP is now per address rather than per interface
 * Filter allowed ioctls in the privileged actioneer
 * Filter allowed UDP ports used by sendto(2) in the privileged actioneer
 * Filter allowed file paths in the privileged actioneer
 * route socket is now drained on overflow as it cannot be
   re-opened by the unpriviledged user

 * hostname can no longer be clobbered by SLAAC
 * grep is no longer used by the test hook
 * Interface hardware address type changes are now picked up
 * Fixed some RA timing issues
 * Fixed nd_* option parsing in dhcpcd.conf
 * Allow SIGPIPE in scripts
 * Default dhcpcd.conf no longer sends the current hostname
 * Default dhcpcd.conf no longer sends a vendorclassid
This commit is contained in:
roy 2020-05-31 12:50:46 +00:00
parent 9769066979
commit 7c187152f8
42 changed files with 2098 additions and 1430 deletions

View File

@ -97,8 +97,6 @@ install similar logic into their dhcpcd package.
dhcpcd-9 defaults the run directory to `/var/run/dhcpcd` instead of
`/var/run` and the prefix of dhcpcd has been removed from the files.
dhcpcd-9 may also run in a chroot, `/var/chroot/dhcpcd` so all the files
could be relative to that.
## ChangeLog
We no longer supply a ChangeLog.

View File

@ -1,9 +1,37 @@
# Echo the interface flags, reason and message options
if [ "$reason" = "TEST" ]; then
set | grep \
"^\(interface\|pid\|reason\|protocol\|profile\|skip_hooks\)=" | sort
set | grep "^if\(carrier\|flags\|mtu\|wireless\|ssid\)=" | sort
set | grep "^\(new_\|old_\|nd[0-9]*_\)" | sort
# General variables at the top
set | while read line; do
case "$line" in
interface=*|pid=*|reason=*|protocol=*|profile=*|skip_hooks=*)
echo "$line";;
esac
done
# Interface flags
set | while read line; do
case "$line" in
ifcarrier=*|ifflags=*|ifmetric=*|ifmtu=*|ifwireless=*|ifssid=*)
echo "$line";;
esac
done
# Old lease
set | while read line; do
case "$line" in
old_*) echo "$line";;
esac
done
# New lease
set | while read line; do
case "$line" in
new_*) echo "$line";;
esac
done
# Router Advertisements
set | while read line; do
case "$line" in
nd[0-9]*_*) echo "$line";;
esac
done
exit 0
fi

View File

@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd April 3, 2020
.Dd May 24, 2020
.Dt DHCPCD-RUN-HOOKS 8
.Os
.Sh NAME
@ -84,8 +84,6 @@ Here's a list of reasons why
.Nm
could be invoked:
.Bl -tag -width EXPIREXXXEXPIRE6
.It Dv CHROOT
dhcpcd is starting up and needs to configure a chroot environment.
.It Dv PREINIT
dhcpcd is starting up and any pre-initialisation should be done.
.It Dv CARRIER
@ -95,7 +93,7 @@ This is generally just a notification and no action need be taken.
dhcpcd lost the carrier.
The cable may have been unplugged or association to the wireless point lost.
.It Dv INFORM | Dv INFORM6
dhcpcd informed a DHCP server about it's address and obtained other
dhcpcd informed a DHCP server about its address and obtained other
configuration details.
.It Dv BOUND | Dv BOUND6
dhcpcd obtained a new lease from a DHCP server.

View File

@ -67,16 +67,17 @@
__CTASSERT(sizeof(struct arphdr) == 8);
static ssize_t
arp_request(const struct interface *ifp,
const struct in_addr *sip, const struct in_addr *tip)
arp_request(const struct arp_state *astate,
const struct in_addr *sip)
{
const struct interface *ifp = astate->iface;
const struct in_addr *tip = &astate->addr;
uint8_t arp_buffer[ARP_LEN];
struct arphdr ar;
size_t len;
uint8_t *p;
const struct iarp_state *state;
ar.ar_hrd = htons(ifp->family);
ar.ar_hrd = htons(ifp->hwtype);
ar.ar_pro = htons(ETHERTYPE_IP);
ar.ar_hln = ifp->hwlen;
ar.ar_pln = sizeof(tip->s_addr);
@ -107,12 +108,11 @@ arp_request(const struct interface *ifp,
#ifdef PRIVSEP
if (ifp->ctx->options & DHCPCD_PRIVSEP)
return ps_bpf_sendarp(ifp, arp_buffer, len);
return ps_bpf_sendarp(ifp, tip, arp_buffer, len);
#endif
state = ARP_CSTATE(ifp);
/* Note that well formed ethernet will add extra padding
* to ensure that the packet is at least 60 bytes (64 including FCS). */
return bpf_send(ifp, state->bpf_fd, ETHERTYPE_ARP, arp_buffer, len);
return bpf_send(astate->bpf, ETHERTYPE_ARP, arp_buffer, len);
eexit:
errno = ENOBUFS;
@ -134,12 +134,12 @@ arp_report_conflicted(const struct arp_state *astate,
hwaddr_ntoa(amsg->sha, astate->iface->hwlen, abuf, sizeof(abuf));
if (bpf_frame_header_len(astate->iface) == 0) {
logerrx("%s: %s claims %s",
logwarnx("%s: %s claims %s",
astate->iface->name, abuf, inet_ntoa(astate->addr));
return;
}
logerrx("%s: %s(%s) claims %s",
logwarnx("%s: %s(%s) claims %s",
astate->iface->name, abuf,
hwaddr_ntoa(amsg->fsha, astate->iface->hwlen, fbuf, sizeof(fbuf)),
inet_ntoa(astate->addr));
@ -179,7 +179,7 @@ arp_found(struct arp_state *astate, const struct arp_msg *amsg)
eloop_timespec_diff(&now, &astate->defend, NULL) < DEFEND_INTERVAL)
logwarnx("%s: %d second defence failed for %s",
ifp->name, DEFEND_INTERVAL, inet_ntoa(astate->addr));
else if (arp_request(ifp, &astate->addr, &astate->addr) == -1)
else if (arp_request(astate, &astate->addr) == -1)
logerr(__func__);
else {
logdebugx("%s: defended address %s",
@ -197,8 +197,8 @@ static bool
arp_validate(const struct interface *ifp, struct arphdr *arp)
{
/* Families must match */
if (arp->ar_hrd != htons(ifp->family))
/* Address type must match */
if (arp->ar_hrd != htons(ifp->hwtype))
return false;
/* Protocol must be IP. */
@ -222,7 +222,8 @@ arp_validate(const struct interface *ifp, struct arphdr *arp)
}
void
arp_packet(struct interface *ifp, uint8_t *data, size_t len)
arp_packet(struct interface *ifp, uint8_t *data, size_t len,
unsigned int bpf_flags)
{
size_t fl = bpf_frame_header_len(ifp), falen;
const struct interface *ifn;
@ -292,108 +293,39 @@ arp_packet(struct interface *ifp, uint8_t *data, size_t len)
if (IN_ARE_ADDR_EQUAL(&arm.sip, &astate->addr) ||
(IN_IS_ADDR_UNSPECIFIED(&arm.sip) &&
IN_ARE_ADDR_EQUAL(&arm.tip, &astate->addr) &&
state->bpf_flags & BPF_BCAST))
bpf_flags & BPF_BCAST))
arp_found(astate, &arm);
}
}
static void
arp_close(struct interface *ifp)
{
struct dhcpcd_ctx *ctx = ifp->ctx;
struct iarp_state *state;
#ifdef PRIVSEP
if (IN_PRIVSEP(ctx)) {
if (IN_PRIVSEP_SE(ctx) &&
ps_bpf_closearp(ifp) == -1)
logerr(__func__);
return;
}
#endif
if ((state = ARP_STATE(ifp)) == NULL)
return;
if (state->bpf_fd == -1)
return;
eloop_event_delete(ctx->eloop, state->bpf_fd);
bpf_close(ifp, state->bpf_fd);
state->bpf_fd = -1;
state->bpf_flags |= BPF_EOF;
}
static void
arp_tryfree(struct iarp_state *state)
{
struct interface *ifp = state->ifp;
/* If there are no more ARP states, close the socket. */
if (TAILQ_FIRST(&state->arp_states) == NULL) {
arp_close(ifp);
if (state->bpf_flags & BPF_READING)
state->bpf_flags |= BPF_EOF;
else {
free(state);
ifp->if_data[IF_DATA_ARP] = NULL;
}
} else if (state->bpf_fd != -1) {
if (bpf_arp(ifp, state->bpf_fd) == -1)
logerr(__func__);
}
}
static void
arp_read(void *arg)
{
struct iarp_state *state = arg;
struct interface *ifp = state->ifp;
struct arp_state *astate = arg;
struct bpf *bpf = astate->bpf;
struct interface *ifp = astate->iface;
uint8_t buf[ARP_LEN];
ssize_t bytes;
struct in_addr addr = astate->addr;
/* Some RAW mechanisms are generic file descriptors, not sockets.
* This means we have no kernel call to just get one packet,
* so we have to process the entire buffer. */
state->bpf_flags &= ~BPF_EOF;
state->bpf_flags |= BPF_READING;
while (!(state->bpf_flags & BPF_EOF)) {
bytes = bpf_read(ifp, state->bpf_fd, buf, sizeof(buf),
&state->bpf_flags);
bpf->bpf_flags &= ~BPF_EOF;
while (!(bpf->bpf_flags & BPF_EOF)) {
bytes = bpf_read(bpf, buf, sizeof(buf));
if (bytes == -1) {
logerr("%s: %s", __func__, ifp->name);
arp_close(ifp);
break;
arp_free(astate);
return;
}
arp_packet(ifp, buf, (size_t)bytes);
arp_packet(ifp, buf, (size_t)bytes, bpf->bpf_flags);
/* Check we still have a state after processing. */
if ((state = ARP_STATE(ifp)) == NULL)
if ((astate = arp_find(ifp, &addr)) == NULL)
break;
if ((bpf = astate->bpf) == NULL)
break;
}
if (state != NULL) {
state->bpf_flags &= ~BPF_READING;
/* Try and free the state if nothing left to do. */
arp_tryfree(state);
}
}
static int
arp_open(struct interface *ifp)
{
struct iarp_state *state;
#ifdef PRIVSEP
if (IN_PRIVSEP_SE(ifp->ctx))
return ps_bpf_openarp(ifp) == -1 ? -1 : 0;
#endif
state = ARP_STATE(ifp);
if (state->bpf_fd == -1) {
state->bpf_fd = bpf_open(ifp, bpf_arp);
if (state->bpf_fd == -1)
return -1;
eloop_event_add(ifp->ctx->eloop, state->bpf_fd, arp_read, state);
}
return state->bpf_fd;
}
static void
@ -425,7 +357,7 @@ arp_probe1(void *arg)
ifp->name, inet_ntoa(astate->addr),
astate->probes ? astate->probes : PROBE_NUM, PROBE_NUM,
(float)delay / MSEC_PER_SEC);
if (arp_request(ifp, NULL, &astate->addr) == -1)
if (arp_request(astate, NULL) == -1)
logerr(__func__);
}
@ -436,11 +368,6 @@ arp_probe(struct arp_state *astate)
astate->probes = 0;
logdebugx("%s: probing for %s",
astate->iface->name, inet_ntoa(astate->addr));
if (!(IN_PRIVSEP(astate->iface->ctx)) && arp_open(astate->iface) == -1)
{
logerr(__func__);
return;
}
arp_probe1(astate);
}
#endif /* ARP */
@ -501,7 +428,7 @@ arp_announce1(void *arg)
goto skip_request;
#endif
if (arp_request(ifp, &astate->addr, &astate->addr) == -1)
if (arp_request(astate, &astate->addr) == -1)
logerr(__func__);
#ifndef __linux__
@ -516,7 +443,7 @@ skip_request:
astate);
}
void
static void
arp_announce(struct arp_state *astate)
{
struct iarp_state *state;
@ -524,12 +451,6 @@ arp_announce(struct arp_state *astate)
struct arp_state *a2;
int r;
if (!(IN_PRIVSEP(astate->iface->ctx)) && arp_open(astate->iface) == -1)
{
logerr(__func__);
return;
}
/* Cancel any other ARP announcements for this address. */
TAILQ_FOREACH(ifp, astate->iface->ctx->ifaces, next) {
state = ARP_STATE(ifp);
@ -557,25 +478,26 @@ arp_announce(struct arp_state *astate)
arp_announce1(astate);
}
void
struct arp_state *
arp_ifannounceaddr(struct interface *ifp, const struct in_addr *ia)
{
struct arp_state *astate;
if (ifp->flags & IFF_NOARP)
return;
if (ifp->flags & IFF_NOARP || !(ifp->options->options & DHCPCD_ARP))
return NULL;
astate = arp_find(ifp, ia);
if (astate == NULL) {
astate = arp_new(ifp, ia);
if (astate == NULL)
return;
return NULL;
astate->announced_cb = arp_free;
}
arp_announce(astate);
return astate;
}
void
struct arp_state *
arp_announceaddr(struct dhcpcd_ctx *ctx, const struct in_addr *ia)
{
struct interface *ifp, *iff = NULL;
@ -588,7 +510,7 @@ arp_announceaddr(struct dhcpcd_ctx *ctx, const struct in_addr *ia)
if (iap == NULL)
continue;
#ifdef IN_IFF_NOTUSEABLE
if (!(iap->addr_flags & IN_IFF_NOTUSEABLE))
if (iap->addr_flags & IN_IFF_NOTUSEABLE)
continue;
#endif
if (iff != NULL && iff->metric < ifp->metric)
@ -596,41 +518,9 @@ arp_announceaddr(struct dhcpcd_ctx *ctx, const struct in_addr *ia)
iff = ifp;
}
if (iff == NULL)
return;
return NULL;
arp_ifannounceaddr(iff, ia);
}
void
arp_change(struct arp_state *astate, const struct in_addr *addr)
{
struct interface *ifp = astate->iface;
struct iarp_state *state = ARP_STATE(ifp);
#ifdef PRIVSEP
if (!IN_IS_ADDR_UNSPECIFIED(&astate->addr) &&
IN_PRIVSEP_SE(ifp->ctx))
{
if (ps_bpf_deladdr(ifp, &astate->addr) == -1)
logerr(__func__);
}
#endif
if (addr != NULL)
astate->addr = *addr;
else
astate->addr.s_addr = INADDR_ANY;
#ifdef PRIVSEP
if (addr != NULL && IN_PRIVSEP_SE(ifp->ctx)) {
if (ps_bpf_addaddr(ifp, addr) == -1)
logerr(__func__);
} else
#endif
if (state->bpf_fd != -1) {
if (bpf_arp(ifp, state->bpf_fd) == -1)
logerr(__func__); /* try and continue */
}
return arp_ifannounceaddr(iff, ia);
}
struct arp_state *
@ -640,25 +530,15 @@ arp_new(struct interface *ifp, const struct in_addr *addr)
struct arp_state *astate;
if ((state = ARP_STATE(ifp)) == NULL) {
#ifdef PRIVSEP
/* We need to ensure ARP is spawned so we can add to it. */
if (IN_PRIVSEP_SE(ifp->ctx) && arp_open(ifp) == -1) {
logerr(__func__);
return NULL;
}
#endif
ifp->if_data[IF_DATA_ARP] = malloc(sizeof(*state));
state = ARP_STATE(ifp);
if (state == NULL) {
logerr(__func__);
return NULL;
}
state->ifp = ifp;
state->bpf_fd = -1;
state->bpf_flags = 0;
TAILQ_INIT(&state->arp_states);
} else {
if (addr && (astate = arp_find(ifp, addr)))
if ((astate = arp_find(ifp, addr)) != NULL)
return astate;
}
@ -667,9 +547,31 @@ arp_new(struct interface *ifp, const struct in_addr *addr)
return NULL;
}
astate->iface = ifp;
astate->addr = *addr;
#ifdef PRIVSEP
if (IN_PRIVSEP(ifp->ctx)) {
if (ps_bpf_openarp(ifp, addr) == -1) {
logerr(__func__);
free(astate);
return NULL;
}
} else
#endif
{
astate->bpf = bpf_open(ifp, bpf_arp, addr);
if (astate->bpf == NULL) {
logerr(__func__);
free(astate);
return NULL;
}
eloop_event_add(ifp->ctx->eloop, astate->bpf->bpf_fd,
arp_read, astate);
}
state = ARP_STATE(ifp);
TAILQ_INSERT_TAIL(&state->arp_states, astate, next);
arp_change(astate, addr);
return astate;
}
@ -684,20 +586,36 @@ void
arp_free(struct arp_state *astate)
{
struct interface *ifp;
struct dhcpcd_ctx *ctx;
struct iarp_state *state;
if (astate == NULL)
return;
ifp = astate->iface;
eloop_timeout_delete(ifp->ctx->eloop, NULL, astate);
arp_change(astate, NULL);
ctx = ifp->ctx;
eloop_timeout_delete(ctx->eloop, NULL, astate);
state = ARP_STATE(ifp);
TAILQ_REMOVE(&state->arp_states, astate, next);
if (astate->free_cb)
astate->free_cb(astate);
#ifdef PRIVSEP
if (IN_PRIVSEP(ctx) && ps_bpf_closearp(ifp, &astate->addr) == -1)
logerr(__func__);
#endif
if (astate->bpf != NULL) {
eloop_event_delete(ctx->eloop, astate->bpf->bpf_fd);
bpf_close(astate->bpf);
}
free(astate);
arp_tryfree(state);
if (TAILQ_FIRST(&state->arp_states) == NULL) {
free(state);
ifp->if_data[IF_DATA_ARP] = NULL;
}
}
void
@ -718,6 +636,4 @@ arp_drop(struct interface *ifp)
while ((state = ARP_STATE(ifp)) != NULL &&
(astate = TAILQ_FIRST(&state->arp_states)) != NULL)
arp_free(astate);
/* No need to close because the last free will close */
}

View File

@ -41,12 +41,14 @@
#define RATE_LIMIT_INTERVAL 60
#define DEFEND_INTERVAL 10
#include "bpf.h"
#include "dhcpcd.h"
#include "if.h"
#ifdef IN_IFF_DUPLICATED
/* NetBSD gained RFC 5227 support in the kernel.
* This means dhcpcd doesn't need ARP except for ARPing support. */
* This means dhcpcd doesn't need ARP except for ARPing support
* and ARP announcing an address. */
#if defined(__NetBSD_Version__) && __NetBSD_Version__ >= 799003900
#define KERNEL_RFC5227
#endif
@ -66,24 +68,22 @@ struct arp_msg {
struct arp_state {
TAILQ_ENTRY(arp_state) next;
struct interface *iface;
struct in_addr addr;
struct bpf *bpf;
int probes;
int claims;
struct timespec defend;
void (*found_cb)(struct arp_state *, const struct arp_msg *);
void (*not_found_cb)(struct arp_state *);
void (*announced_cb)(struct arp_state *);
void (*defend_failed_cb)(struct arp_state *);
void (*free_cb)(struct arp_state *);
struct in_addr addr;
int probes;
int claims;
struct timespec defend;
};
TAILQ_HEAD(arp_statehead, arp_state);
struct iarp_state {
struct interface *ifp;
int bpf_fd;
unsigned int bpf_flags;
struct arp_statehead arp_states;
};
@ -93,13 +93,11 @@ struct iarp_state {
((const struct iarp_state *)(ifp)->if_data[IF_DATA_ARP])
#ifdef ARP
void arp_packet(struct interface *, uint8_t *, size_t);
void arp_packet(struct interface *, uint8_t *, size_t, unsigned int);
struct arp_state *arp_new(struct interface *, const struct in_addr *);
void arp_change(struct arp_state *, const struct in_addr *);
void arp_probe(struct arp_state *);
void arp_announce(struct arp_state *);
void arp_announceaddr(struct dhcpcd_ctx *, const struct in_addr *);
void arp_ifannounceaddr(struct interface *, const struct in_addr *);
struct arp_state *arp_announceaddr(struct dhcpcd_ctx *, const struct in_addr *);
struct arp_state *arp_ifannounceaddr(struct interface *, const struct in_addr *);
void arp_cancel(struct arp_state *);
struct arp_state * arp_find(struct interface *, const struct in_addr *);
void arp_free(struct arp_state *);

View File

@ -29,10 +29,9 @@
#ifndef BPF_HEADER
#define BPF_HEADER
#define BPF_READING (1U << 0)
#define BPF_EOF (1U << 1)
#define BPF_PARTIALCSUM (1U << 2)
#define BPF_BCAST (1U << 3)
#define BPF_EOF 0x01U
#define BPF_PARTIALCSUM 0x02U
#define BPF_BCAST 0x04U
/*
* Even though we program the BPF filter should we trust it?
@ -55,16 +54,28 @@
#include "dhcpcd.h"
struct bpf {
const struct interface *bpf_ifp;
int bpf_fd;
unsigned int bpf_flags;
void *bpf_buffer;
size_t bpf_size;
size_t bpf_len;
size_t bpf_pos;
};
extern const char *bpf_name;
size_t bpf_frame_header_len(const struct interface *);
void *bpf_frame_header_src(const struct interface *, void *, size_t *);
void *bpf_frame_header_dst(const struct interface *, void *, size_t *);
int bpf_frame_bcast(const struct interface *, const char *frame);
int bpf_open(struct interface *, int (*)(struct interface *, int));
int bpf_close(struct interface *, int);
int bpf_frame_bcast(const struct interface *, const void *);
struct bpf * bpf_open(const struct interface *,
int (*)(const struct bpf *, const struct in_addr *),
const struct in_addr *);
void bpf_close(struct bpf *);
int bpf_attach(int, void *, unsigned int);
ssize_t bpf_send(const struct interface *, int, uint16_t, const void *, size_t);
ssize_t bpf_read(struct interface *, int, void *, size_t, unsigned int *);
int bpf_arp(struct interface *, int);
int bpf_bootp(struct interface *, int);
ssize_t bpf_send(const struct bpf *, uint16_t, const void *, size_t);
ssize_t bpf_read(struct bpf *, void *, size_t);
int bpf_arp(const struct bpf *, const struct in_addr *);
int bpf_bootp(const struct bpf *, const struct in_addr *);
#endif

View File

@ -26,17 +26,19 @@
* SUCH DAMAGE.
*/
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common.h"
#include "dhcpcd.h"
#include "if-options.h"
#include "logerr.h"
const char *
hwaddr_ntoa(const void *hwaddr, size_t hwlen, char *buf, size_t buflen)
@ -44,7 +46,7 @@ hwaddr_ntoa(const void *hwaddr, size_t hwlen, char *buf, size_t buflen)
const unsigned char *hp, *ep;
char *p;
if (buf == NULL)
if (buf == NULL || hwlen == 0)
return NULL;
if (hwlen * 3 > buflen) {
@ -103,38 +105,97 @@ hwaddr_aton(uint8_t *buffer, const char *addr)
return len;
}
size_t
read_hwaddr_aton(uint8_t **data, const char *path)
ssize_t
readfile(const char *file, void *data, size_t len)
{
FILE *fp;
char *buf;
size_t buf_len, len;
int fd;
ssize_t bytes;
if ((fp = fopen(path, "r")) == NULL)
return 0;
fd = open(file, O_RDONLY);
if (fd == -1)
return -1;
bytes = read(fd, data, len);
close(fd);
if ((size_t)bytes == len) {
errno = ENOBUFS;
return -1;
}
return bytes;
}
buf = NULL;
buf_len = len = 0;
*data = NULL;
while (getline(&buf, &buf_len, fp) != -1) {
if ((len = hwaddr_aton(NULL, buf)) != 0) {
if (buf_len >= len)
*data = (uint8_t *)buf;
else {
if ((*data = malloc(len)) == NULL)
len = 0;
}
if (len != 0)
(void)hwaddr_aton(*data, buf);
if (buf_len < len)
free(buf);
ssize_t
writefile(const char *file, mode_t mode, const void *data, size_t len)
{
int fd;
ssize_t bytes;
fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, mode);
if (fd == -1)
return -1;
bytes = write(fd, data, len);
close(fd);
return bytes;
}
int
filemtime(const char *file, time_t *time)
{
struct stat st;
if (stat(file, &st) == -1)
return -1;
*time = st.st_mtime;
return 0;
}
/* Handy routine to read very long lines in text files.
* This means we read the whole line and avoid any nasty buffer overflows.
* We strip leading space and avoid comment lines, making the code that calls
* us smaller. */
char *
get_line(char ** __restrict buf, ssize_t * __restrict buflen)
{
char *p, *c;
bool quoted;
do {
p = *buf;
if (*buf == NULL)
return NULL;
c = memchr(*buf, '\n', (size_t)*buflen);
if (c == NULL) {
c = memchr(*buf, '\0', (size_t)*buflen);
if (c == NULL)
return NULL;
*buflen = c - *buf;
*buf = NULL;
} else {
*c++ = '\0';
*buflen -= c - *buf;
*buf = c;
}
for (; *p == ' ' || *p == '\t'; p++)
;
} while (*p == '\0' || *p == '\n' || *p == '#' || *p == ';');
/* Strip embedded comments unless in a quoted string or escaped */
quoted = false;
for (c = p; *c != '\0'; c++) {
if (*c == '\\') {
c++; /* escaped */
continue;
}
if (*c == '"')
quoted = !quoted;
else if (*c == '#' && !quoted) {
*c = '\0';
break;
}
}
fclose(fp);
return len;
return p;
}
int
is_root_local(void)
{

View File

@ -147,6 +147,9 @@
const char *hwaddr_ntoa(const void *, size_t, char *, size_t);
size_t hwaddr_aton(uint8_t *, const char *);
size_t read_hwaddr_aton(uint8_t **, const char *);
ssize_t readfile(const char *, void *, size_t);
ssize_t writefile(const char *, mode_t, const void *, size_t);
int filemtime(const char *, time_t *);
char *get_line(char ** __restrict, ssize_t * __restrict);
int is_root_local(void);
#endif

View File

@ -193,21 +193,33 @@ control_handle_unpriv(void *arg)
}
static int
make_sock(struct sockaddr_un *sa, const char *ifname, bool unpriv)
make_sock(struct sockaddr_un *sa, const char *ifname, sa_family_t family,
bool unpriv)
{
int fd;
#define SOCK_FLAGS SOCK_CLOEXEC | SOCK_NONBLOCK
if ((fd = xsocket(AF_UNIX, SOCK_STREAM | SOCK_FLAGS, 0)) == -1)
if ((fd = xsocket(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0)) == -1)
return -1;
#undef SOCK_FLAGS
memset(sa, 0, sizeof(*sa));
sa->sun_family = AF_UNIX;
if (unpriv)
strlcpy(sa->sun_path, UNPRIVSOCKET, sizeof(sa->sun_path));
else {
const char *per;
switch(family) {
case AF_INET:
per = "-4";
break;
case AF_INET6:
per = "-6";
break;
default:
per = "";
break;
}
snprintf(sa->sun_path, sizeof(sa->sun_path), CONTROLSOCKET,
ifname ? ifname : "", ifname ? "." : "");
ifname ? ifname : "", ifname ? per : "", ifname ? "." : "");
}
return fd;
}
@ -216,14 +228,17 @@ make_sock(struct sockaddr_un *sa, const char *ifname, bool unpriv)
#define S_UNPRIV (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
static int
control_start1(struct dhcpcd_ctx *ctx, const char *ifname, mode_t fmode)
control_start1(struct dhcpcd_ctx *ctx, const char *ifname, sa_family_t family,
mode_t fmode)
{
struct sockaddr_un sa;
int fd;
socklen_t len;
if ((fd = make_sock(&sa, ifname, (fmode & S_UNPRIV) == S_UNPRIV)) == -1)
fd = make_sock(&sa, ifname, family, (fmode & S_UNPRIV) == S_UNPRIV);
if (fd == -1)
return -1;
len = (socklen_t)SUN_LEN(&sa);
unlink(sa.sun_path);
if (bind(fd, (struct sockaddr *)&sa, len) == -1 ||
@ -244,17 +259,19 @@ control_start1(struct dhcpcd_ctx *ctx, const char *ifname, mode_t fmode)
}
int
control_start(struct dhcpcd_ctx *ctx, const char *ifname)
control_start(struct dhcpcd_ctx *ctx, const char *ifname, sa_family_t family)
{
int fd;
if ((fd = control_start1(ctx, ifname, S_PRIV)) == -1)
if ((fd = control_start1(ctx, ifname, family, S_PRIV)) == -1)
return -1;
ctx->control_fd = fd;
eloop_event_add(ctx->eloop, fd, control_handle, ctx);
if (ifname == NULL && (fd = control_start1(ctx, NULL, S_UNPRIV)) != -1){
if (ifname == NULL &&
(fd = control_start1(ctx, NULL, AF_UNSPEC, S_UNPRIV)) != -1)
{
/* We must be in master mode, so create an unprivileged socket
* to allow normal users to learn the status of dhcpcd. */
ctx->control_unpriv_fd = fd;
@ -318,12 +335,12 @@ control_stop(struct dhcpcd_ctx *ctx)
}
int
control_open(const char *ifname, bool unpriv)
control_open(const char *ifname, sa_family_t family, bool unpriv)
{
struct sockaddr_un sa;
int fd;
if ((fd = make_sock(&sa, ifname, unpriv)) != -1) {
if ((fd = make_sock(&sa, ifname, family, unpriv)) != -1) {
socklen_t len;
len = (socklen_t)SUN_LEN(&sa);

View File

@ -66,9 +66,9 @@ TAILQ_HEAD(fd_list_head, fd_list);
#define FD_LISTEN (1<<0)
#define FD_UNPRIV (1<<1)
int control_start(struct dhcpcd_ctx *, const char *);
int control_start(struct dhcpcd_ctx *, const char *, sa_family_t);
int control_stop(struct dhcpcd_ctx *);
int control_open(const char *, bool);
int control_open(const char *, sa_family_t, bool);
ssize_t control_send(struct dhcpcd_ctx *, int, char * const *);
int control_queue(struct fd_list *, void *, size_t, bool);

View File

@ -29,7 +29,7 @@
#define CONFIG_H
#define PACKAGE "dhcpcd"
#define VERSION "9.0.2"
#define VERSION "9.1.0"
#ifndef PRIVSEP_USER
# define PRIVSEP_USER "_" PACKAGE
@ -60,7 +60,7 @@
# define PIDFILE RUNDIR "/%s%s%spid"
#endif
#ifndef CONTROLSOCKET
# define CONTROLSOCKET RUNDIR "/%s%ssock"
# define CONTROLSOCKET RUNDIR "/%s%s%ssock"
#endif
#ifndef UNPRIVSOCKET
# define UNPRIVSOCKET RUNDIR "/unpriv.sock"

View File

@ -49,13 +49,8 @@ int dev_init(struct dev *, const struct dev_dhcpcd *);
#include "dhcpcd.h"
int dev_initialized(struct dhcpcd_ctx *, const char *);
int dev_listening(struct dhcpcd_ctx *);
int dev_start(struct dhcpcd_ctx *);
int dev_start(struct dhcpcd_ctx *, int (*)(void *, int, const char *));
void dev_stop(struct dhcpcd_ctx *);
#else
#define dev_initialized(a, b) (1)
#define dev_listening(a) (0)
#define dev_start(a) {}
#define dev_stop(a) {}
#endif
#endif

View File

@ -26,7 +26,6 @@
* SUCH DAMAGE.
*/
#include <sys/stat.h>
#include <sys/utsname.h>
#include <ctype.h>
@ -176,9 +175,10 @@ dhcp_vendor(char *str, size_t len)
return -1;
p += l;
len -= (size_t)l;
l = if_machinearch(p, len);
l = if_machinearch(p + 1, len - 1);
if (l == -1 || (size_t)(l + 1) > len)
return -1;
*p = ':';
p += l;
return p - str;
}
@ -202,8 +202,8 @@ make_option_mask(const struct dhcp_opt *dopts, size_t dopts_len,
continue;
if (strncmp(token, "dhcp6_", 6) == 0)
token += 6;
if (strncmp(token, "nd6_", 4) == 0)
token += 4;
if (strncmp(token, "nd_", 3) == 0)
token += 3;
match = 0;
for (i = 0, opt = odopts; i < odopts_len; i++, opt++) {
if (opt->var == NULL || opt->option == 0)
@ -945,38 +945,85 @@ dhcp_zero_index(struct dhcp_opt *opt)
dhcp_zero_index(o);
}
size_t
dhcp_read_lease_fd(int fd, void **lease)
ssize_t
dhcp_readfile(struct dhcpcd_ctx *ctx, const char *file, void *data, size_t len)
{
struct stat st;
size_t sz;
void *buf;
ssize_t len;
if (fstat(fd, &st) != 0)
goto out;
if (!S_ISREG(st.st_mode)) {
errno = EINVAL;
goto out;
}
if (st.st_size > UINT32_MAX) {
errno = E2BIG;
goto out;
}
#ifdef PRIVSEP
if (ctx->options & DHCPCD_PRIVSEP &&
!(ctx->options & DHCPCD_PRIVSEPROOT))
return ps_root_readfile(ctx, file, data, len);
#else
UNUSED(ctx);
#endif
sz = (size_t)st.st_size;
if (sz == 0)
goto out;
if ((buf = malloc(sz)) == NULL)
goto out;
if ((len = read(fd, buf, sz)) == -1) {
free(buf);
goto out;
}
*lease = buf;
return (size_t)len;
out:
*lease = NULL;
return 0;
return readfile(file, data, len);
}
ssize_t
dhcp_writefile(struct dhcpcd_ctx *ctx, const char *file, mode_t mode,
const void *data, size_t len)
{
#ifdef PRIVSEP
if (ctx->options & DHCPCD_PRIVSEP &&
!(ctx->options & DHCPCD_PRIVSEPROOT))
return ps_root_writefile(ctx, file, mode, data, len);
#else
UNUSED(ctx);
#endif
return writefile(file, mode, data, len);
}
int
dhcp_filemtime(struct dhcpcd_ctx *ctx, const char *file, time_t *time)
{
#ifdef PRIVSEP
if (ctx->options & DHCPCD_PRIVSEP &&
!(ctx->options & DHCPCD_PRIVSEPROOT))
return (int)ps_root_filemtime(ctx, file, time);
#else
UNUSED(ctx);
#endif
return filemtime(file, time);
}
int
dhcp_unlink(struct dhcpcd_ctx *ctx, const char *file)
{
#ifdef PRIVSEP
if (ctx->options & DHCPCD_PRIVSEP &&
!(ctx->options & DHCPCD_PRIVSEPROOT))
return (int)ps_root_unlink(ctx, file);
#else
UNUSED(ctx);
#endif
return unlink(file);
}
size_t
dhcp_read_hwaddr_aton(struct dhcpcd_ctx *ctx, uint8_t **data, const char *file)
{
char buf[BUFSIZ];
ssize_t bytes;
size_t len;
bytes = dhcp_readfile(ctx, file, buf, sizeof(buf));
if (bytes == -1 || bytes == sizeof(buf))
return 0;
bytes[buf] = '\0';
len = hwaddr_aton(NULL, buf);
if (len == 0)
return 0;
*data = malloc(len);
if (*data == NULL)
return 0;
hwaddr_aton(*data, buf);
return len;
}

View File

@ -136,6 +136,11 @@ void dhcp_envoption(struct dhcpcd_ctx *,
const uint8_t *, size_t, struct dhcp_opt **),
const uint8_t *od, size_t ol);
void dhcp_zero_index(struct dhcp_opt *);
size_t dhcp_read_lease_fd(int, void **);
ssize_t dhcp_readfile(struct dhcpcd_ctx *, const char *, void *, size_t);
ssize_t dhcp_writefile(struct dhcpcd_ctx *, const char *, mode_t,
const void *, size_t);
int dhcp_filemtime(struct dhcpcd_ctx *, const char *, time_t *);
int dhcp_unlink(struct dhcpcd_ctx *, const char *);
size_t dhcp_read_hwaddr_aton(struct dhcpcd_ctx *, uint8_t **, const char *);
#endif

View File

@ -41,6 +41,7 @@
#include <stdint.h>
#include "arp.h"
#include "bpf.h"
#include "auth.h"
#include "dhcp-common.h"
@ -221,9 +222,8 @@ struct dhcp_state {
uint32_t xid;
int socket;
int bpf_fd;
unsigned int bpf_flags;
int udp_fd;
struct bpf *bpf;
int udp_rfd;
struct ipv4_addr *addr;
uint8_t added;
@ -256,7 +256,7 @@ ssize_t print_rfc3361(FILE *, const uint8_t *, size_t);
ssize_t print_rfc3442(FILE *, const uint8_t *, size_t);
int dhcp_openudp(struct in_addr *);
void dhcp_packet(struct interface *, uint8_t *, size_t);
void dhcp_packet(struct interface *, uint8_t *, size_t, unsigned int);
void dhcp_recvmsg(struct dhcpcd_ctx *, struct msghdr *);
void dhcp_printoptions(const struct dhcpcd_ctx *,
const struct dhcp_opt *, size_t);

View File

@ -168,9 +168,10 @@ enum DH6S {
DH6S_INFORMED,
DH6S_RENEW_REQUESTED,
DH6S_PROBE,
DH6S_DECLINE,
DH6S_DELEGATED,
DH6S_RELEASE,
DH6S_RELEASED
DH6S_RELEASED,
};
struct dhcp6_state {
@ -225,6 +226,7 @@ struct dhcp6_state {
(D6_CSTATE((ifp)) && \
D6_CSTATE((ifp))->reason && dhcp6_dadcompleted((ifp)))
int dhcp6_openraw(void);
int dhcp6_openudp(unsigned int, struct in6_addr *);
void dhcp6_recvmsg(struct dhcpcd_ctx *, struct msghdr *, struct ipv6_addr *);
void dhcp6_printoptions(const struct dhcpcd_ctx *,

View File

@ -33,458 +33,458 @@
#include <unistd.h>
const char * const dhcpcd_embedded_conf[] = {
const char dhcpcd_embedded_conf[] =
#ifdef SMALL
"define 1 request ipaddress subnet_mask",
"define 121 rfc3442 classless_static_routes",
"define 3 request array ipaddress routers",
"define 6 array ipaddress domain_name_servers",
"define 12 dname host_name",
"define 15 array dname domain_name",
"define 26 uint16 interface_mtu",
"define 28 request ipaddress broadcast_address",
"define 33 request array ipaddress static_routes",
"define 50 ipaddress dhcp_requested_address",
"define 51 request uint32 dhcp_lease_time",
"define 52 byte dhcp_option_overload",
"define 53 byte dhcp_message_type",
"define 54 ipaddress dhcp_server_identifier",
"define 55 array byte dhcp_parameter_request_list",
"define 56 string dhcp_message",
"define 57 uint16 dhcp_max_message_size",
"define 58 request uint32 dhcp_renewal_time",
"define 59 request uint32 dhcp_rebinding_time",
"define 60 string vendor_class_identifier",
"define 61 binhex dhcp_client_identifier",
"define 80 norequest flag rapid_commit",
"define 81 embed fqdn",
"embed bitflags=0000NEOS flags",
"embed byte rcode1",
"embed byte rcode2",
"embed optional domain fqdn",
"define 119 array domain domain_search",
"define 249 rfc3442 ms_classless_static_routes",
"definend 1 binhex source_address",
"definend 2 binhex target_address",
"definend 3 index embed prefix_information",
"embed byte length",
"embed bitflags=LA flags",
"embed uint32 vltime",
"embed uint32 pltime",
"embed uint32 reserved",
"embed array ip6address prefix",
"definend 5 embed mtu",
"embed uint16 reserved",
"embed uint32 mtu",
"definend 25 index embed rdnss",
"embed uint16 reserved",
"embed uint32 lifetime",
"embed array ip6address servers",
"definend 31 index embed dnssl",
"embed uint16 reserved",
"embed uint32 lifetime",
"embed domain search",
"define6 1 binhex client_id",
"define6 2 binhex server_id",
"define6 3 norequest index embed ia_na",
"embed binhex:4 iaid",
"embed uint32 t1",
"embed uint32 t2",
"encap 5 option",
"encap 13 option",
"define6 4 norequest index embed ia_ta",
"embed uint32 iaid",
"encap 5 option",
"encap 13 option",
"define6 5 norequest index embed ia_addr",
"embed ip6address ia_addr",
"embed uint32 pltime",
"embed uint32 vltime",
"encap 13 option",
"define6 12 ip6address unicast",
"define6 13 norequest embed status_code",
"embed uint16 status_code",
"embed optional string message",
"define6 18 binhex interface_id",
"define6 19 byte reconfigure_msg",
"define6 20 flag reconfigure_accept",
"define6 23 array ip6address name_servers",
"define6 24 array domain domain_search",
"define6 39 embed fqdn",
"embed bitflags=00000NOS flags",
"embed optional domain fqdn",
"define6 82 request uint32 sol_max_rt",
"define6 83 request uint32 inf_max_rt",
"define 1 request ipaddress subnet_mask\n"
"define 121 rfc3442 classless_static_routes\n"
"define 3 request array ipaddress routers\n"
"define 6 array ipaddress domain_name_servers\n"
"define 12 dname host_name\n"
"define 15 array dname domain_name\n"
"define 26 uint16 interface_mtu\n"
"define 28 request ipaddress broadcast_address\n"
"define 33 request array ipaddress static_routes\n"
"define 50 ipaddress dhcp_requested_address\n"
"define 51 request uint32 dhcp_lease_time\n"
"define 52 byte dhcp_option_overload\n"
"define 53 byte dhcp_message_type\n"
"define 54 ipaddress dhcp_server_identifier\n"
"define 55 array byte dhcp_parameter_request_list\n"
"define 56 string dhcp_message\n"
"define 57 uint16 dhcp_max_message_size\n"
"define 58 request uint32 dhcp_renewal_time\n"
"define 59 request uint32 dhcp_rebinding_time\n"
"define 60 string vendor_class_identifier\n"
"define 61 binhex dhcp_client_identifier\n"
"define 80 norequest flag rapid_commit\n"
"define 81 embed fqdn\n"
"embed bitflags=0000NEOS flags\n"
"embed byte rcode1\n"
"embed byte rcode2\n"
"embed optional domain fqdn\n"
"define 119 array domain domain_search\n"
"define 249 rfc3442 ms_classless_static_routes\n"
"definend 1 binhex source_address\n"
"definend 2 binhex target_address\n"
"definend 3 index embed prefix_information\n"
"embed byte length\n"
"embed bitflags=LA flags\n"
"embed uint32 vltime\n"
"embed uint32 pltime\n"
"embed uint32 reserved\n"
"embed array ip6address prefix\n"
"definend 5 embed mtu\n"
"embed uint16 reserved\n"
"embed uint32 mtu\n"
"definend 25 index embed rdnss\n"
"embed uint16 reserved\n"
"embed uint32 lifetime\n"
"embed array ip6address servers\n"
"definend 31 index embed dnssl\n"
"embed uint16 reserved\n"
"embed uint32 lifetime\n"
"embed domain search\n"
"define6 1 binhex client_id\n"
"define6 2 binhex server_id\n"
"define6 3 norequest index embed ia_na\n"
"embed binhex:4 iaid\n"
"embed uint32 t1\n"
"embed uint32 t2\n"
"encap 5 option\n"
"encap 13 option\n"
"define6 4 norequest index embed ia_ta\n"
"embed uint32 iaid\n"
"encap 5 option\n"
"encap 13 option\n"
"define6 5 norequest index embed ia_addr\n"
"embed ip6address ia_addr\n"
"embed uint32 pltime\n"
"embed uint32 vltime\n"
"encap 13 option\n"
"define6 12 ip6address unicast\n"
"define6 13 norequest embed status_code\n"
"embed uint16 status_code\n"
"embed optional string message\n"
"define6 18 binhex interface_id\n"
"define6 19 byte reconfigure_msg\n"
"define6 20 flag reconfigure_accept\n"
"define6 23 array ip6address name_servers\n"
"define6 24 array domain domain_search\n"
"define6 39 embed fqdn\n"
"embed bitflags=00000NOS flags\n"
"embed optional domain fqdn\n"
"define6 82 request uint32 sol_max_rt\n"
"define6 83 request uint32 inf_max_rt\n"
#else
"define 1 request ipaddress subnet_mask",
"define 121 rfc3442 classless_static_routes",
"define 2 uint32 time_offset",
"define 3 request array ipaddress routers",
"define 4 array ipaddress time_servers",
"define 5 array ipaddress ien116_name_servers",
"define 6 array ipaddress domain_name_servers",
"define 7 array ipaddress log_servers",
"define 8 array ipaddress cookie_servers",
"define 9 array ipaddress lpr_servers",
"define 10 array ipaddress impress_servers",
"define 11 array ipaddress resource_location_servers",
"define 12 dname host_name",
"define 13 uint16 boot_size",
"define 14 string merit_dump",
"define 15 array dname domain_name",
"define 16 ipaddress swap_server",
"define 17 string root_path",
"define 18 string extensions_path",
"define 19 byte ip_forwarding",
"define 20 byte non_local_source_routing",
"define 21 array ipaddress policy_filter",
"define 22 uint16 max_dgram_reassembly",
"define 23 byte default_ip_ttl",
"define 24 uint32 path_mtu_aging_timeout",
"define 25 array uint16 path_mtu_plateau_table",
"define 26 uint16 interface_mtu",
"define 27 byte all_subnets_local",
"define 28 request ipaddress broadcast_address",
"define 29 byte perform_mask_discovery",
"define 30 byte mask_supplier",
"define 31 byte router_discovery",
"define 32 ipaddress router_solicitation_address",
"define 33 request array ipaddress static_routes",
"define 34 byte trailer_encapsulation",
"define 35 uint32 arp_cache_timeout",
"define 36 uint16 ieee802_3_encapsulation",
"define 37 byte default_tcp_ttl",
"define 38 uint32 tcp_keepalive_interval",
"define 39 byte tcp_keepalive_garbage",
"define 40 string nis_domain",
"define 41 array ipaddress nis_servers",
"define 42 array ipaddress ntp_servers",
"define 43 binhex vendor_encapsulated_options",
"define 44 array ipaddress netbios_name_servers",
"define 45 ipaddress netbios_dd_server",
"define 46 byte netbios_node_type",
"define 47 string netbios_scope",
"define 48 array ipaddress font_servers",
"define 49 array ipaddress x_display_manager",
"define 50 ipaddress dhcp_requested_address",
"define 51 request uint32 dhcp_lease_time",
"define 52 byte dhcp_option_overload",
"define 53 byte dhcp_message_type",
"define 54 ipaddress dhcp_server_identifier",
"define 55 array byte dhcp_parameter_request_list",
"define 56 string dhcp_message",
"define 57 uint16 dhcp_max_message_size",
"define 58 request uint32 dhcp_renewal_time",
"define 59 request uint32 dhcp_rebinding_time",
"define 60 string vendor_class_identifier",
"define 61 binhex dhcp_client_identifier",
"define 64 string nisplus_domain",
"define 65 array ipaddress nisplus_servers",
"define 66 dname tftp_server_name",
"define 67 string bootfile_name",
"define 68 array ipaddress mobile_ip_home_agent",
"define 69 array ipaddress smtp_server",
"define 70 array ipaddress pop_server",
"define 71 array ipaddress nntp_server",
"define 72 array ipaddress www_server",
"define 73 array ipaddress finger_server",
"define 74 array ipaddress irc_server",
"define 75 array ipaddress streettalk_server",
"define 76 array ipaddress streettalk_directory_assistance_server",
"define 77 binhex user_class",
"define 78 embed slp_agent",
"embed byte mandatory",
"embed array ipaddress address",
"define 79 embed slp_service",
"embed byte mandatory",
"embed ascii scope_list",
"define 80 norequest flag rapid_commit",
"define 81 embed fqdn",
"embed bitflags=0000NEOS flags",
"embed byte rcode1",
"embed byte rcode2",
"embed optional domain fqdn",
"define 83 embed isns",
"embed byte reserved1",
"embed bitflags=00000SAE functions",
"embed byte reserved2",
"embed bitflags=00fFsSCE dd",
"embed byte reserved3",
"embed bitflags=0000DMHE admin",
"embed uint16 reserved4",
"embed byte reserved5",
"embed bitflags=0TXPAMSE server_security",
"embed array ipaddress servers",
"define 85 array ipaddress nds_servers",
"define 86 raw nds_tree_name",
"define 87 raw nds_context",
"define 88 array domain bcms_controller_names",
"define 89 array ipaddress bcms_controller_address",
"define 90 embed auth",
"embed byte protocol",
"embed byte algorithm",
"embed byte rdm",
"embed binhex:8 replay",
"embed binhex information",
"define 91 uint32 client_last_transaction_time",
"define 92 array ipaddress associated_ip",
"define 98 string uap_servers",
"define 99 encap geoconf_civic",
"embed byte what",
"embed uint16 country_code",
"define 100 string posix_timezone",
"define 101 string tzdb_timezone",
"define 116 byte auto_configure",
"define 117 array uint16 name_service_search",
"define 118 ipaddress subnet_selection",
"define 119 array domain domain_search",
"define 120 rfc3361 sip_server",
"define 122 encap tsp",
"encap 1 ipaddress dhcp_server",
"encap 2 ipaddress dhcp_secondary_server",
"encap 3 rfc3361 provisioning_server",
"encap 4 embed as_req_as_rep_backoff",
"embed uint32 nominal",
"embed uint32 maximum",
"embed uint32 retry",
"encap 5 embed ap_req_ap_rep_backoff",
"embed uint32 nominal",
"embed uint32 maximum",
"embed uint32 retry",
"encap 6 domain kerberos_realm",
"encap 7 byte ticket_granting_server_utilization",
"encap 8 byte provisioning_timer",
"define 123 binhex geoconf",
"define 124 binhex vivco",
"define 125 embed vivso",
"embed uint32 enterprise_number",
"define 136 array ipaddress pana_agent",
"define 137 domain lost_server",
"define 138 array ipaddress capwap_ac",
"define 139 encap mos_ip",
"encap 1 array ipaddress is",
"encap 2 array ipaddress cs",
"encap 3 array ipaddress es",
"define 140 encap mos_domain",
"encap 1 domain is",
"encap 2 domain cs",
"encap 3 domain es",
"define 141 array domain sip_ua_cs_list",
"define 142 array ipaddress andsf",
"define 143 array ip6address andsf6",
"define 144 binhex geoloc",
"define 145 array byte forcerenew_nonce_capable",
"define 146 embed rdnss_selection",
"embed byte prf",
"embed ipaddress primary",
"embed ipaddress secondary",
"embed array domain domains",
"define 150 array ipaddress tftp_servers",
"define 161 string mudurl",
"define 208 binhex pxelinux_magic",
"define 209 string config_file",
"define 210 string path_prefix",
"define 211 uint32 reboot_time",
"define 212 embed sixrd",
"embed byte mask_len",
"embed byte prefix_len",
"embed ip6address prefix",
"embed array ipaddress brip_address",
"define 213 domain access_domain",
"define 221 encap vss",
"encap 0 string nvt",
"encap 1 binhex vpn_id",
"encap 255 flag global",
"define 249 rfc3442 ms_classless_static_routes",
"define 252 string wpad_url",
"definend 1 binhex source_address",
"definend 2 binhex target_address",
"definend 3 index embed prefix_information",
"embed byte length",
"embed bitflags=LA flags",
"embed uint32 vltime",
"embed uint32 pltime",
"embed uint32 reserved",
"embed array ip6address prefix",
"definend 5 embed mtu",
"embed uint16 reserved",
"embed uint32 mtu",
"definend 25 index embed rdnss",
"embed uint16 reserved",
"embed uint32 lifetime",
"embed array ip6address servers",
"definend 31 index embed dnssl",
"embed uint16 reserved",
"embed uint32 lifetime",
"embed domain search",
"define6 1 binhex client_id",
"define6 2 binhex server_id",
"define6 3 norequest index embed ia_na",
"embed binhex:4 iaid",
"embed uint32 t1",
"embed uint32 t2",
"encap 5 option",
"encap 13 option",
"define6 4 norequest index embed ia_ta",
"embed uint32 iaid",
"encap 5 option",
"encap 13 option",
"define6 5 norequest index embed ia_addr",
"embed ip6address ia_addr",
"embed uint32 pltime",
"embed uint32 vltime",
"encap 13 option",
"define6 6 array uint16 option_request",
"define6 7 byte preference",
"define6 8 uint16 elased_time",
"define6 9 binhex dhcp_relay_msg",
"define6 11 embed auth",
"embed byte protocol",
"embed byte algorithm",
"embed byte rdm",
"embed binhex:8 replay",
"embed binhex information",
"define6 12 ip6address unicast",
"define6 13 norequest embed status_code",
"embed uint16 status_code",
"embed optional string message",
"define6 14 norequest flag rapid_commit",
"define6 15 binhex user_class",
"define6 16 binhex vivco",
"define6 17 embed vivso",
"embed uint32 enterprise_number",
"define6 18 binhex interface_id",
"define6 19 byte reconfigure_msg",
"define6 20 flag reconfigure_accept",
"define6 21 array domain sip_servers_names",
"define6 22 array ip6address sip_servers_addresses",
"define6 23 array ip6address name_servers",
"define6 24 array domain domain_search",
"define6 25 norequest index embed ia_pd",
"embed binhex:4 iaid",
"embed uint32 t1",
"embed uint32 t2",
"encap 26 option",
"define6 26 index embed prefix",
"embed uint32 pltime",
"embed uint32 vltime",
"embed byte length",
"embed ip6address prefix",
"encap 13 option",
"encap 67 option",
"define6 27 array ip6address nis_servers",
"define6 28 array ip6address nisp_servers",
"define6 29 string nis_domain_name",
"define6 30 string nisp_domain_name",
"define6 31 array ip6address sntp_servers",
"define6 32 uint32 info_refresh_time",
"define6 33 array domain bcms_server_d",
"define6 34 array ip6address bcms_server_a",
"define6 36 encap geoconf_civic",
"embed byte what",
"embed uint16 country_code",
"define6 37 embed remote_id",
"embed uint32 enterprise_number",
"embed binhex remote_id",
"define6 38 binhex subscriber_id",
"define6 39 embed fqdn",
"embed bitflags=00000NOS flags",
"embed optional domain fqdn",
"define6 40 array ip6address pana_agent",
"define6 41 string posix_timezone",
"define6 42 string tzdb_timezone",
"define6 43 array uint16 ero",
"define6 49 domain mip6_hnidf",
"define6 50 encap mip6_vdinf",
"encap 71 option",
"encap 72 option",
"encap 73 option",
"define6 51 domain lost_server",
"define6 52 array ip6address capwap_ac",
"define6 53 binhex relay_id",
"define6 54 encap mos_ip",
"encap 1 array ip6address is",
"encap 2 array ip6address cs",
"encap 3 array ip6address es",
"define6 55 encap mos_domain",
"encap 1 domain is",
"encap 2 domain cs",
"encap 3 domain es",
"define6 56 encap ntp_server",
"encap 1 ip6address addr",
"encap 2 ip6address mcast_addr",
"encap 3 domain fqdn",
"define6 57 domain access_domain",
"define6 58 array domain sip_ua_cs_list",
"define6 59 string bootfile_url",
"define6 60 binhex bootfile_param",
"define6 61 array uint16 architecture_types",
"define6 62 embed nii",
"embed byte type",
"embed byte major",
"embed byte minor",
"define6 63 binhex geoloc",
"define6 64 domain aftr_name",
"define6 67 embed pd_exclude",
"embed byte prefix_len",
"embed binhex subnetID",
"define6 69 encap mip6_idinf",
"encap 71 option",
"encap 72 option",
"encap 73 option",
"define6 70 encap mip6_udinf",
"encap 71 option",
"encap 72 option",
"encap 73 option",
"define6 71 embed mip6_hnp",
"embed byte prefix_len",
"embed ip6address prefix",
"define6 72 ip6address mip6_haa",
"define6 73 domain mip6_haf",
"define6 74 embed rdnss_selection",
"embed ip6address server",
"embed byte prf",
"embed array domain domains",
"define6 75 string krb_principal_name",
"define6 76 string krb_realm_name",
"define6 78 embed krb_kdc",
"embed uint16 priority",
"embed uint16 weight",
"embed byte transport_type",
"embed uint16 port",
"embed ip6address address",
"embed string realm_name",
"define6 80 ip6address link_address",
"define6 82 request uint32 sol_max_rt",
"define6 83 request uint32 inf_max_rt",
"define6 89 embed s46_rule",
"embed bitflags=0000000F flags",
"embed byte ea_len",
"embed byte prefix4_len",
"embed ipaddress ipv4_prefix",
"embed ip6address ipv6_prefix",
"define6 90 ip6address s64_br",
"define6 91 embed s46_dmr",
"embed byte prefix_len",
"embed binhex prefix",
"define6 92 embed s46_v4v6bind",
"embed ipaddress ipv4_address",
"embed byte ipv6_prefix_len",
"embed binhex ipv6_prefix_and_options",
"define6 93 embed s46_portparams",
"embed byte offset",
"embed byte psid_len",
"embed uint16 psid",
"define6 94 embed s46_cont_mape",
"encap 89 option",
"encap 90 option",
"define6 95 embed s46_cont_mapt",
"encap 89 option",
"encap 91 option",
"define6 96 embed s46_cont_lw",
"encap 90 option",
"encap 92 option",
"define6 112 string mudurl",
"define 1 request ipaddress subnet_mask\n"
"define 121 rfc3442 classless_static_routes\n"
"define 2 uint32 time_offset\n"
"define 3 request array ipaddress routers\n"
"define 4 array ipaddress time_servers\n"
"define 5 array ipaddress ien116_name_servers\n"
"define 6 array ipaddress domain_name_servers\n"
"define 7 array ipaddress log_servers\n"
"define 8 array ipaddress cookie_servers\n"
"define 9 array ipaddress lpr_servers\n"
"define 10 array ipaddress impress_servers\n"
"define 11 array ipaddress resource_location_servers\n"
"define 12 dname host_name\n"
"define 13 uint16 boot_size\n"
"define 14 string merit_dump\n"
"define 15 array dname domain_name\n"
"define 16 ipaddress swap_server\n"
"define 17 string root_path\n"
"define 18 string extensions_path\n"
"define 19 byte ip_forwarding\n"
"define 20 byte non_local_source_routing\n"
"define 21 array ipaddress policy_filter\n"
"define 22 uint16 max_dgram_reassembly\n"
"define 23 byte default_ip_ttl\n"
"define 24 uint32 path_mtu_aging_timeout\n"
"define 25 array uint16 path_mtu_plateau_table\n"
"define 26 uint16 interface_mtu\n"
"define 27 byte all_subnets_local\n"
"define 28 request ipaddress broadcast_address\n"
"define 29 byte perform_mask_discovery\n"
"define 30 byte mask_supplier\n"
"define 31 byte router_discovery\n"
"define 32 ipaddress router_solicitation_address\n"
"define 33 request array ipaddress static_routes\n"
"define 34 byte trailer_encapsulation\n"
"define 35 uint32 arp_cache_timeout\n"
"define 36 uint16 ieee802_3_encapsulation\n"
"define 37 byte default_tcp_ttl\n"
"define 38 uint32 tcp_keepalive_interval\n"
"define 39 byte tcp_keepalive_garbage\n"
"define 40 string nis_domain\n"
"define 41 array ipaddress nis_servers\n"
"define 42 array ipaddress ntp_servers\n"
"define 43 binhex vendor_encapsulated_options\n"
"define 44 array ipaddress netbios_name_servers\n"
"define 45 ipaddress netbios_dd_server\n"
"define 46 byte netbios_node_type\n"
"define 47 string netbios_scope\n"
"define 48 array ipaddress font_servers\n"
"define 49 array ipaddress x_display_manager\n"
"define 50 ipaddress dhcp_requested_address\n"
"define 51 request uint32 dhcp_lease_time\n"
"define 52 byte dhcp_option_overload\n"
"define 53 byte dhcp_message_type\n"
"define 54 ipaddress dhcp_server_identifier\n"
"define 55 array byte dhcp_parameter_request_list\n"
"define 56 string dhcp_message\n"
"define 57 uint16 dhcp_max_message_size\n"
"define 58 request uint32 dhcp_renewal_time\n"
"define 59 request uint32 dhcp_rebinding_time\n"
"define 60 string vendor_class_identifier\n"
"define 61 binhex dhcp_client_identifier\n"
"define 64 string nisplus_domain\n"
"define 65 array ipaddress nisplus_servers\n"
"define 66 dname tftp_server_name\n"
"define 67 string bootfile_name\n"
"define 68 array ipaddress mobile_ip_home_agent\n"
"define 69 array ipaddress smtp_server\n"
"define 70 array ipaddress pop_server\n"
"define 71 array ipaddress nntp_server\n"
"define 72 array ipaddress www_server\n"
"define 73 array ipaddress finger_server\n"
"define 74 array ipaddress irc_server\n"
"define 75 array ipaddress streettalk_server\n"
"define 76 array ipaddress streettalk_directory_assistance_server\n"
"define 77 binhex user_class\n"
"define 78 embed slp_agent\n"
"embed byte mandatory\n"
"embed array ipaddress address\n"
"define 79 embed slp_service\n"
"embed byte mandatory\n"
"embed ascii scope_list\n"
"define 80 norequest flag rapid_commit\n"
"define 81 embed fqdn\n"
"embed bitflags=0000NEOS flags\n"
"embed byte rcode1\n"
"embed byte rcode2\n"
"embed optional domain fqdn\n"
"define 83 embed isns\n"
"embed byte reserved1\n"
"embed bitflags=00000SAE functions\n"
"embed byte reserved2\n"
"embed bitflags=00fFsSCE dd\n"
"embed byte reserved3\n"
"embed bitflags=0000DMHE admin\n"
"embed uint16 reserved4\n"
"embed byte reserved5\n"
"embed bitflags=0TXPAMSE server_security\n"
"embed array ipaddress servers\n"
"define 85 array ipaddress nds_servers\n"
"define 86 raw nds_tree_name\n"
"define 87 raw nds_context\n"
"define 88 array domain bcms_controller_names\n"
"define 89 array ipaddress bcms_controller_address\n"
"define 90 embed auth\n"
"embed byte protocol\n"
"embed byte algorithm\n"
"embed byte rdm\n"
"embed binhex:8 replay\n"
"embed binhex information\n"
"define 91 uint32 client_last_transaction_time\n"
"define 92 array ipaddress associated_ip\n"
"define 98 string uap_servers\n"
"define 99 encap geoconf_civic\n"
"embed byte what\n"
"embed uint16 country_code\n"
"define 100 string posix_timezone\n"
"define 101 string tzdb_timezone\n"
"define 116 byte auto_configure\n"
"define 117 array uint16 name_service_search\n"
"define 118 ipaddress subnet_selection\n"
"define 119 array domain domain_search\n"
"define 120 rfc3361 sip_server\n"
"define 122 encap tsp\n"
"encap 1 ipaddress dhcp_server\n"
"encap 2 ipaddress dhcp_secondary_server\n"
"encap 3 rfc3361 provisioning_server\n"
"encap 4 embed as_req_as_rep_backoff\n"
"embed uint32 nominal\n"
"embed uint32 maximum\n"
"embed uint32 retry\n"
"encap 5 embed ap_req_ap_rep_backoff\n"
"embed uint32 nominal\n"
"embed uint32 maximum\n"
"embed uint32 retry\n"
"encap 6 domain kerberos_realm\n"
"encap 7 byte ticket_granting_server_utilization\n"
"encap 8 byte provisioning_timer\n"
"define 123 binhex geoconf\n"
"define 124 binhex vivco\n"
"define 125 embed vivso\n"
"embed uint32 enterprise_number\n"
"define 136 array ipaddress pana_agent\n"
"define 137 domain lost_server\n"
"define 138 array ipaddress capwap_ac\n"
"define 139 encap mos_ip\n"
"encap 1 array ipaddress is\n"
"encap 2 array ipaddress cs\n"
"encap 3 array ipaddress es\n"
"define 140 encap mos_domain\n"
"encap 1 domain is\n"
"encap 2 domain cs\n"
"encap 3 domain es\n"
"define 141 array domain sip_ua_cs_list\n"
"define 142 array ipaddress andsf\n"
"define 143 array ip6address andsf6\n"
"define 144 binhex geoloc\n"
"define 145 array byte forcerenew_nonce_capable\n"
"define 146 embed rdnss_selection\n"
"embed byte prf\n"
"embed ipaddress primary\n"
"embed ipaddress secondary\n"
"embed array domain domains\n"
"define 150 array ipaddress tftp_servers\n"
"define 161 string mudurl\n"
"define 208 binhex pxelinux_magic\n"
"define 209 string config_file\n"
"define 210 string path_prefix\n"
"define 211 uint32 reboot_time\n"
"define 212 embed sixrd\n"
"embed byte mask_len\n"
"embed byte prefix_len\n"
"embed ip6address prefix\n"
"embed array ipaddress brip_address\n"
"define 213 domain access_domain\n"
"define 221 encap vss\n"
"encap 0 string nvt\n"
"encap 1 binhex vpn_id\n"
"encap 255 flag global\n"
"define 249 rfc3442 ms_classless_static_routes\n"
"define 252 string wpad_url\n"
"definend 1 binhex source_address\n"
"definend 2 binhex target_address\n"
"definend 3 index embed prefix_information\n"
"embed byte length\n"
"embed bitflags=LA flags\n"
"embed uint32 vltime\n"
"embed uint32 pltime\n"
"embed uint32 reserved\n"
"embed array ip6address prefix\n"
"definend 5 embed mtu\n"
"embed uint16 reserved\n"
"embed uint32 mtu\n"
"definend 25 index embed rdnss\n"
"embed uint16 reserved\n"
"embed uint32 lifetime\n"
"embed array ip6address servers\n"
"definend 31 index embed dnssl\n"
"embed uint16 reserved\n"
"embed uint32 lifetime\n"
"embed domain search\n"
"define6 1 binhex client_id\n"
"define6 2 binhex server_id\n"
"define6 3 norequest index embed ia_na\n"
"embed binhex:4 iaid\n"
"embed uint32 t1\n"
"embed uint32 t2\n"
"encap 5 option\n"
"encap 13 option\n"
"define6 4 norequest index embed ia_ta\n"
"embed uint32 iaid\n"
"encap 5 option\n"
"encap 13 option\n"
"define6 5 norequest index embed ia_addr\n"
"embed ip6address ia_addr\n"
"embed uint32 pltime\n"
"embed uint32 vltime\n"
"encap 13 option\n"
"define6 6 array uint16 option_request\n"
"define6 7 byte preference\n"
"define6 8 uint16 elased_time\n"
"define6 9 binhex dhcp_relay_msg\n"
"define6 11 embed auth\n"
"embed byte protocol\n"
"embed byte algorithm\n"
"embed byte rdm\n"
"embed binhex:8 replay\n"
"embed binhex information\n"
"define6 12 ip6address unicast\n"
"define6 13 norequest embed status_code\n"
"embed uint16 status_code\n"
"embed optional string message\n"
"define6 14 norequest flag rapid_commit\n"
"define6 15 binhex user_class\n"
"define6 16 binhex vivco\n"
"define6 17 embed vivso\n"
"embed uint32 enterprise_number\n"
"define6 18 binhex interface_id\n"
"define6 19 byte reconfigure_msg\n"
"define6 20 flag reconfigure_accept\n"
"define6 21 array domain sip_servers_names\n"
"define6 22 array ip6address sip_servers_addresses\n"
"define6 23 array ip6address name_servers\n"
"define6 24 array domain domain_search\n"
"define6 25 norequest index embed ia_pd\n"
"embed binhex:4 iaid\n"
"embed uint32 t1\n"
"embed uint32 t2\n"
"encap 26 option\n"
"define6 26 index embed prefix\n"
"embed uint32 pltime\n"
"embed uint32 vltime\n"
"embed byte length\n"
"embed ip6address prefix\n"
"encap 13 option\n"
"encap 67 option\n"
"define6 27 array ip6address nis_servers\n"
"define6 28 array ip6address nisp_servers\n"
"define6 29 string nis_domain_name\n"
"define6 30 string nisp_domain_name\n"
"define6 31 array ip6address sntp_servers\n"
"define6 32 uint32 info_refresh_time\n"
"define6 33 array domain bcms_server_d\n"
"define6 34 array ip6address bcms_server_a\n"
"define6 36 encap geoconf_civic\n"
"embed byte what\n"
"embed uint16 country_code\n"
"define6 37 embed remote_id\n"
"embed uint32 enterprise_number\n"
"embed binhex remote_id\n"
"define6 38 binhex subscriber_id\n"
"define6 39 embed fqdn\n"
"embed bitflags=00000NOS flags\n"
"embed optional domain fqdn\n"
"define6 40 array ip6address pana_agent\n"
"define6 41 string posix_timezone\n"
"define6 42 string tzdb_timezone\n"
"define6 43 array uint16 ero\n"
"define6 49 domain mip6_hnidf\n"
"define6 50 encap mip6_vdinf\n"
"encap 71 option\n"
"encap 72 option\n"
"encap 73 option\n"
"define6 51 domain lost_server\n"
"define6 52 array ip6address capwap_ac\n"
"define6 53 binhex relay_id\n"
"define6 54 encap mos_ip\n"
"encap 1 array ip6address is\n"
"encap 2 array ip6address cs\n"
"encap 3 array ip6address es\n"
"define6 55 encap mos_domain\n"
"encap 1 domain is\n"
"encap 2 domain cs\n"
"encap 3 domain es\n"
"define6 56 encap ntp_server\n"
"encap 1 ip6address addr\n"
"encap 2 ip6address mcast_addr\n"
"encap 3 domain fqdn\n"
"define6 57 domain access_domain\n"
"define6 58 array domain sip_ua_cs_list\n"
"define6 59 string bootfile_url\n"
"define6 60 binhex bootfile_param\n"
"define6 61 array uint16 architecture_types\n"
"define6 62 embed nii\n"
"embed byte type\n"
"embed byte major\n"
"embed byte minor\n"
"define6 63 binhex geoloc\n"
"define6 64 domain aftr_name\n"
"define6 67 embed pd_exclude\n"
"embed byte prefix_len\n"
"embed binhex subnetID\n"
"define6 69 encap mip6_idinf\n"
"encap 71 option\n"
"encap 72 option\n"
"encap 73 option\n"
"define6 70 encap mip6_udinf\n"
"encap 71 option\n"
"encap 72 option\n"
"encap 73 option\n"
"define6 71 embed mip6_hnp\n"
"embed byte prefix_len\n"
"embed ip6address prefix\n"
"define6 72 ip6address mip6_haa\n"
"define6 73 domain mip6_haf\n"
"define6 74 embed rdnss_selection\n"
"embed ip6address server\n"
"embed byte prf\n"
"embed array domain domains\n"
"define6 75 string krb_principal_name\n"
"define6 76 string krb_realm_name\n"
"define6 78 embed krb_kdc\n"
"embed uint16 priority\n"
"embed uint16 weight\n"
"embed byte transport_type\n"
"embed uint16 port\n"
"embed ip6address address\n"
"embed string realm_name\n"
"define6 80 ip6address link_address\n"
"define6 82 request uint32 sol_max_rt\n"
"define6 83 request uint32 inf_max_rt\n"
"define6 89 embed s46_rule\n"
"embed bitflags=0000000F flags\n"
"embed byte ea_len\n"
"embed byte prefix4_len\n"
"embed ipaddress ipv4_prefix\n"
"embed ip6address ipv6_prefix\n"
"define6 90 ip6address s64_br\n"
"define6 91 embed s46_dmr\n"
"embed byte prefix_len\n"
"embed binhex prefix\n"
"define6 92 embed s46_v4v6bind\n"
"embed ipaddress ipv4_address\n"
"embed byte ipv6_prefix_len\n"
"embed binhex ipv6_prefix_and_options\n"
"define6 93 embed s46_portparams\n"
"embed byte offset\n"
"embed byte psid_len\n"
"embed uint16 psid\n"
"define6 94 embed s46_cont_mape\n"
"encap 89 option\n"
"encap 90 option\n"
"define6 95 embed s46_cont_mapt\n"
"encap 89 option\n"
"encap 91 option\n"
"define6 96 embed s46_cont_lw\n"
"encap 90 option\n"
"encap 92 option\n"
"define6 112 string mudurl\n"
#endif
NULL
};
"\0";

View File

@ -35,4 +35,4 @@
#define INITDEFINE6S 69
#endif
extern const char * const dhcpcd_embedded_conf[];
extern const char dhcpcd_embedded_conf[];

View File

@ -5,7 +5,7 @@
#controlgroup wheel
# Inform the DHCP server of our hostname for DDNS.
hostname
#hostname
# Use the hardware address of the interface for the Client ID.
#clientid
@ -18,20 +18,27 @@ duid
# Persist interface configuration when dhcpcd exits.
persistent
# Rapid commit support.
# Safe to enable by default because it requires the equivalent option set
# on the server to actually work.
option rapid_commit
# vendorclassid is set to blank to avoid sending the default of
# dhcpcd-<version>:<os>:<machine>:<platform>
vendorclassid
# A list of options to request from the DHCP server.
option domain_name_servers, domain_name, domain_search, host_name
option domain_name_servers, domain_name, domain_search
option classless_static_routes
# Respect the network MTU. This is applied to DHCP routes.
option interface_mtu
# Request a hostname from the network
option host_name
# Most distributions have NTP support.
#option ntp_servers
# Rapid commit support.
# Safe to enable by default because it requires the equivalent option set
# on the server to actually work.
option rapid_commit
# A ServerID is required by RFC2131.
require dhcp_server_identifier

View File

@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd April 19, 2020
.Dd May 12, 2020
.Dt DHCPCD.CONF 5
.Os
.Sh NAME
@ -792,7 +792,7 @@ with a name of
exported to
.Xr dhcpcd-run-hooks 8 ,
with a prefix of
.Va _nd .
.Va nd_ .
.It Ic define6 Ar code Ar type Ar variable
Defines the DHCPv6 option
.Ar code
@ -803,7 +803,7 @@ with a name of
exported to
.Xr dhcpcd-run-hooks 8 ,
with a prefix of
.Va _dhcp6 .
.Va dhcp6_ .
.It Ic vendopt Ar code Ar type Ar variable
Defines the Vendor-Identifying Vendor Options.
The

View File

@ -82,7 +82,7 @@ struct interface {
unsigned int index;
unsigned int active;
unsigned int flags;
sa_family_t family;
uint16_t hwtype; /* ARPHRD_ETHER for example */
unsigned char hwaddr[HWADDR_LEN];
uint8_t hwlen;
unsigned short vlanid;
@ -125,6 +125,7 @@ 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 */
const char *cffile;
unsigned long long options;
@ -163,6 +164,7 @@ struct dhcpcd_ctx {
#endif
struct eloop *eloop;
char *script;
#ifdef HAVE_OPEN_MEMSTREAM
FILE *script_fp;
#endif
@ -205,7 +207,8 @@ struct dhcpcd_ctx {
struct dhcp_opt *dhcp_opts;
size_t dhcp_opts_len;
int udp_fd;
int udp_rfd;
int udp_wfd;
/* Our aggregate option buffer.
* We ONLY use this when options are split, which for most purposes is
@ -222,11 +225,11 @@ struct dhcpcd_ctx {
#endif
struct ra_head *ra_routers;
int dhcp6_fd;
struct dhcp_opt *nd_opts;
size_t nd_opts_len;
#ifdef DHCP6
int dhcp6_rfd;
int dhcp6_wfd;
struct dhcp_opt *dhcp6_opts;
size_t dhcp6_opts_len;
#endif
@ -247,8 +250,12 @@ struct dhcpcd_ctx {
#ifdef USE_SIGNALS
extern const int dhcpcd_signals[];
extern const size_t dhcpcd_signals_len;
extern const int dhcpcd_signals_ignore[];
extern const size_t dhcpcd_signals_ignore_len;
#endif
extern const char *dhcpcd_default_script;
int dhcpcd_ifafwaiting(const struct interface *);
int dhcpcd_afwaiting(const struct dhcpcd_ctx *);
void dhcpcd_daemonise(struct dhcpcd_ctx *);
@ -257,8 +264,7 @@ void dhcpcd_linkoverflow(struct dhcpcd_ctx *);
int dhcpcd_handleargs(struct dhcpcd_ctx *, struct fd_list *, int, char **);
void dhcpcd_handlecarrier(struct dhcpcd_ctx *, int, unsigned int, const char *);
int dhcpcd_handleinterface(void *, int, const char *);
void dhcpcd_handlehwaddr(struct dhcpcd_ctx *, const char *,
const void *, uint8_t);
void dhcpcd_handlehwaddr(struct interface *, uint16_t, const void *, uint8_t);
void dhcpcd_dropinterface(struct interface *, const char *);
int dhcpcd_selectprofile(struct interface *, const char *);

View File

@ -130,7 +130,7 @@ duid_make(void *d, const struct interface *ifp, uint16_t type)
u16 = htons(type);
memcpy(p, &u16, sizeof(u16));
p += sizeof(u16);
u16 = htons(ifp->family);
u16 = htons(ifp->hwtype);
memcpy(p, &u16, sizeof(u16));
p += sizeof(u16);
if (type == DUID_LLT) {
@ -149,20 +149,18 @@ duid_make(void *d, const struct interface *ifp, uint16_t type)
#define DUID_STRLEN DUID_LEN * 3
static size_t
duid_get(uint8_t **d, const struct interface *ifp)
duid_get(struct dhcpcd_ctx *ctx, const struct interface *ifp)
{
FILE *fp;
uint8_t *data;
size_t len;
int x = 0;
size_t len, slen;
char line[DUID_STRLEN];
const struct interface *ifp2;
/* If we already have a DUID then use it as it's never supposed
* to change once we have one even if the interfaces do */
if ((len = read_hwaddr_aton(&data, DUID)) != 0) {
if ((len = dhcp_read_hwaddr_aton(ctx, &data, DUID)) != 0) {
if (len <= DUID_LEN) {
*d = data;
ctx->duid = data;
return len;
}
logerrx("DUID too big (max %u): %s", DUID_LEN, DUID);
@ -176,13 +174,18 @@ duid_get(uint8_t **d, const struct interface *ifp)
}
}
/* Regardless of what happens we will create a DUID to use. */
*d = data;
/* No file? OK, lets make one based the machines UUID */
len = duid_make_uuid(data);
if (len > 0)
if (ifp == NULL) {
len = duid_make_uuid(data);
if (len == 0)
free(data);
else
ctx->duid = data;
return len;
}
/* Regardless of what happens we will create a DUID to use. */
ctx->duid = data;
/* No UUID? OK, lets make one based on our interface */
if (ifp->hwlen == 0) {
@ -202,27 +205,25 @@ duid_get(uint8_t **d, const struct interface *ifp)
}
}
if (!(fp = fopen(DUID, "w"))) {
logerr("%s", DUID);
return duid_make(data, ifp, DUID_LL);
}
len = duid_make(data, ifp, DUID_LLT);
x = fprintf(fp, "%s\n", hwaddr_ntoa(data, len, line, sizeof(line)));
if (fclose(fp) == EOF)
x = -1;
/* Failed to write the duid? scrub it, we cannot use it */
if (x < 1) {
logerr("%s", DUID);
unlink(DUID);
hwaddr_ntoa(data, len, line, sizeof(line));
slen = strlen(line);
if (slen < sizeof(line) - 2) {
line[slen++] = '\n';
line[slen] = '\0';
}
if (dhcp_writefile(ctx, DUID, 0640, line, slen) == -1) {
logerr("%s: cannot write duid", __func__);
return duid_make(data, ifp, DUID_LL);
}
return len;
}
size_t duid_init(const struct interface *ifp)
size_t
duid_init(struct dhcpcd_ctx *ctx, const struct interface *ifp)
{
if (ifp->ctx->duid == NULL)
ifp->ctx->duid_len = duid_get(&ifp->ctx->duid, ifp);
return ifp->ctx->duid_len;
if (ctx->duid == NULL)
ctx->duid_len = duid_get(ctx, ifp);
return ctx->duid_len;
}

View File

@ -35,6 +35,6 @@
#define DUID_UUID 4
size_t duid_make(void *, const struct interface *, uint16_t);
size_t duid_init(const struct interface *);
size_t duid_init(struct dhcpcd_ctx *, const struct interface *);
#endif

View File

@ -1023,12 +1023,13 @@ eloop_start(struct eloop *eloop, sigset_t *signals)
continue;
}
eloop_reduce_timers(eloop);
t = TAILQ_FIRST(&eloop->timeouts);
if (t == NULL && eloop->events_len == 0)
break;
if (t != NULL)
eloop_reduce_timers(eloop);
if (t != NULL && t->seconds == 0 && t->nseconds == 0) {
TAILQ_REMOVE(&eloop->timeouts, t, next);
t->callback(t->arg);

View File

@ -120,6 +120,7 @@
#define DHCPCD_ONESHOT (1ULL << 60)
#define DHCPCD_INACTIVE (1ULL << 61)
#define DHCPCD_SLAACTEMP (1ULL << 62)
#define DHCPCD_PRIVSEPROOT (1ULL << 63)
#define DHCPCD_NODROP (DHCPCD_EXITING | DHCPCD_PERSISTENT)
@ -128,6 +129,58 @@
#define DHCPCD_WARNINGS (DHCPCD_CSR_WARNED | \
DHCPCD_ROUTER_HOST_ROUTE_WARNED)
/* These options only make sense in the config file, so don't use any
valid short options for them */
#define O_BASE MAX('z', 'Z') + 1
#define O_ARPING O_BASE + 1
#define O_FALLBACK O_BASE + 2
#define O_DESTINATION O_BASE + 3
#define O_IPV6RS O_BASE + 4
#define O_NOIPV6RS O_BASE + 5
#define O_IPV6RA_FORK O_BASE + 6
#define O_LINK_RCVBUF O_BASE + 7
#define O_ANONYMOUS O_BASE + 8
#define O_NOALIAS O_BASE + 9
#define O_IA_NA O_BASE + 10
#define O_IA_TA O_BASE + 11
#define O_IA_PD O_BASE + 12
#define O_HOSTNAME_SHORT O_BASE + 13
#define O_DEV O_BASE + 14
#define O_NODEV O_BASE + 15
#define O_NOIPV4 O_BASE + 16
#define O_NOIPV6 O_BASE + 17
#define O_IAID O_BASE + 18
#define O_DEFINE O_BASE + 19
#define O_DEFINE6 O_BASE + 20
#define O_EMBED O_BASE + 21
#define O_ENCAP O_BASE + 22
#define O_VENDOPT O_BASE + 23
#define O_VENDCLASS O_BASE + 24
#define O_AUTHPROTOCOL O_BASE + 25
#define O_AUTHTOKEN O_BASE + 26
#define O_AUTHNOTREQUIRED O_BASE + 27
#define O_NODHCP O_BASE + 28
#define O_NODHCP6 O_BASE + 29
#define O_DHCP O_BASE + 30
#define O_DHCP6 O_BASE + 31
#define O_IPV4 O_BASE + 32
#define O_IPV6 O_BASE + 33
#define O_CONTROLGRP O_BASE + 34
#define O_SLAAC O_BASE + 35
#define O_GATEWAY O_BASE + 36
#define O_NOUP O_BASE + 37
#define O_IPV6RA_AUTOCONF O_BASE + 38
#define O_IPV6RA_NOAUTOCONF O_BASE + 39
#define O_REJECT O_BASE + 40
#define O_BOOTP O_BASE + 42
#define O_DEFINEND O_BASE + 43
#define O_NODELAY O_BASE + 44
#define O_INFORM6 O_BASE + 45
#define O_LASTLEASE_EXTEND O_BASE + 46
#define O_INACTIVE O_BASE + 47
#define O_MUDURL O_BASE + 48
#define O_MSUSERCLASS O_BASE + 49
extern const struct option cf_options[];
struct if_sla {
@ -190,7 +243,6 @@ struct if_options {
char **config;
char **environ;
char *script;
char hostname[HOSTNAME_MAX_LEN + 1]; /* We don't store the length */
uint8_t fqdn;

View File

@ -75,12 +75,6 @@
#include "logerr.h"
#include "privsep.h"
#ifdef __sun
/* It has the ioctl, but the member is missing from the struct?
* No matter, our getifaddrs foo in if-sun.c will DTRT. */
#undef SIOCGIFHWADDR
#endif
void
if_free(struct interface *ifp)
{
@ -387,10 +381,10 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
struct if_laddrreq iflr = { .flags = IFLR_PREFIX };
int link_fd;
#endif
#elif AF_PACKET
#elif defined(AF_PACKET)
const struct sockaddr_ll *sll;
#endif
#if defined(SIOCGIFPRIORITY) || defined(SIOCGIFHWADDR)
#if defined(SIOCGIFPRIORITY)
struct ifreq ifr;
#endif
@ -398,12 +392,22 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
logerr(__func__);
return NULL;
}
TAILQ_INIT(ifs);
#if defined(PRIVSEP) && defined(HAVE_CAPSICUM)
if (ctx->options & DHCPCD_PRIVSEP) {
if (ps_root_getifaddrs(ctx, ifaddrs) == -1) {
logerr("ps_root_getifaddrs");
free(ifs);
return NULL;
}
} else
#endif
if (getifaddrs(ifaddrs) == -1) {
logerr(__func__);
logerr("getifaddrs");
free(ifs);
return NULL;
}
TAILQ_INIT(ifs);
#ifdef IFLR_ACTIVE
link_fd = xsocket(PF_LINK, SOCK_DGRAM | SOCK_CLOEXEC, 0);
@ -419,7 +423,7 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
#ifdef AF_LINK
if (ifa->ifa_addr->sa_family != AF_LINK)
continue;
#elif AF_PACKET
#elif defined(AF_PACKET)
if (ifa->ifa_addr->sa_family != AF_PACKET)
continue;
#endif
@ -485,13 +489,9 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
if_noconf = ((argc == 0 || argc == -1) && ctx->ifac == 0 &&
!if_hasconf(ctx, spec.devname));
/* Don't allow loopback or pointopoint unless explicit.
* Don't allow some reserved interface names unless explicit. */
if (if_noconf) {
if (ifa->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT) ||
if_ignore(ctx, spec.devname))
active = IF_INACTIVE;
}
/* Don't allow some reserved interface names unless explicit. */
if (if_noconf && if_ignore(ctx, spec.devname))
active = IF_INACTIVE;
ifp = calloc(1, sizeof(*ifp));
if (ifp == NULL) {
@ -533,6 +533,7 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
#ifdef IFT_TUNNEL
case IFT_TUNNEL: /* FALLTHROUGH */
#endif
case IFT_LOOP: /* FALLTHROUGH */
case IFT_PPP:
/* Don't allow unless explicit */
if (if_noconf) {
@ -551,16 +552,16 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
case IFT_L3IPVLAN: /* FALLTHROUGH */
#endif
case IFT_ETHER:
ifp->family = ARPHRD_ETHER;
ifp->hwtype = ARPHRD_ETHER;
break;
#ifdef IFT_IEEE1394
case IFT_IEEE1394:
ifp->family = ARPHRD_IEEE1394;
ifp->hwtype = ARPHRD_IEEE1394;
break;
#endif
#ifdef IFT_INFINIBAND
case IFT_INFINIBAND:
ifp->family = ARPHRD_INFINIBAND;
ifp->hwtype = ARPHRD_INFINIBAND;
break;
#endif
default:
@ -572,71 +573,43 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
" interface type 0x%.2x",
ifp->name, sdl->sdl_type);
/* Pretend it's ethernet */
ifp->family = ARPHRD_ETHER;
ifp->hwtype = ARPHRD_ETHER;
break;
}
ifp->hwlen = sdl->sdl_alen;
memcpy(ifp->hwaddr, CLLADDR(sdl), ifp->hwlen);
#elif AF_PACKET
#elif defined(AF_PACKET)
sll = (const void *)ifa->ifa_addr;
ifp->index = (unsigned int)sll->sll_ifindex;
ifp->family = sll->sll_hatype;
ifp->hwtype = sll->sll_hatype;
ifp->hwlen = sll->sll_halen;
if (ifp->hwlen != 0)
memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen);
#endif
}
#ifdef SIOCGIFHWADDR
else {
/* This is a huge bug in getifaddrs(3) as there
* is no reason why this can't be returned in
* ifa_addr. */
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifa->ifa_name,
sizeof(ifr.ifr_name));
if (ioctl(ctx->pf_inet_fd, SIOCGIFHWADDR, &ifr) == -1)
logerr("%s: SIOCGIFHWADDR", ifa->ifa_name);
ifp->family = ifr.ifr_hwaddr.sa_family;
if (ioctl(ctx->pf_inet_fd, SIOCGIFINDEX, &ifr) == -1)
logerr("%s: SIOCGIFINDEX", ifa->ifa_name);
ifp->index = (unsigned int)ifr.ifr_ifindex;
}
#endif
/* Ensure hardware address is valid. */
if (!if_valid_hwaddr(ifp->hwaddr, ifp->hwlen))
ifp->hwlen = 0;
/* We only work on ethernet by default */
if (ifp->family != ARPHRD_ETHER) {
if ((argc == 0 || argc == -1) &&
ctx->ifac == 0 && !if_hasconf(ctx, ifp->name))
active = IF_INACTIVE;
switch (ifp->family) {
case ARPHRD_IEEE1394:
case ARPHRD_INFINIBAND:
#ifdef ARPHRD_LOOPBACK
case ARPHRD_LOOPBACK:
#endif
#ifdef ARPHRD_PPP
case ARPHRD_PPP:
#endif
#ifdef ARPHRD_NONE
case ARPHRD_NONE:
#endif
/* We don't warn for supported families */
switch(ifp->hwtype) {
case ARPHRD_ETHER: /* FALLTHROUGH */
case ARPHRD_IEEE1394: /* FALLTHROUGH */
case ARPHRD_INFINIBAND: /* FALLTHROUGH */
case ARPHRD_NONE: /* FALLTHROUGH */
break;
case ARPHRD_LOOPBACK:
case ARPHRD_PPP:
if (if_noconf) {
logdebugx("%s: ignoring due to"
" interface type and"
" no config",
ifp->name);
active = IF_INACTIVE;
}
break;
/* IFT already checked */
#ifndef AF_LINK
default:
if (active)
logwarnx("%s: unsupported"
" interface family 0x%.2x",
ifp->name, ifp->family);
" interface type 0x%.2x",
ifp->name, ifp->hwtype);
break;
#endif
}
#endif
}
if (!(ctx->options & (DHCPCD_DUMPLEASE | DHCPCD_TEST))) {
@ -654,7 +627,7 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
/* Respect the interface priority */
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
if (ioctl(ctx->pf_inet_fd, SIOCGIFPRIORITY, &ifr) == 0)
if (pioctl(ctx, SIOCGIFPRIORITY, &ifr, sizeof(ifr)) == 0)
ifp->metric = (unsigned int)ifr.ifr_metric;
if_getssid(ifp);
#else
@ -713,22 +686,39 @@ if_nametospec(const char *ifname, struct if_spec *spec)
errno = e;
return -1;
}
*ep-- = '\0';
*ep = '\0';
#ifdef __sun
ep--;
#endif
} else {
spec->lun = -1;
#ifdef __sun
ep = spec->drvname + strlen(spec->drvname) - 1;
#endif
}
strlcpy(spec->devname, spec->drvname, sizeof(spec->devname));
#ifdef __sun
/* Solaris has numbers in the driver name, such as e1000g */
while (ep > spec->drvname && isdigit((int)*ep))
ep--;
if (*ep++ == ':') {
errno = EINVAL;
return -1;
}
#else
/* BSD and Linux no not have numbers in the driver name */
for (ep = spec->drvname; *ep != '\0' && !isdigit((int)*ep); ep++) {
if (*ep == ':') {
errno = EINVAL;
return -1;
}
}
#endif
spec->ppa = (int)strtoi(ep, &pp, 10, 0, INT_MAX, &e);
*ep = '\0';
#ifndef __sun
/*
* . is used for VLAN style names
* i is used on NetBSD for xvif interfaces
@ -738,6 +728,7 @@ if_nametospec(const char *ifname, struct if_spec *spec)
if (e)
spec->vlid = -1;
} else
#endif
spec->vlid = -1;
return 0;
@ -808,7 +799,8 @@ if_domtu(const struct interface *ifp, short int mtu)
if (mtu != 0)
r = if_ioctl(ifp->ctx, SIOCSIFMTU, &ifr, sizeof(ifr));
else
r = ioctl(ifp->ctx->pf_inet_fd, SIOCGIFMTU, &ifr);
r = pioctl(ifp->ctx, SIOCGIFMTU, &ifr, sizeof(ifr));
if (r == -1)
return -1;
return ifr.ifr_mtu;
@ -910,9 +902,6 @@ xsocket(int domain, int type, int protocol)
#if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK)
int xflags, xtype = type;
#endif
#ifdef SO_RERROR
int on;
#endif
#ifndef HAVE_SOCK_CLOEXEC
if (xtype & SOCK_CLOEXEC)
@ -937,13 +926,6 @@ xsocket(int domain, int type, int protocol)
goto out;
#endif
#ifdef SO_RERROR
/* Tell recvmsg(2) to return ENOBUFS if the receiving socket overflows. */
on = 1;
if (setsockopt(s, SOL_SOCKET, SO_RERROR, &on, sizeof(on)) == -1)
logerr("%s: SO_RERROR", __func__);
#endif
return s;
#if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK)

View File

@ -95,6 +95,8 @@ typedef unsigned long ioctl_request_t;
#define FRAMEHDRLEN_MAX 14 /* only ethernet support */
#define FRAMELEN_MAX (FRAMEHDRLEN_MAX + 9216)
#define UDPLEN_MAX 64 * 1024
/* Work out if we have a private address or not
* 10/8
* 172.16/12
@ -117,6 +119,11 @@ typedef unsigned long ioctl_request_t;
* but then ignores it. */
#undef RTF_CLONING
/* This interface is busted on DilOS at least.
* It used to work, but lukily Solaris can fall back to
* IP_PKTINFO. */
#undef IP_RECVIF
/* Solaris getifaddrs is very un-suitable for dhcpcd.
* See if-sun.c for details why. */
struct ifaddrs;
@ -126,6 +133,11 @@ int if_getsubnet(struct dhcpcd_ctx *, const char *, int, void *, size_t);
#endif
int if_ioctl(struct dhcpcd_ctx *, ioctl_request_t, void *, size_t);
#ifdef HAVE_PLEDGE
#define pioctl(ctx, req, data, len) if_ioctl((ctx), (req), (data), (len))
#else
#define pioctl(ctx, req, data, len) ioctl((ctx)->pf_inet_fd, (req),(data),(len))
#endif
int if_getflags(struct interface *);
int if_setflag(struct interface *, short, short);
#define if_up(ifp) if_setflag((ifp), (IFF_UP | IFF_RUNNING), 0)
@ -171,7 +183,7 @@ int if_conf(struct interface *);
int if_init(struct interface *);
int if_getssid(struct interface *);
bool if_ignore(struct dhcpcd_ctx *, const char *);
int if_vimaster(const struct dhcpcd_ctx *ctx, const char *);
int if_vimaster(struct dhcpcd_ctx *ctx, const char *);
unsigned short if_vlanid(const struct interface *);
int if_opensockets(struct dhcpcd_ctx *);
int if_opensockets_os(struct dhcpcd_ctx *);
@ -203,6 +215,9 @@ int if_setmac(struct interface *ifp, void *, uint8_t);
#else
# define SOCK_NONBLOCK 0x20000000
#endif
#ifndef SOCK_CXNB
#define SOCK_CXNB SOCK_CLOEXEC | SOCK_NONBLOCK
#endif
int if_route(unsigned char, const struct rt *rt);
int if_initrt(struct dhcpcd_ctx *, rb_tree_t *, int);
@ -241,7 +256,7 @@ struct interface *if_findifpfromcmsg(struct dhcpcd_ctx *,
int xsocket(int, int, int);
#ifdef __linux__
int if_linksocket(struct sockaddr_nl *, int);
int if_linksocket(struct sockaddr_nl *, int, int);
int if_getnetlink(struct dhcpcd_ctx *, struct iovec *, int, int,
int (*)(struct dhcpcd_ctx *, void *, struct nlmsghdr *), void *);
#endif

View File

@ -565,8 +565,6 @@ ipv4_getstate(struct interface *ifp)
return NULL;
}
TAILQ_INIT(&state->addrs);
state->buffer_size = state->buffer_len = state->buffer_pos = 0;
state->buffer = NULL;
}
return state;
}
@ -963,6 +961,5 @@ ipv4_free(struct interface *ifp)
TAILQ_REMOVE(&state->addrs, ia, next);
free(ia);
}
free(state->buffer);
free(state);
}

View File

@ -110,10 +110,6 @@ TAILQ_HEAD(ipv4_addrhead, ipv4_addr);
struct ipv4_state {
struct ipv4_addrhead addrs;
/* Buffer for BPF */
size_t buffer_size, buffer_len, buffer_pos;
char *buffer;
};
#define IPV4_STATE(ifp) \

View File

@ -57,12 +57,10 @@ static const struct in_addr inaddr_llbcast = {
.s_addr = HTONL(LINKLOCAL_BCAST)
};
static void ipv4ll_start1(struct interface *, struct arp_state *);
static in_addr_t
static void
ipv4ll_pickaddr(struct interface *ifp)
{
struct in_addr addr;
struct in_addr addr = { .s_addr = 0 };
struct ipv4ll_state *state;
state = IPV4LL_STATE(ifp);
@ -88,7 +86,7 @@ again:
/* Restore the original random state */
setstate(ifp->ctx->randomstate);
return addr.s_addr;
state->pickedaddr = addr;
}
int
@ -176,13 +174,12 @@ ipv4ll_announced_arp(struct arp_state *astate)
struct ipv4ll_state *state = IPV4LL_STATE(astate->iface);
state->conflicts = 0;
#ifdef KERNEL_RFC5227
arp_free(astate);
#endif
}
#ifndef KERNEL_RFC5227
/* This is the callback by ARP freeing */
static void
ipv4ll_arpfree(struct arp_state *astate)
ipv4ll_free_arp(struct arp_state *astate)
{
struct ipv4ll_state *state;
@ -191,23 +188,33 @@ ipv4ll_arpfree(struct arp_state *astate)
state->arp = NULL;
}
/* This is us freeing any ARP state */
static void
ipv4ll_freearp(struct interface *ifp)
{
struct ipv4ll_state *state;
state = IPV4LL_STATE(ifp);
if (state == NULL || state->arp == NULL)
return;
eloop_timeout_delete(ifp->ctx->eloop, NULL, state->arp);
arp_free(state->arp);
state->arp = NULL;
}
#else
#define ipv4ll_freearp(ifp)
#endif
static void
ipv4ll_not_found(struct interface *ifp)
{
struct ipv4ll_state *state;
struct ipv4_addr *ia;
#ifdef KERNEL_RFC5227
struct arp_state *astate;
bool new_addr;
#endif
state = IPV4LL_STATE(ifp);
assert(state != NULL);
ia = ipv4_iffindaddr(ifp, &state->pickedaddr, &inaddr_llmask);
#ifdef KERNEL_RFC5227
new_addr = ia == NULL;
#endif
#ifdef IN_IFF_NOTREADY
if (ia == NULL || ia->addr_flags & IN_IFF_NOTREADY)
#endif
@ -227,6 +234,7 @@ ipv4ll_not_found(struct interface *ifp)
return;
logdebugx("%s: DAD completed for %s", ifp->name, ia->saddr);
#endif
test:
state->addr = ia;
state->down = false;
@ -236,49 +244,27 @@ test:
return;
}
rt_build(ifp->ctx, AF_INET);
#ifdef KERNEL_RFC5227
if (!new_addr) {
astate = arp_new(ifp, &ia->addr);
if (ifp->ctx->options & DHCPCD_FORKED)
return;
if (astate != NULL) {
astate->announced_cb = ipv4ll_announced_arp;
astate->free_cb = ipv4ll_arpfree;
arp_announce(astate);
}
}
#else
arp_announce(state->arp);
#endif
astate = arp_announceaddr(ifp->ctx, &ia->addr);
if (astate != NULL)
astate->announced_cb = ipv4ll_announced_arp;
script_runreason(ifp, "IPV4LL");
dhcpcd_daemonise(ifp->ctx);
}
static void
ipv4ll_startifp(void *arg)
{
struct interface *ifp = arg;
struct ipv4ll_state *state;
state = IPV4LL_STATE(ifp);
ipv4ll_start1(ifp, state->arp);
}
static void
ipv4ll_found(struct interface *ifp)
{
struct ipv4ll_state *state = IPV4LL_STATE(ifp);
if (state->arp != NULL)
arp_cancel(state->arp);
ipv4ll_freearp(ifp);
if (++state->conflicts == MAX_CONFLICTS)
logerrx("%s: failed to acquire an IPv4LL address",
ifp->name);
state->pickedaddr.s_addr = ipv4ll_pickaddr(ifp);
ipv4ll_pickaddr(ifp);
eloop_timeout_add_sec(ifp->ctx->eloop,
state->conflicts >= MAX_CONFLICTS ?
RATE_LIMIT_INTERVAL : PROBE_WAIT,
ipv4ll_startifp, ifp);
ipv4ll_start, ifp);
}
static void
@ -286,62 +272,49 @@ ipv4ll_defend_failed(struct interface *ifp)
{
struct ipv4ll_state *state = IPV4LL_STATE(ifp);
if (state->arp != NULL)
arp_cancel(state->arp);
ipv4ll_freearp(ifp);
ipv4_deladdr(state->addr, 1);
state->down = true;
state->addr = NULL;
rt_build(ifp->ctx, AF_INET);
script_runreason(ifp, "IPV4LL");
state->pickedaddr.s_addr = ipv4ll_pickaddr(ifp);
ipv4ll_start1(ifp, state->arp);
ipv4ll_pickaddr(ifp);
ipv4ll_start(ifp);
}
#ifndef KERNEL_RFC5227
static void
ipv4ll_not_found_arp(struct arp_state *astate)
{
struct interface *ifp;
struct ipv4ll_state *state;
assert(astate != NULL);
assert(astate->iface != NULL);
ifp = astate->iface;
state = IPV4LL_STATE(ifp);
assert(state != NULL);
assert(state->arp == astate);
ipv4ll_not_found(ifp);
ipv4ll_not_found(astate->iface);
}
static void
ipv4ll_found_arp(struct arp_state *astate, __unused const struct arp_msg *amsg)
{
struct interface *ifp = astate->iface;
struct ipv4ll_state *state = IPV4LL_STATE(ifp);
assert(state->arp == astate);
ipv4ll_found(ifp);
ipv4ll_found(astate->iface);
}
static void
ipv4ll_defend_failed_arp(struct arp_state *astate)
{
struct ipv4ll_state *state = IPV4LL_STATE(astate->iface);
assert(state->arp == astate);
ipv4ll_defend_failed(astate->iface);
}
#endif
static void
ipv4ll_start1(struct interface *ifp, struct arp_state *astate)
void
ipv4ll_start(void *arg)
{
struct interface *ifp = arg;
struct ipv4ll_state *state;
struct ipv4_addr *ia;
bool repick;
#ifndef KERNEL_RFC5227
struct arp_state *astate;
#endif
assert(ifp != NULL);
if ((state = IPV4LL_STATE(ifp)) == NULL) {
ifp->if_data[IF_DATA_IPV4LL] = calloc(1, sizeof(*state));
if ((state = IPV4LL_STATE(ifp)) == NULL) {
@ -377,26 +350,6 @@ ipv4ll_start1(struct interface *ifp, struct arp_state *astate)
state->seeded = true;
}
#ifndef KERNEL_RFC5227
if (astate == NULL) {
if (state->arp != NULL)
return;
if ((astate = arp_new(ifp, NULL)) == NULL)
return;
astate->found_cb = ipv4ll_found_arp;
astate->not_found_cb = ipv4ll_not_found_arp;
astate->announced_cb = ipv4ll_announced_arp;
astate->defend_failed_cb = ipv4ll_defend_failed_arp;
astate->free_cb = ipv4ll_arpfree;
state->arp = astate;
} else
assert(state->arp == astate);
#else
UNUSED(astate);
#endif
state->down = true;
/* Find the previosuly used address. */
if (state->pickedaddr.s_addr != INADDR_ANY)
ia = ipv4_iffindaddr(ifp, &state->pickedaddr, NULL);
@ -418,11 +371,9 @@ ipv4ll_start1(struct interface *ifp, struct arp_state *astate)
#endif
state->addr = ia;
state->down = true;
if (ia != NULL) {
state->pickedaddr = ia->addr;
#ifndef KERNEL_RFC5227
astate->addr = ia->addr;
#endif
#ifdef IN_IFF_TENTATIVE
if (ia->addr_flags & (IN_IFF_TENTATIVE | IN_IFF_DETACHED)) {
loginfox("%s: waiting for DAD to complete on %s",
@ -433,41 +384,27 @@ ipv4ll_start1(struct interface *ifp, struct arp_state *astate)
#ifdef IN_IFF_DUPLICATED
loginfox("%s: using IPv4LL address %s", ifp->name, ia->saddr);
#endif
ipv4ll_not_found(ifp);
return;
} else {
loginfox("%s: probing for an IPv4LL address", ifp->name);
if (repick || state->pickedaddr.s_addr == INADDR_ANY)
ipv4ll_pickaddr(ifp);
}
loginfox("%s: probing for an IPv4LL address", ifp->name);
if (repick || state->pickedaddr.s_addr == INADDR_ANY)
state->pickedaddr.s_addr = ipv4ll_pickaddr(ifp);
#ifndef KERNEL_RFC5227
astate->addr = state->pickedaddr;
#endif
#ifdef IN_IFF_DUPLICATED
#ifdef KERNEL_RFC5227
ipv4ll_not_found(ifp);
#else
arp_probe(astate);
#endif
}
void
ipv4ll_start(void *arg)
{
ipv4ll_start1(arg, NULL);
}
static void
ipv4ll_freearp(struct interface *ifp)
{
struct ipv4ll_state *state;
state = IPV4LL_STATE(ifp);
if (state == NULL || state->arp == NULL)
ipv4ll_freearp(ifp);
state->arp = astate = arp_new(ifp, &state->pickedaddr);
if (state->arp == NULL)
return;
eloop_timeout_delete(ifp->ctx->eloop, NULL, state->arp);
arp_free(state->arp);
astate->found_cb = ipv4ll_found_arp;
astate->not_found_cb = ipv4ll_not_found_arp;
astate->announced_cb = ipv4ll_announced_arp;
astate->defend_failed_cb = ipv4ll_defend_failed_arp;
astate->free_cb = ipv4ll_free_arp;
arp_probe(astate);
#endif
}
void
@ -516,6 +453,7 @@ ipv4ll_reset(struct interface *ifp)
if (state == NULL)
return;
ipv4ll_freearp(ifp);
state->pickedaddr.s_addr = INADDR_ANY;
state->seeded = false;
}
@ -587,9 +525,7 @@ ipv4ll_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid)
ipv4ll_not_found(ifp);
else if (ia->addr_flags & IN_IFF_DUPLICATED) {
logerrx("%s: DAD detected %s", ifp->name, ia->saddr);
#ifdef KERNEL_RFC5227
arp_freeaddr(ifp, &ia->addr);
#endif
ipv4ll_freearp(ifp);
ipv4_deladdr(ia, 1);
state->addr = NULL;
rt_build(ifp->ctx, AF_INET);

View File

@ -43,11 +43,13 @@
struct ipv4ll_state {
struct in_addr pickedaddr;
struct ipv4_addr *addr;
struct arp_state *arp;
char randomstate[128];
bool seeded;
bool down;
size_t conflicts;
#ifndef KERNEL_RFC5227
struct arp_state *arp;
#endif
};
#define IPV4LL_STATE(ifp) \

View File

@ -98,10 +98,9 @@ struct rs_state {
#define RETRANS_TIMER 1000 /* milliseconds */
#define DELAY_FIRST_PROBE_TIME 5 /* seconds */
int ipv6nd_open(bool);
#ifdef __sun
int ipv6nd_open(struct interface *);
#else
int ipv6nd_open(struct dhcpcd_ctx *);
int ipv6nd_openif(struct interface *);
#endif
void ipv6nd_recvmsg(struct dhcpcd_ctx *, struct msghdr *);
int ipv6nd_rtpref(struct ra *);

View File

@ -54,11 +54,15 @@
#include "logerr.h"
#include "privsep.h"
#ifdef HAVE_CAPSICUM
#include <sys/capsicum.h>
#endif
static void
ps_bpf_recvbpf(void *arg)
{
struct ps_process *psp = arg;
unsigned int flags;
struct bpf *bpf = psp->psp_bpf;
uint8_t buf[FRAMELEN_MAX];
ssize_t len;
struct ps_msghdr psm = {
@ -66,16 +70,16 @@ ps_bpf_recvbpf(void *arg)
.ps_cmd = psp->psp_id.psi_cmd,
};
bpf->bpf_flags &= ~BPF_EOF;
/* A BPF read can read more than one filtered packet at time.
* This mechanism allows us to read each packet from the buffer. */
flags = 0;
while (!(flags & BPF_EOF)) {
len = bpf_read(&psp->psp_ifp, psp->psp_work_fd,
buf, sizeof(buf), &flags);
while (!(bpf->bpf_flags & BPF_EOF)) {
len = bpf_read(bpf, buf, sizeof(buf));
if (len == -1)
logerr(__func__);
if (len == -1 || len == 0)
break;
psm.ps_flags = bpf->bpf_flags;
len = ps_sendpsmdata(psp->psp_ctx, psp->psp_ctx->ps_data_fd,
&psm, buf, (size_t)len);
if (len == -1 && errno != ECONNRESET)
@ -85,55 +89,30 @@ ps_bpf_recvbpf(void *arg)
}
}
#ifdef ARP
static ssize_t
ps_bpf_arp_addr(uint8_t cmd, struct ps_process *psp, struct msghdr *msg)
{
struct interface *ifp = &psp->psp_ifp;
struct iovec *iov = msg->msg_iov;
struct in_addr addr;
struct arp_state *astate;
if (psp == NULL) {
errno = ESRCH;
return -1;
}
assert(msg->msg_iovlen == 1);
assert(iov->iov_len == sizeof(addr));
memcpy(&addr, iov->iov_base, sizeof(addr));
if (cmd & PS_START) {
astate = arp_new(ifp, &addr);
if (astate == NULL)
return -1;
} else if (cmd & PS_DELETE) {
astate = arp_find(ifp, &addr);
if (astate == NULL) {
errno = ESRCH;
return -1;
}
arp_free(astate);
} else {
errno = EINVAL;
return -1;
}
return bpf_arp(ifp, psp->psp_work_fd);
}
#endif
static ssize_t
ps_bpf_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
{
struct ps_process *psp = arg;
struct iovec *iov = msg->msg_iov;
#ifdef ARP
if (psm->ps_cmd & (PS_START | PS_DELETE))
return ps_bpf_arp_addr(psm->ps_cmd, psp, msg);
#ifdef PRIVSEP_DEBUG
logerrx("%s: IN cmd %x, psp %p", __func__, psm->ps_cmd, psp);
#endif
return bpf_send(&psp->psp_ifp, psp->psp_work_fd, psp->psp_proto,
switch(psm->ps_cmd) {
#ifdef ARP
case PS_BPF_ARP: /* FALLTHROUGH */
#endif
case PS_BPF_BOOTP:
break;
default:
/* IPC failure, we should not be processing any commands
* at this point!/ */
errno = EINVAL;
return -1;
}
return bpf_send(psp->psp_bpf, psp->psp_proto,
iov->iov_base, iov->iov_len);
}
@ -152,19 +131,40 @@ ps_bpf_start_bpf(void *arg)
{
struct ps_process *psp = arg;
struct dhcpcd_ctx *ctx = psp->psp_ctx;
char *addr;
struct in_addr *ia = &psp->psp_id.psi_addr.psa_in_addr;
#ifdef HAVE_CAPSICUM
cap_rights_t rights;
setproctitle("[BPF %s] %s", psp->psp_protostr, psp->psp_ifname);
/* We need CAP_IOCTL so we can change the BPF filter when we
* need to. */
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_EVENT, CAP_IOCTL);
#endif
if (ia->s_addr == INADDR_ANY) {
ia = NULL;
addr = NULL;
} else
addr = inet_ntoa(*ia);
setproctitle("[BPF %s] %s%s%s", psp->psp_protostr, psp->psp_ifname,
addr != NULL ? " " : "", addr != NULL ? addr : "");
ps_freeprocesses(ctx, psp);
psp->psp_work_fd = bpf_open(&psp->psp_ifp, psp->psp_filter);
if (psp->psp_work_fd == -1)
psp->psp_bpf = bpf_open(&psp->psp_ifp, psp->psp_filter, ia);
if (psp->psp_bpf == NULL)
logerr("%s: bpf_open",__func__);
#ifdef HAVE_CAPSICUM
else if (cap_rights_limit(psp->psp_bpf->bpf_fd, &rights) == -1 &&
errno != ENOSYS)
logerr("%s: cap_rights_limit", __func__);
#endif
else if (eloop_event_add(ctx->eloop,
psp->psp_work_fd, ps_bpf_recvbpf, psp) == -1)
psp->psp_bpf->bpf_fd, ps_bpf_recvbpf, psp) == -1)
logerr("%s: eloop_event_add", __func__);
else
else {
psp->psp_work_fd = psp->psp_bpf->bpf_fd;
return 0;
}
eloop_exit(ctx->eloop, EXIT_FAILURE);
return -1;
@ -181,14 +181,13 @@ ps_bpf_signal_bpfcb(int sig, void *arg)
ssize_t
ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
{
uint8_t cmd;
uint16_t cmd;
struct ps_process *psp;
pid_t start;
struct iovec *iov = msg->msg_iov;
struct interface *ifp;
struct ipv4_state *istate;
cmd = (uint8_t)(psm->ps_cmd & ~(PS_START | PS_STOP));
cmd = (uint16_t)(psm->ps_cmd & ~(PS_START | PS_STOP));
psp = ps_findprocess(ctx, &psm->ps_id);
#ifdef PRIVSEP_DEBUG
@ -227,11 +226,6 @@ ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
ifp->options = NULL;
memset(ifp->if_data, 0, sizeof(ifp->if_data));
if ((istate = ipv4_getstate(ifp)) == NULL) {
ps_freeprocess(psp);
return -1;
}
memcpy(psp->psp_ifname, ifp->name, sizeof(psp->psp_ifname));
switch (cmd) {
@ -252,12 +246,21 @@ 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, PSF_DROPPRIVS);
ps_bpf_start_bpf, ps_bpf_signal_bpfcb,
PSF_DROPPRIVS);
switch (start) {
case -1:
ps_freeprocess(psp);
return -1;
case 0:
#ifdef HAVE_CAPSICUM
if (cap_enter() == -1 && errno != ENOSYS)
logerr("%s: cap_enter", __func__);
#endif
#ifdef HAVE_PLEDGE
if (pledge("stdio", NULL) == -1)
logerr("%s: pledge", __func__);
#endif
break;
default:
#ifdef PRIVSEP_DEBUG
@ -275,17 +278,21 @@ ps_bpf_dispatch(struct dhcpcd_ctx *ctx,
{
struct iovec *iov = msg->msg_iov;
struct interface *ifp;
uint8_t *bpf;
size_t bpf_len;
ifp = if_findindex(ctx->ifaces, psm->ps_id.psi_ifindex);
bpf = iov->iov_base;
bpf_len = iov->iov_len;
switch (psm->ps_cmd) {
#ifdef ARP
case PS_BPF_ARP:
arp_packet(ifp, iov->iov_base, iov->iov_len);
arp_packet(ifp, bpf, bpf_len, (unsigned int)psm->ps_flags);
break;
#endif
case PS_BPF_BOOTP:
dhcp_packet(ifp, iov->iov_base, iov->iov_len);
dhcp_packet(ifp, bpf, bpf_len, (unsigned int)psm->ps_flags);
break;
default:
errno = ENOTSUP;
@ -296,59 +303,48 @@ ps_bpf_dispatch(struct dhcpcd_ctx *ctx,
}
static ssize_t
ps_bpf_send(const struct interface *ifp, uint8_t cmd,
const void *data, size_t len)
ps_bpf_send(const struct interface *ifp, const struct in_addr *ia,
uint16_t cmd, const void *data, size_t len)
{
struct dhcpcd_ctx *ctx = ifp->ctx;
struct ps_msghdr psm = {
.ps_cmd = cmd,
.ps_id = {
.psi_ifindex = ifp->index,
.psi_cmd = (uint8_t)(cmd &
~(PS_START | PS_STOP | PS_DELETE)),
.psi_cmd = (uint8_t)(cmd & ~(PS_START | PS_STOP)),
},
};
if (psm.ps_id.psi_cmd == PS_BPF_ARP_ADDR)
psm.ps_id.psi_cmd = PS_BPF_ARP;
if (ia != NULL)
psm.ps_id.psi_addr.psa_in_addr = *ia;
return ps_sendpsmdata(ctx, ctx->ps_root_fd, &psm, data, len);
}
#ifdef ARP
ssize_t
ps_bpf_openarp(const struct interface *ifp)
ps_bpf_openarp(const struct interface *ifp, const struct in_addr *ia)
{
return ps_bpf_send(ifp, PS_BPF_ARP | PS_START, ifp, sizeof(*ifp));
assert(ia != NULL);
return ps_bpf_send(ifp, ia, PS_BPF_ARP | PS_START,
ifp, sizeof(*ifp));
}
ssize_t
ps_bpf_addaddr(const struct interface *ifp, const struct in_addr *addr)
ps_bpf_closearp(const struct interface *ifp, const struct in_addr *ia)
{
return ps_bpf_send(ifp, PS_BPF_ARP_ADDR | PS_START, addr, sizeof(*addr));
return ps_bpf_send(ifp, ia, PS_BPF_ARP | PS_STOP, NULL, 0);
}
ssize_t
ps_bpf_deladdr(const struct interface *ifp, const struct in_addr *addr)
ps_bpf_sendarp(const struct interface *ifp, const struct in_addr *ia,
const void *data, size_t len)
{
return ps_bpf_send(ifp, PS_BPF_ARP_ADDR | PS_DELETE, addr, sizeof(*addr));
}
ssize_t
ps_bpf_closearp(const struct interface *ifp)
{
return ps_bpf_send(ifp, PS_BPF_ARP | PS_STOP, NULL, 0);
}
ssize_t
ps_bpf_sendarp(const struct interface *ifp, const void *data, size_t len)
{
return ps_bpf_send(ifp, PS_BPF_ARP, data, len);
assert(ia != NULL);
return ps_bpf_send(ifp, ia, PS_BPF_ARP, data, len);
}
#endif
@ -356,19 +352,20 @@ ssize_t
ps_bpf_openbootp(const struct interface *ifp)
{
return ps_bpf_send(ifp, PS_BPF_BOOTP | PS_START, ifp, sizeof(*ifp));
return ps_bpf_send(ifp, NULL, PS_BPF_BOOTP | PS_START,
ifp, sizeof(*ifp));
}
ssize_t
ps_bpf_closebootp(const struct interface *ifp)
{
return ps_bpf_send(ifp, PS_BPF_BOOTP | PS_STOP, NULL, 0);
return ps_bpf_send(ifp, NULL, PS_BPF_BOOTP | PS_STOP, NULL, 0);
}
ssize_t
ps_bpf_sendbootp(const struct interface *ifp, const void *data, size_t len)
{
return ps_bpf_send(ifp, PS_BPF_BOOTP, data, len);
return ps_bpf_send(ifp, NULL, PS_BPF_BOOTP, data, len);
}

View File

@ -35,11 +35,10 @@ ssize_t ps_bpf_dispatch(struct dhcpcd_ctx *,
struct ps_msghdr *, struct msghdr *);
#ifdef ARP
ssize_t ps_bpf_openarp(const struct interface *);
ssize_t ps_bpf_addaddr(const struct interface *, const struct in_addr *);
ssize_t ps_bpf_deladdr(const struct interface *, const struct in_addr *);
ssize_t ps_bpf_closearp(const struct interface *);
ssize_t ps_bpf_sendarp(const struct interface *, const void *, size_t);
ssize_t ps_bpf_openarp(const struct interface *, const struct in_addr *);
ssize_t ps_bpf_closearp(const struct interface *, const struct in_addr *);
ssize_t ps_bpf_sendarp(const struct interface *, const struct in_addr *,
const void *, size_t);
#endif
ssize_t ps_bpf_openbootp(const struct interface *);

View File

@ -28,7 +28,20 @@
#include <sys/ioctl.h>
/* Need these for filtering the ioctls */
#include <net/if.h>
#include <netinet/in.h>
#include <netinet6/in6_var.h>
#include <netinet6/nd6.h>
#ifdef __DragonFly__
# include <netproto/802_11/ieee80211_ioctl.h>
#else
# include <net80211/ieee80211.h>
# include <net80211/ieee80211_ioctl.h>
#endif
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "dhcpcd.h"
@ -40,13 +53,43 @@ ps_root_doioctldom(int domain, unsigned long req, void *data, size_t len)
{
int s, err;
/* Only allow these ioctls */
switch(req) {
#ifdef SIOCIFAFATTACH
case SIOCIFAFATTACH: /* FALLTHROUGH */
#endif
#ifdef SIOCSIFXFLAGS
case SIOCSIFXFLAGS: /* FALLTHROUGH */
#endif
#ifdef SIOCSIFINFO_FLAGS
case SIOCSIFINFO_FLAGS: /* FALLTHROUGH */
#endif
#ifdef SIOCSRTRFLUSH_IN6
case SIOCSRTRFLUSH_IN6: /* FALLTHROUGH */
case SIOCSPFXFLUSH_IN6: /* FALLTHROUGH */
#endif
#if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE)
case SIOCALIFADDR: /* FALLTHROUGH */
case SIOCDLIFADDR: /* FALLTHROUGH */
#else
case SIOCSIFLLADDR: /* FALLTHROUGH */
#endif
#ifdef SIOCSIFINFO_IN6
case SIOCSIFINFO_IN6: /* FALLTHROUGH */
#endif
case SIOCAIFADDR_IN6: /* FALLTHROUGH */
case SIOCDIFADDR_IN6: /* FALLTHROUGH */
break;
default:
errno = EPERM;
return -1;
}
s = socket(domain, SOCK_DGRAM, 0);
if (s != -1)
err = ioctl(s, req, data, len);
else
err = -1;
if (s != -1)
close(s);
if (s == -1)
return -1;
err = ioctl(s, req, data, len);
close(s);
return err;
}
@ -66,6 +109,37 @@ ps_root_doroute(void *data, size_t len)
return err;
}
#ifdef HAVE_PLEDGE
static ssize_t
ps_root_doindirectioctl(unsigned long req, void *data, size_t len)
{
char *p = data;
struct ifreq ifr = { .ifr_flags = 0 };
ssize_t err;
switch(req) {
case SIOCG80211NWID: /* FALLTHROUGH */
case SIOCGETVLAN:
break;
default:
errno = EPERM;
return -1;
}
if (len < IFNAMSIZ) {
errno = EINVAL;
return -1;
}
strlcpy(ifr.ifr_name, p, IFNAMSIZ);
ifr.ifr_data = p + IFNAMSIZ;
err = ps_root_doioctldom(PF_INET, req, &ifr, sizeof(ifr));
if (err != -1)
memmove(data, ifr.ifr_data, len - IFNAMSIZ);
return err;
}
#endif
ssize_t
ps_root_os(struct ps_msghdr *psm, struct msghdr *msg)
{
@ -80,6 +154,10 @@ ps_root_os(struct ps_msghdr *psm, struct msghdr *msg)
return ps_root_doioctldom(PF_INET6, psm->ps_flags, data, len);
case PS_ROUTE:
return ps_root_doroute(data, len);
#ifdef HAVE_PLEDGE
case PS_IOCTLINDIRECT:
return ps_root_doindirectioctl(psm->ps_flags, data, len);
#endif
default:
errno = ENOTSUP;
return -1;
@ -87,19 +165,19 @@ ps_root_os(struct ps_msghdr *psm, struct msghdr *msg)
}
static ssize_t
ps_root_ioctldom(struct dhcpcd_ctx *ctx, uint8_t domain, unsigned long request,
ps_root_ioctldom(struct dhcpcd_ctx *ctx, uint16_t domain, unsigned long request,
void *data, size_t len)
{
if (ps_sendcmd(ctx, ctx->ps_root_fd, domain,
request, data, len) == -1)
return -1;
return ps_root_readerror(ctx);
return ps_root_readerror(ctx, data, len);
}
ssize_t
ps_root_ioctllink(struct dhcpcd_ctx *ctx, unsigned long request,
void *data,size_t len)
void *data, size_t len)
{
return ps_root_ioctldom(ctx, PS_IOCTLLINK, request, data, len);
@ -119,5 +197,21 @@ ps_root_route(struct dhcpcd_ctx *ctx, void *data, size_t len)
if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_ROUTE, 0, data, len) == -1)
return -1;
return ps_root_readerror(ctx);
return ps_root_readerror(ctx, data, len);
}
#ifdef HAVE_PLEDGE
ssize_t
ps_root_indirectioctl(struct dhcpcd_ctx *ctx, unsigned long request,
const char *ifname, void *data, size_t len)
{
char buf[PS_BUFLEN];
strlcpy(buf, ifname, IFNAMSIZ);
memcpy(buf + IFNAMSIZ, data, len);
if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IOCTLINDIRECT,
request, buf, IFNAMSIZ + len) == -1)
return -1;
return ps_root_readerror(ctx, data, len);
}
#endif

View File

@ -29,6 +29,9 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/icmp6.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
@ -45,13 +48,17 @@
#include "logerr.h"
#include "privsep.h"
#ifdef HAVE_CAPSICUM
#include <sys/capsicum.h>
#endif
#ifdef INET
static void
ps_inet_recvbootp(void *arg)
{
struct dhcpcd_ctx *ctx = arg;
if (ps_recvmsg(ctx, ctx->udp_fd, PS_BOOTP, ctx->ps_inet_fd) == -1)
if (ps_recvmsg(ctx, ctx->udp_rfd, PS_BOOTP, ctx->ps_inet_fd) == -1)
logerr(__func__);
}
#endif
@ -82,7 +89,7 @@ ps_inet_recvdhcp6(void *arg)
{
struct dhcpcd_ctx *ctx = arg;
if (ps_recvmsg(ctx, ctx->dhcp6_fd, PS_DHCP6, ctx->ps_inet_fd) == -1)
if (ps_recvmsg(ctx, ctx->dhcp6_rfd, PS_DHCP6, ctx->ps_inet_fd) == -1)
logerr(__func__);
}
#endif
@ -92,8 +99,19 @@ ps_inet_startcb(void *arg)
{
struct dhcpcd_ctx *ctx = arg;
int ret = 0;
#ifdef HAVE_CAPSICUM
cap_rights_t rights;
setproctitle("[network proxy]");
cap_rights_init(&rights, CAP_RECV, CAP_EVENT);
#endif
if (ctx->options & DHCPCD_MASTER)
setproctitle("[network proxy]");
else
setproctitle("[network proxy] %s%s%s",
ctx->ifv[0],
ctx->options & DHCPCD_IPV4 ? " [ip4]" : "",
ctx->options & DHCPCD_IPV6 ? " [ip6]" : "");
/* This end is the main engine, so it's useless for us. */
close(ctx->ps_data_fd);
@ -105,23 +123,42 @@ ps_inet_startcb(void *arg)
if ((ctx->options & (DHCPCD_IPV4 | DHCPCD_MASTER)) ==
(DHCPCD_IPV4 | DHCPCD_MASTER))
{
ctx->udp_fd = dhcp_openudp(NULL);
if (ctx->udp_fd == -1)
ctx->udp_rfd = dhcp_openudp(NULL);
if (ctx->udp_rfd == -1)
logerr("%s: dhcp_open", __func__);
else if (eloop_event_add(ctx->eloop, ctx->udp_fd,
#ifdef HAVE_CAPSICUM
else if (cap_rights_limit(ctx->udp_rfd, &rights) == -1
&& errno != ENOSYS)
{
logerr("%s: cap_rights_limit", __func__);
close(ctx->udp_rfd);
ctx->udp_rfd = -1;
}
#endif
else if (eloop_event_add(ctx->eloop, ctx->udp_rfd,
ps_inet_recvbootp, ctx) == -1)
{
logerr("%s: eloop_event_add DHCP", __func__);
close(ctx->udp_fd);
ctx->udp_fd = -1;
close(ctx->udp_rfd);
ctx->udp_rfd = -1;
} else
ret++;
}
#endif
#if defined(INET6) && !defined(__sun)
if (ctx->options & DHCPCD_IPV6) {
if (ipv6nd_open(ctx) == -1)
ctx->nd_fd = ipv6nd_open(true);
if (ctx->nd_fd == -1)
logerr("%s: ipv6nd_open", __func__);
#ifdef HAVE_CAPSICUM
else if (cap_rights_limit(ctx->nd_fd, &rights) == -1
&& errno != ENOSYS)
{
logerr("%s: cap_rights_limit", __func__);
close(ctx->nd_fd);
ctx->nd_fd = -1;
}
#endif
else if (eloop_event_add(ctx->eloop, ctx->nd_fd,
ps_inet_recvra, ctx) == -1)
{
@ -136,15 +173,24 @@ ps_inet_startcb(void *arg)
if ((ctx->options & (DHCPCD_DHCP6 | DHCPCD_MASTER)) ==
(DHCPCD_DHCP6 | DHCPCD_MASTER))
{
ctx->dhcp6_fd = dhcp6_openudp(0, NULL);
if (ctx->dhcp6_fd == -1)
ctx->dhcp6_rfd = dhcp6_openudp(0, NULL);
if (ctx->dhcp6_rfd == -1)
logerr("%s: dhcp6_open", __func__);
else if (eloop_event_add(ctx->eloop, ctx->dhcp6_fd,
#ifdef HAVE_CAPSICUM
else if (cap_rights_limit(ctx->dhcp6_rfd, &rights) == -1
&& errno != ENOSYS)
{
logerr("%s: cap_rights_limit", __func__);
close(ctx->dhcp6_rfd);
ctx->dhcp6_rfd = -1;
}
#endif
else if (eloop_event_add(ctx->eloop, ctx->dhcp6_rfd,
ps_inet_recvdhcp6, ctx) == -1)
{
logerr("%s: eloop_event_add DHCP6", __func__);
close(ctx->dhcp6_fd);
ctx->dhcp6_fd = -1;
close(ctx->dhcp6_rfd);
ctx->dhcp6_rfd = -1;
} else
ret++;
}
@ -157,34 +203,84 @@ ps_inet_startcb(void *arg)
return ret;
}
static ssize_t
ps_inet_recvmsg_cb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
static bool
ps_inet_validudp(struct msghdr *msg, uint16_t sport, uint16_t dport)
{
struct udphdr udp;
struct iovec *iov = msg->msg_iov;
if (msg->msg_iovlen == 0 || iov->iov_len < sizeof(udp)) {
errno = EINVAL;
return false;
}
memcpy(&udp, iov->iov_base, sizeof(udp));
if (udp.uh_sport != htons(sport) || udp.uh_dport != htons(dport)) {
errno = EPERM;
return false;
}
return true;
}
#ifdef INET6
static bool
ps_inet_validnd(struct msghdr *msg)
{
struct icmp6_hdr icmp6;
struct iovec *iov = msg->msg_iov;
if (msg->msg_iovlen == 0 || iov->iov_len < sizeof(icmp6)) {
errno = EINVAL;
return false;
}
memcpy(&icmp6, iov->iov_base, sizeof(icmp6));
switch(icmp6.icmp6_type) {
case ND_ROUTER_SOLICIT:
case ND_NEIGHBOR_ADVERT:
break;
default:
errno = EPERM;
return false;
}
return true;
}
#endif
static ssize_t
ps_inet_sendmsg(struct dhcpcd_ctx *ctx,
struct ps_msghdr *psm, struct msghdr *msg)
{
struct dhcpcd_ctx *ctx = arg;
struct ps_process *psp;
int s;
psp = ps_findprocess(ctx, &psm->ps_id);
if (psp != NULL) {
s = psp->psp_work_fd;
logerrx("psp found fd %d", s);
goto dosend;
}
switch (psm->ps_cmd) {
#ifdef INET
case PS_BOOTP:
s = ctx->udp_fd;
if (!ps_inet_validudp(msg, BOOTPC, BOOTPS))
return -1;
s = ctx->udp_wfd;
break;
#endif
#if defined(INET6) && !defined(__sun)
case PS_ND:
if (!ps_inet_validnd(msg))
return -1;
s = ctx->nd_fd;
break;
#endif
#ifdef DHCP6
case PS_DHCP6:
s = ctx->dhcp6_fd;
if (!ps_inet_validudp(msg, DHCP6_CLIENT_PORT,DHCP6_SERVER_PORT))
return -1;
s = ctx->dhcp6_wfd;
break;
#endif
default:
@ -193,17 +289,16 @@ ps_inet_recvmsg_cb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
}
dosend:
return sendmsg(s, msg, 0);
}
/* Receive from state engine, send message on wire. */
static void
ps_inet_recvmsg(void *arg)
{
struct dhcpcd_ctx *ctx = arg;
if (ps_recvpsmsg(ctx, ctx->ps_inet_fd, ps_inet_recvmsg_cb, ctx) == -1)
/* Receive shutdown */
if (ps_recvpsmsg(ctx, ctx->ps_inet_fd, NULL, NULL) == -1)
logerr(__func__);
}
@ -260,10 +355,23 @@ ps_inet_dodispatch(void *arg)
pid_t
ps_inet_start(struct dhcpcd_ctx *ctx)
{
pid_t pid;
return ps_dostart(ctx, &ctx->ps_inet_pid, &ctx->ps_inet_fd,
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, PSF_DROPPRIVS);
ps_inet_startcb, ps_inet_signalcb,
PSF_DROPPRIVS);
#ifdef HAVE_CAPSICUM
if (pid == 0 && cap_enter() == -1 && errno != ENOSYS)
logerr("%s: cap_enter", __func__);
#endif
#ifdef HAVE_PLEDGE
if (pid == 0 && pledge("stdio", NULL) == -1)
logerr("%s: pledge", __func__);
#endif
return pid;
}
int
@ -273,13 +381,6 @@ ps_inet_stop(struct dhcpcd_ctx *ctx)
return ps_dostop(ctx, &ctx->ps_inet_pid, &ctx->ps_inet_fd);
}
ssize_t
ps_inet_sendmsg(struct dhcpcd_ctx *ctx, uint8_t cmd, const struct msghdr *msg)
{
return ps_sendmsg(ctx, ctx->ps_inet_fd, cmd, 0, msg);
}
#ifdef INET
static void
ps_inet_recvinbootp(void *arg)
@ -297,6 +398,11 @@ ps_inet_listenin(void *arg)
struct ps_process *psp = arg;
struct in_addr *ia = &psp->psp_id.psi_addr.psa_in_addr;
char buf[INET_ADDRSTRLEN];
#ifdef HAVE_CAPSICUM
cap_rights_t rights;
cap_rights_init(&rights, CAP_RECV, CAP_EVENT);
#endif
inet_ntop(AF_INET, ia, buf, sizeof(buf));
setproctitle("[network proxy] %s", buf);
@ -307,6 +413,15 @@ ps_inet_listenin(void *arg)
return -1;
}
#ifdef HAVE_CAPSICUM
if (cap_rights_limit(psp->psp_work_fd, &rights) == -1 &&
errno != ENOSYS)
{
logerr("%s: cap_rights_limit", __func__);
return -1;
}
#endif
if (eloop_event_add(psp->psp_ctx->eloop, psp->psp_work_fd,
ps_inet_recvinbootp, psp) == -1)
{
@ -314,9 +429,7 @@ ps_inet_listenin(void *arg)
return -1;
}
#ifdef PRIVSEP_DEBUG
logdebugx("spawned listener %s on PID %d", buf, getpid());
#endif
return 0;
}
#endif
@ -336,6 +449,11 @@ static int
ps_inet_listennd(void *arg)
{
struct ps_process *psp = arg;
#ifdef HAVE_CAPSICUM
cap_rights_t rights;
cap_rights_init(&rights, CAP_RECV, CAP_EVENT);
#endif
setproctitle("[ND network proxy]");
@ -345,6 +463,15 @@ ps_inet_listennd(void *arg)
return -1;
}
#ifdef HAVE_CAPSICUM
if (cap_rights_limit(psp->psp_work_fd, &rights) == -1 &&
errno != ENOSYS)
{
logerr("%s: cap_rights_limit", __func__);
return -1;
}
#endif
if (eloop_event_add(psp->psp_ctx->eloop, psp->psp_work_fd,
ps_inet_recvin6nd, psp) == -1)
{
@ -374,6 +501,11 @@ ps_inet_listenin6(void *arg)
struct ps_process *psp = arg;
struct in6_addr *ia = &psp->psp_id.psi_addr.psa_in6_addr;
char buf[INET6_ADDRSTRLEN];
#ifdef HAVE_CAPSICUM
cap_rights_t rights;
cap_rights_init(&rights, CAP_RECV, CAP_EVENT);
#endif
inet_ntop(AF_INET6, ia, buf, sizeof(buf));
setproctitle("[network proxy] %s", buf);
@ -384,6 +516,15 @@ ps_inet_listenin6(void *arg)
return -1;
}
#ifdef HAVE_CAPSICUM
if (cap_rights_limit(psp->psp_work_fd, &rights) == -1 &&
errno != ENOSYS)
{
logerr("%s: cap_rights_limit", __func__);
return -1;
}
#endif
if (eloop_event_add(psp->psp_ctx->eloop, psp->psp_work_fd,
ps_inet_recvin6dhcp6, psp) == -1)
{
@ -396,35 +537,28 @@ ps_inet_listenin6(void *arg)
}
#endif
static ssize_t
ps_inet_recvmsgpsp_cb(void *arg, __unused struct ps_msghdr *psm,
struct msghdr *msg)
{
struct ps_process *psp = arg;
return sendmsg(psp->psp_work_fd, msg, 0);
}
static void
ps_inet_recvmsgpsp(void *arg)
{
struct ps_process *psp = arg;
if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd,
ps_inet_recvmsgpsp_cb, psp) == -1)
/* Receive shutdown. */
if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, NULL, NULL) == -1)
logerr(__func__);
}
ssize_t
ps_inet_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm,
__unused struct msghdr *msg)
ps_inet_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
{
uint8_t cmd;
uint16_t cmd;
struct ps_process *psp;
int (*start_func)(void *);
pid_t start;
cmd = (uint8_t)(psm->ps_cmd & ~(PS_START | PS_STOP));
cmd = (uint16_t)(psm->ps_cmd & ~(PS_START | PS_STOP));
if (cmd == psm->ps_cmd)
return ps_inet_sendmsg(ctx, psm, msg);
psp = ps_findprocess(ctx, &psm->ps_id);
#ifdef PRIVSEP_DEBUG
@ -475,12 +609,21 @@ ps_inet_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm,
start = ps_dostart(ctx,
&psp->psp_pid, &psp->psp_fd,
ps_inet_recvmsgpsp, NULL, psp,
start_func, ps_inet_signalcb, PSF_DROPPRIVS);
start_func, ps_inet_signalcb,
PSF_DROPPRIVS);
switch (start) {
case -1:
ps_freeprocess(psp);
return -1;
case 0:
#ifdef HAVE_CAPSICUM
if (cap_enter() == -1 && errno != ENOSYS)
logerr("%s: cap_enter", __func__);
#endif
#ifdef HAVE_PLEDGE
if (pledge("stdio", NULL) == -1)
logerr("%s: pledge", __func__);
#endif
break;
default:
break;
@ -490,7 +633,7 @@ ps_inet_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm,
#ifdef INET
static ssize_t
ps_inet_in_docmd(struct ipv4_addr *ia, uint8_t cmd, const struct msghdr *msg)
ps_inet_in_docmd(struct ipv4_addr *ia, uint16_t cmd, const struct msghdr *msg)
{
assert(ia != NULL);
struct dhcpcd_ctx *ctx = ia->iface->ctx;
@ -521,20 +664,17 @@ ps_inet_closebootp(struct ipv4_addr *ia)
}
ssize_t
ps_inet_sendbootp(struct ipv4_addr *ia, const struct msghdr *msg)
ps_inet_sendbootp(struct interface *ifp, const struct msghdr *msg)
{
struct dhcpcd_ctx *ctx = ia->iface->ctx;
if (ctx->options & DHCPCD_MASTER)
return ps_sendmsg(ctx, ctx->ps_inet_fd, PS_BOOTP, 0, msg);
return ps_inet_in_docmd(ia, PS_BOOTP, msg);
return ps_sendmsg(ifp->ctx, ifp->ctx->ps_root_fd, PS_BOOTP, 0, msg);
}
#endif /* INET */
#ifdef INET6
#ifdef __sun
static ssize_t
ps_inet_ifp_docmd(struct interface *ifp, uint8_t cmd, const struct msghdr *msg)
ps_inet_ifp_docmd(struct interface *ifp, uint16_t cmd, const struct msghdr *msg)
{
struct dhcpcd_ctx *ctx = ifp->ctx;
struct ps_msghdr psm = {
@ -573,13 +713,13 @@ ssize_t
ps_inet_sendnd(struct interface *ifp, const struct msghdr *msg)
{
return ps_inet_sendmsg(ifp->ctx, PS_ND, msg);
return ps_sendmsg(ifp->ctx, ifp->ctx->ps_root_fd, PS_ND, 0, msg);
}
#endif
#ifdef DHCP6
static ssize_t
ps_inet_in6_docmd(struct ipv6_addr *ia, uint8_t cmd, const struct msghdr *msg)
ps_inet_in6_docmd(struct ipv6_addr *ia, uint16_t cmd, const struct msghdr *msg)
{
struct dhcpcd_ctx *ctx = ia->iface->ctx;
struct ps_msghdr psm = {
@ -609,13 +749,10 @@ ps_inet_closedhcp6(struct ipv6_addr *ia)
}
ssize_t
ps_inet_senddhcp6(struct ipv6_addr *ia, const struct msghdr *msg)
ps_inet_senddhcp6(struct interface *ifp, const struct msghdr *msg)
{
struct dhcpcd_ctx *ctx = ia->iface->ctx;
if (ctx->options & DHCPCD_MASTER)
return ps_sendmsg(ctx, ctx->ps_inet_fd, PS_DHCP6, 0, msg);
return ps_inet_in6_docmd(ia, PS_DHCP6, msg);
return ps_sendmsg(ifp->ctx, ifp->ctx->ps_root_fd, PS_DHCP6, 0, msg);
}
#endif /* DHCP6 */
#endif /* INET6 */

View File

@ -31,7 +31,6 @@
pid_t ps_inet_start(struct dhcpcd_ctx *);
int ps_inet_stop(struct dhcpcd_ctx *);
ssize_t ps_inet_sendmsg(struct dhcpcd_ctx *, uint8_t, const struct msghdr *);
ssize_t ps_inet_cmd(struct dhcpcd_ctx *, struct ps_msghdr *, struct msghdr *);
ssize_t ps_inet_dispatch(void *, struct ps_msghdr *, struct msghdr *);
@ -39,7 +38,7 @@ ssize_t ps_inet_dispatch(void *, struct ps_msghdr *, struct msghdr *);
struct ipv4_addr;
ssize_t ps_inet_openbootp(struct ipv4_addr *);
ssize_t ps_inet_closebootp(struct ipv4_addr *);
ssize_t ps_inet_sendbootp(struct ipv4_addr *, const struct msghdr *);
ssize_t ps_inet_sendbootp(struct interface *, const struct msghdr *);
#endif
#ifdef INET6
@ -52,7 +51,7 @@ ssize_t ps_inet_sendnd(struct interface *, const struct msghdr *);
#ifdef DHCP6
ssize_t ps_inet_opendhcp6(struct ipv6_addr *);
ssize_t ps_inet_closedhcp6(struct ipv6_addr *);
ssize_t ps_inet_senddhcp6(struct ipv6_addr *, const struct msghdr *);
ssize_t ps_inet_senddhcp6(struct interface *, const struct msghdr *);
#endif /* DHCP6 */
#endif /* INET6 */
#endif

View File

@ -38,16 +38,21 @@
#include <fcntl.h>
#include <pwd.h>
#include <signal.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "common.h"
#include "dev.h"
#include "dhcpcd.h"
#include "dhcp6.h"
#include "eloop.h"
#include "if.h"
#include "ipv6nd.h"
#include "logerr.h"
#include "privsep.h"
#include "sa.h"
#include "script.h"
__CTASSERT(sizeof(ioctl_request_t) <= sizeof(unsigned long));
@ -57,11 +62,14 @@ struct psr_error
ssize_t psr_result;
int psr_errno;
char psr_pad[sizeof(ssize_t) - sizeof(int)];
size_t psr_datalen;
};
struct psr_ctx {
struct dhcpcd_ctx *psr_ctx;
struct psr_error psr_error;
size_t psr_datalen;
void *psr_data;
};
static void
@ -78,35 +86,43 @@ ps_root_readerrorcb(void *arg)
struct psr_ctx *psr_ctx = arg;
struct dhcpcd_ctx *ctx = psr_ctx->psr_ctx;
struct psr_error *psr_error = &psr_ctx->psr_error;
struct iovec iov[] = {
{ .iov_base = psr_error, .iov_len = sizeof(*psr_error) },
{ .iov_base = psr_ctx->psr_data,
.iov_len = psr_ctx->psr_datalen },
};
ssize_t len;
int exit_code = EXIT_FAILURE;
len = read(ctx->ps_root_fd, psr_error, sizeof(*psr_error));
if (len == 0 || len == -1) {
logerr(__func__);
psr_error->psr_result = -1;
psr_error->psr_errno = errno;
} else if ((size_t)len < sizeof(*psr_error)) {
logerrx("%s: psr_error truncated", __func__);
psr_error->psr_result = -1;
psr_error->psr_errno = EINVAL;
} else
exit_code = EXIT_SUCCESS;
#define PSR_ERROR(e) \
do { \
psr_error->psr_result = -1; \
psr_error->psr_errno = (e); \
goto out; \
} while (0 /* CONSTCOND */)
len = readv(ctx->ps_root_fd, iov, __arraycount(iov));
if (len == -1)
PSR_ERROR(errno);
else if ((size_t)len < sizeof(*psr_error))
PSR_ERROR(EINVAL);
exit_code = EXIT_SUCCESS;
out:
eloop_exit(ctx->ps_eloop, exit_code);
}
ssize_t
ps_root_readerror(struct dhcpcd_ctx *ctx)
ps_root_readerror(struct dhcpcd_ctx *ctx, void *data, size_t len)
{
struct psr_ctx psr_ctx = { .psr_ctx = ctx };
struct psr_ctx psr_ctx = {
.psr_ctx = ctx,
.psr_data = data, .psr_datalen = len,
};
if (eloop_event_add(ctx->ps_eloop, ctx->ps_root_fd,
ps_root_readerrorcb, &psr_ctx) == -1)
{
logerr(__func__);
return -1;
}
eloop_start(ctx->ps_eloop, &ctx->sigset);
@ -114,19 +130,85 @@ ps_root_readerror(struct dhcpcd_ctx *ctx)
return psr_ctx.psr_error.psr_result;
}
#ifdef HAVE_CAPSICUM
static void
ps_root_mreaderrorcb(void *arg)
{
struct psr_ctx *psr_ctx = arg;
struct dhcpcd_ctx *ctx = psr_ctx->psr_ctx;
struct psr_error *psr_error = &psr_ctx->psr_error;
struct iovec iov[] = {
{ .iov_base = psr_error, .iov_len = sizeof(*psr_error) },
{ .iov_base = NULL, .iov_len = 0 },
};
ssize_t len;
int exit_code = EXIT_FAILURE;
len = recv(ctx->ps_root_fd, psr_error, sizeof(*psr_error), MSG_PEEK);
if (len == -1)
PSR_ERROR(errno);
else if ((size_t)len < sizeof(*psr_error))
PSR_ERROR(EINVAL);
if (psr_error->psr_datalen != 0) {
psr_ctx->psr_data = malloc(psr_error->psr_datalen);
if (psr_ctx->psr_data == NULL)
PSR_ERROR(errno);
psr_ctx->psr_datalen = psr_error->psr_datalen;
iov[1].iov_base = psr_ctx->psr_data;
iov[1].iov_len = psr_ctx->psr_datalen;
}
len = readv(ctx->ps_root_fd, iov, __arraycount(iov));
if (len == -1)
PSR_ERROR(errno);
else if ((size_t)len != sizeof(*psr_error) + psr_ctx->psr_datalen)
PSR_ERROR(EINVAL);
exit_code = EXIT_SUCCESS;
out:
eloop_exit(ctx->ps_eloop, exit_code);
}
ssize_t
ps_root_mreaderror(struct dhcpcd_ctx *ctx, void **data, size_t *len)
{
struct psr_ctx psr_ctx = {
.psr_ctx = ctx,
};
if (eloop_event_add(ctx->ps_eloop, ctx->ps_root_fd,
ps_root_mreaderrorcb, &psr_ctx) == -1)
return -1;
eloop_start(ctx->ps_eloop, &ctx->sigset);
errno = psr_ctx.psr_error.psr_errno;
*data = psr_ctx.psr_data;
*len = psr_ctx.psr_datalen;
return psr_ctx.psr_error.psr_result;
}
#endif
static ssize_t
ps_root_writeerror(struct dhcpcd_ctx *ctx, ssize_t result)
ps_root_writeerror(struct dhcpcd_ctx *ctx, ssize_t result,
void *data, size_t len)
{
struct psr_error psr = {
.psr_result = result,
.psr_errno = errno,
.psr_datalen = len,
};
struct iovec iov[] = {
{ .iov_base = &psr, .iov_len = sizeof(psr) },
{ .iov_base = data, .iov_len = len },
};
#ifdef PRIVSEP_DEBUG
logdebugx("%s: result %zd errno %d", __func__, result, errno);
#endif
return write(ctx->ps_root_fd, &psr, sizeof(psr));
return writev(ctx->ps_root_fd, iov, __arraycount(iov));
}
static ssize_t
@ -134,6 +216,27 @@ ps_root_doioctl(unsigned long req, void *data, size_t len)
{
int s, err;
/* Only allow these ioctls */
switch(req) {
#ifdef SIOCAIFADDR
case SIOCAIFADDR: /* FALLTHROUGH */
case SIOCDIFADDR: /* FALLTHROUGH */
#endif
#ifdef SIOCSIFHWADDR
case SIOCSIFHWADDR: /* FALLTHROUGH */
#endif
#ifdef SIOCGIFPRIORITY
case SIOCGIFPRIORITY: /* FALLTHROUGH */
#endif
case SIOCSIFFLAGS: /* FALLTHROUGH */
case SIOCGIFMTU: /* FALLTHROUGH */
case SIOCSIFMTU:
break;
default:
errno = EPERM;
return -1;
}
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s != -1)
#ifdef IOCTL_REQUEST_TYPE
@ -157,34 +260,13 @@ static ssize_t
ps_root_run_script(struct dhcpcd_ctx *ctx, const void *data, size_t len)
{
const char *envbuf = data;
char * const argv[] = { UNCONST(data), NULL };
char * const argv[] = { ctx->script, NULL };
pid_t pid;
int status;
#ifdef PRIVSEP_DEBUG
logdebugx("%s: IN %zu", __func__, len);
#endif
if (len == 0)
return 0;
/* Script is the first one, find the environment buffer. */
while (*envbuf != '\0') {
if (len == 0)
return EINVAL;
envbuf++;
len--;
}
if (len != 0) {
envbuf++;
len--;
}
#ifdef PRIVSEP_DEBUG
logdebugx("%s: run script: %s", __func__, argv[0]);
#endif
if (script_buftoenv(ctx, UNCONST(envbuf), len) == NULL)
return -1;
@ -202,147 +284,174 @@ ps_root_run_script(struct dhcpcd_ctx *ctx, const void *data, size_t len)
return status;
}
#if defined(__linux__) && !defined(st_mtimespec)
#define st_atimespec st_atim
#define st_mtimespec st_mtim
#endif
ssize_t
ps_root_docopychroot(struct dhcpcd_ctx *ctx, const char *file)
static bool
ps_root_validpath(const struct dhcpcd_ctx *ctx, uint16_t cmd, const char *path)
{
char path[PATH_MAX], buf[BUFSIZ], *slash;
struct stat from_sb, to_sb;
int from_fd, to_fd;
ssize_t rcount, wcount, total;
#if defined(BSD) || defined(__linux__)
struct timespec ts[2];
#else
struct timeval tv[2];
#endif
/* Avoid a previous directory attack to avoid /proc/../
* dhcpcd should never use a path with double dots. */
if (strstr(path, "..") != NULL)
return false;
if (snprintf(path, sizeof(path), "%s/%s",
ctx->ps_user->pw_dir, file) == -1)
return -1;
if (stat(file, &from_sb) == -1)
return -1;
if (stat(path, &to_sb) == 0) {
#if defined(BSD) || defined(__linux__)
if (from_sb.st_mtimespec.tv_sec == to_sb.st_mtimespec.tv_sec &&
from_sb.st_mtimespec.tv_nsec == to_sb.st_mtimespec.tv_nsec)
return 0;
#else
if (from_sb.st_mtime == to_sb.st_mtime)
return 0;
#endif
} else {
/* Ensure directory exists */
slash = strrchr(path, '/');
if (slash != NULL) {
*slash = '\0';
ps_mkdir(path);
*slash = '/';
}
if (cmd == PS_READFILE) {
if (strcmp(ctx->cffile, path) == 0)
return true;
}
if (strncmp(DBDIR, path, strlen(DBDIR)) == 0)
return true;
if (strncmp(RUNDIR, path, strlen(RUNDIR)) == 0)
return true;
if (unlink(path) == -1 && errno != ENOENT)
return -1;
if ((from_fd = open(file, O_RDONLY, 0)) == -1)
return -1;
if ((to_fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, 0555)) == -1)
return -1;
total = 0;
while ((rcount = read(from_fd, buf, sizeof(buf))) > 0) {
wcount = write(to_fd, buf, (size_t)rcount);
if (wcount != rcount) {
total = -1;
break;
}
total += wcount;
}
#if defined(BSD) || defined(__linux__)
ts[0] = from_sb.st_atimespec;
ts[1] = from_sb.st_mtimespec;
if (futimens(to_fd, ts) == -1)
total = -1;
#else
tv[0].tv_sec = from_sb.st_atime;
tv[0].tv_usec = 0;
tv[1].tv_sec = from_sb.st_mtime;
tv[1].tv_usec = 0;
if (futimes(to_fd, tv) == -1)
total = -1;
#ifdef __linux__
if (strncmp("/proc/net/", path, strlen("/proc/net/")) == 0 ||
strncmp("/proc/sys/net/", path, strlen("/proc/sys/net/")) == 0 ||
strncmp("/sys/class/net/", path, strlen("/sys/class/net/")) == 0)
return true;
#endif
close(from_fd);
close(to_fd);
return total;
errno = EPERM;
return false;
}
static ssize_t
ps_root_dofileop(struct dhcpcd_ctx *ctx, void *data, size_t len, uint8_t op)
ps_root_dowritefile(const struct dhcpcd_ctx *ctx,
mode_t mode, void *data, size_t len)
{
char *path = data;
size_t plen;
char *file = data, *nc;
if (len < sizeof(plen)) {
nc = memchr(file, '\0', len);
if (nc == NULL) {
errno = EINVAL;
return -1;
}
memcpy(&plen, path, sizeof(plen));
path += sizeof(plen);
if (sizeof(plen) + plen > len) {
errno = EINVAL;
if (!ps_root_validpath(ctx, PS_WRITEFILE, file))
return -1;
}
switch(op) {
case PS_COPY:
return ps_root_docopychroot(ctx, path);
case PS_UNLINK:
return (ssize_t)unlink(path);
default:
errno = ENOTSUP;
return -1;
}
nc++;
return writefile(file, mode, nc, len - (size_t)(nc - file));
}
#ifdef HAVE_CAPSICUM
#define IFA_NADDRS 3
static ssize_t
ps_root_dogetifaddrs(void **rdata, size_t *rlen)
{
struct ifaddrs *ifaddrs, *ifa;
size_t len;
uint8_t *buf, *sap;
socklen_t salen;
void *ifdata;
if (getifaddrs(&ifaddrs) == -1)
return -1;
if (ifaddrs == NULL) {
*rdata = NULL;
*rlen = 0;
return 0;
}
/* Work out the buffer length required.
* Ensure everything is aligned correctly, which does
* create a larger buffer than what is needed to send,
* but makes creating the same structure in the client
* much easier. */
len = 0;
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
len += ALIGN(sizeof(*ifa));
len += ALIGN(IFNAMSIZ);
len += ALIGN(sizeof(salen) * IFA_NADDRS);
if (ifa->ifa_addr != NULL)
len += ALIGN(sa_len(ifa->ifa_addr));
if (ifa->ifa_netmask != NULL)
len += ALIGN(sa_len(ifa->ifa_netmask));
if (ifa->ifa_broadaddr != NULL)
len += ALIGN(sa_len(ifa->ifa_broadaddr));
}
/* Use calloc to set everything to zero.
* This satisfies memory sanitizers because don't write
* where we don't need to. */
buf = calloc(1, len);
if (buf == NULL) {
freeifaddrs(ifaddrs);
return -1;
}
*rdata = buf;
*rlen = len;
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
/* Don't carry ifa_data. */
ifdata = ifa->ifa_data;
ifa->ifa_data = NULL;
memcpy(buf, ifa, sizeof(*ifa));
buf += ALIGN(sizeof(*ifa));
ifa->ifa_data = ifdata;
strlcpy((char *)buf, ifa->ifa_name, IFNAMSIZ);
buf += ALIGN(IFNAMSIZ);
sap = buf;
buf += ALIGN(sizeof(salen) * IFA_NADDRS);
#define COPYINSA(addr) \
do { \
salen = sa_len((addr)); \
if (salen != 0) { \
memcpy(sap, &salen, sizeof(salen)); \
memcpy(buf, (addr), salen); \
buf += ALIGN(salen); \
} \
sap += sizeof(salen); \
} while (0 /*CONSTCOND */)
if (ifa->ifa_addr != NULL)
COPYINSA(ifa->ifa_addr);
if (ifa->ifa_netmask != NULL)
COPYINSA(ifa->ifa_netmask);
if (ifa->ifa_broadaddr != NULL)
COPYINSA(ifa->ifa_broadaddr);
}
freeifaddrs(ifaddrs);
return 0;
}
#endif
static ssize_t
ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
{
struct dhcpcd_ctx *ctx = arg;
uint8_t cmd;
uint16_t cmd;
struct ps_process *psp;
struct iovec *iov = msg->msg_iov;
void *data = iov->iov_base;
size_t len = iov->iov_len;
void *data = iov->iov_base, *rdata = NULL;
size_t len = iov->iov_len, rlen = 0;
uint8_t buf[PS_BUFLEN];
time_t mtime;
ssize_t err;
bool free_rdata = false;
cmd = (uint8_t)(psm->ps_cmd & ~(PS_START | PS_STOP | PS_DELETE));
cmd = (uint16_t)(psm->ps_cmd & ~(PS_START | PS_STOP));
psp = ps_findprocess(ctx, &psm->ps_id);
#ifdef PRIVSEP_DEBUG
logerrx("%s: IN cmd %x, psp %p", __func__, psm->ps_cmd, psp);
#endif
if ((!(psm->ps_cmd & PS_START) || cmd == PS_BPF_ARP_ADDR) &&
psp != NULL)
{
if (psp != NULL) {
if (psm->ps_cmd & PS_STOP) {
int ret = ps_dostop(ctx, &psp->psp_pid, &psp->psp_fd);
ps_freeprocess(psp);
return ret;
}
return ps_sendpsmmsg(ctx, psp->psp_fd, psm, msg);
} else if (!(psm->ps_cmd & PS_START))
return ps_sendpsmmsg(ctx, psp->psp_fd, psm, msg);
/* Process has already started .... */
return 0;
}
if (psm->ps_cmd & (PS_STOP | PS_DELETE) && psp == NULL)
if (psm->ps_cmd & PS_STOP && psp == NULL)
return 0;
/* All these should just be PS_START */
switch (cmd) {
#ifdef INET
#ifdef ARP
@ -366,7 +475,7 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
break;
}
assert(msg->msg_iovlen == 1);
assert(msg->msg_iovlen == 0 || msg->msg_iovlen == 1);
/* Reset errno */
errno = 0;
@ -374,20 +483,71 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
switch (psm->ps_cmd) {
case PS_IOCTL:
err = ps_root_doioctl(psm->ps_flags, data, len);
if (err != -1) {
rdata = data;
rlen = len;
}
break;
case PS_SCRIPT:
err = ps_root_run_script(ctx, data, len);
break;
case PS_COPY: /* FALLTHROUGH */
case PS_UNLINK:
err = ps_root_dofileop(ctx, data, len, psm->ps_cmd);
if (!ps_root_validpath(ctx, psm->ps_cmd, data)) {
err = -1;
break;
}
err = unlink(data);
break;
case PS_READFILE:
if (!ps_root_validpath(ctx, psm->ps_cmd, data)) {
err = -1;
break;
}
err = readfile(data, buf, sizeof(buf));
if (err != -1) {
rdata = buf;
rlen = (size_t)err;
}
break;
case PS_WRITEFILE:
err = ps_root_dowritefile(ctx, (mode_t)psm->ps_flags,
data, len);
break;
case PS_FILEMTIME:
err = filemtime(data, &mtime);
if (err != -1) {
rdata = &mtime;
rlen = sizeof(mtime);
}
break;
#ifdef HAVE_CAPSICUM
case PS_GETIFADDRS:
err = ps_root_dogetifaddrs(&rdata, &rlen);
free_rdata = true;
break;
#endif
#if defined(INET6) && (defined(__linux__) || defined(HAVE_PLEDGE))
case PS_IP6FORWARDING:
err = ip6_forwarding(data);
break;
#endif
#ifdef PLUGIN_DEV
case PS_DEV_INITTED:
err = dev_initialized(ctx, data);
break;
case PS_DEV_LISTENING:
err = dev_listening(ctx);
break;
#endif
default:
err = ps_root_os(psm, msg);
break;
}
return ps_root_writeerror(ctx, err);
err = ps_root_writeerror(ctx, err, rlen != 0 ? rdata : 0, rlen);
if (free_rdata)
free(rdata);
return err;
}
/* Receive from state engine, do an action. */
@ -401,13 +561,72 @@ ps_root_recvmsg(void *arg)
logerr(__func__);
}
#ifdef PLUGIN_DEV
static int
ps_root_handleinterface(void *arg, int action, const char *ifname)
{
struct dhcpcd_ctx *ctx = arg;
unsigned long flag;
if (action == 1)
flag = PS_DEV_IFADDED;
else if (action == -1)
flag = PS_DEV_IFREMOVED;
else if (action == 0)
flag = PS_DEV_IFUPDATED;
else {
errno = EINVAL;
return -1;
}
return (int)ps_sendcmd(ctx, ctx->ps_data_fd, PS_DEV_IFCMD, flag,
ifname, strlen(ifname) + 1);
}
#endif
static int
ps_root_startcb(void *arg)
{
struct dhcpcd_ctx *ctx = arg;
setproctitle("[privileged actioneer]");
if (ctx->options & DHCPCD_MASTER)
setproctitle("[privileged actioneer]");
else
setproctitle("[privileged actioneer] %s%s%s",
ctx->ifv[0],
ctx->options & DHCPCD_IPV4 ? " [ip4]" : "",
ctx->options & DHCPCD_IPV6 ? " [ip6]" : "");
ctx->ps_root_pid = getpid();
ctx->options |= DHCPCD_PRIVSEPROOT;
/* 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. */
#ifdef INET
ctx->udp_wfd = xsocket(PF_INET, SOCK_RAW | SOCK_CXNB, IPPROTO_UDP);
if (ctx->udp_wfd == -1)
return -1;
#endif
#ifdef INET6
ctx->nd_fd = ipv6nd_open(false);
if (ctx->nd_fd == -1)
return -1;
#endif
#ifdef DHCP6
ctx->dhcp6_wfd = dhcp6_openraw();
if (ctx->dhcp6_wfd == -1)
return -1;
#endif
#ifdef PLUGIN_DEV
/* Start any dev listening plugin which may want to
* change the interface name provided by the kernel */
if ((ctx->options & (DHCPCD_MASTER | DHCPCD_DEV)) ==
(DHCPCD_MASTER | DHCPCD_DEV))
dev_start(ctx, ps_root_handleinterface);
#endif
return 0;
}
@ -429,17 +648,58 @@ ps_root_signalcb(int sig, void *arg)
eloop_exit(ctx->eloop, sig == SIGTERM ? EXIT_SUCCESS : EXIT_FAILURE);
}
int (*handle_interface)(void *, int, const char *);
#ifdef PLUGIN_DEV
static ssize_t
ps_root_devcb(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
{
int action;
struct iovec *iov = msg->msg_iov;
if (msg->msg_iovlen != 1) {
errno = EINVAL;
return -1;
}
switch(psm->ps_flags) {
case PS_DEV_IFADDED:
action = 1;
break;
case PS_DEV_IFREMOVED:
action = -1;
break;
case PS_DEV_IFUPDATED:
action = 0;
break;
default:
errno = EINVAL;
return -1;
}
return dhcpcd_handleinterface(ctx, action, iov->iov_base);
}
#endif
static ssize_t
ps_root_dispatchcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
{
struct dhcpcd_ctx *ctx = arg;
ssize_t err;
#ifdef INET
err = ps_bpf_dispatch(ctx, psm, msg);
if (err == -1 && errno == ENOTSUP)
switch(psm->ps_cmd) {
#ifdef PLUGIN_DEV
case PS_DEV_IFCMD:
err = ps_root_devcb(ctx, psm, msg);
break;
#endif
err = ps_inet_dispatch(ctx, psm, msg);
default:
#ifdef INET
err = ps_bpf_dispatch(ctx, psm, msg);
if (err == -1 && errno == ENOTSUP)
#endif
err = ps_inet_dispatch(ctx, psm, msg);
}
return err;
}
@ -458,7 +718,6 @@ ps_root_start(struct dhcpcd_ctx *ctx)
int fd[2];
pid_t pid;
#define SOCK_CXNB SOCK_CLOEXEC | SOCK_NONBLOCK
if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, fd) == -1)
return -1;
@ -477,20 +736,16 @@ ps_root_start(struct dhcpcd_ctx *ctx)
close(fd[1]);
if (eloop_event_add(ctx->eloop, ctx->ps_data_fd,
ps_root_dispatch, ctx) == -1)
logerr(__func__);
if ((ctx->ps_eloop = eloop_new()) == NULL) {
logerr(__func__);
return -1;
}
if ((ctx->ps_eloop = eloop_new()) == NULL)
return -1;
if (eloop_signal_set_cb(ctx->ps_eloop,
dhcpcd_signals, dhcpcd_signals_len,
ps_root_readerrorsig, ctx) == -1)
{
logerr(__func__);
return -1;
}
return pid;
}
@ -502,39 +757,12 @@ ps_root_stop(struct dhcpcd_ctx *ctx)
}
ssize_t
ps_root_script(const struct interface *ifp, const void *data, size_t len)
ps_root_script(struct dhcpcd_ctx *ctx, const void *data, size_t len)
{
char buf[PS_BUFLEN], *p = buf;
size_t blen = PS_BUFLEN, slen = strlen(ifp->options->script) + 1;
#ifdef PRIVSEP_DEBUG
logdebugx("%s: sending script: %zu %s len %zu",
__func__, slen, ifp->options->script, len);
#endif
if (slen > blen) {
errno = ENOBUFS;
if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_SCRIPT, 0, data, len) == -1)
return -1;
}
memcpy(p, ifp->options->script, slen);
p += slen;
blen -= slen;
if (len > blen) {
errno = ENOBUFS;
return -1;
}
memcpy(p, data, len);
#ifdef PRIVSEP_DEBUG
logdebugx("%s: sending script data: %zu", __func__, slen + len);
#endif
if (ps_sendcmd(ifp->ctx, ifp->ctx->ps_root_fd, PS_SCRIPT, 0,
buf, slen + len) == -1)
return -1;
return ps_root_readerror(ifp->ctx);
return ps_root_readerror(ctx, NULL, 0);
}
ssize_t
@ -551,41 +779,157 @@ ps_root_ioctl(struct dhcpcd_ctx *ctx, ioctl_request_t req, void *data,
if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IOCTL, req, data, len) == -1)
return -1;
#endif
return ps_root_readerror(ctx);
return ps_root_readerror(ctx, data, len);
}
static ssize_t
ps_root_fileop(struct dhcpcd_ctx *ctx, const char *path, uint8_t op)
ssize_t
ps_root_unlink(struct dhcpcd_ctx *ctx, const char *file)
{
char buf[PATH_MAX], *p = buf;
size_t plen = strlen(path) + 1;
size_t len = sizeof(plen) + plen;
if (len > sizeof(buf)) {
if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_UNLINK, 0,
file, strlen(file) + 1) == -1)
return -1;
return ps_root_readerror(ctx, NULL, 0);
}
ssize_t
ps_root_readfile(struct dhcpcd_ctx *ctx, const char *file,
void *data, size_t len)
{
if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_READFILE, 0,
file, strlen(file) + 1) == -1)
return -1;
return ps_root_readerror(ctx, data, len);
}
ssize_t
ps_root_writefile(struct dhcpcd_ctx *ctx, const char *file, mode_t mode,
const void *data, size_t len)
{
char buf[PS_BUFLEN];
size_t flen;
flen = strlcpy(buf, file, sizeof(buf));
flen += 1;
if (flen > sizeof(buf) || flen + len > sizeof(buf)) {
errno = ENOBUFS;
return -1;
}
memcpy(buf + flen, data, len);
memcpy(p, &plen, sizeof(plen));
p += sizeof(plen);
memcpy(p, path, plen);
if (ps_sendcmd(ctx, ctx->ps_root_fd, op, 0, buf, len) == -1)
if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_WRITEFILE, mode,
buf, flen + len) == -1)
return -1;
return ps_root_readerror(ctx);
}
ssize_t
ps_root_copychroot(struct dhcpcd_ctx *ctx, const char *path)
{
return ps_root_fileop(ctx, path, PS_COPY);
return ps_root_readerror(ctx, NULL, 0);
}
ssize_t
ps_root_unlink(struct dhcpcd_ctx *ctx, const char *path)
ps_root_filemtime(struct dhcpcd_ctx *ctx, const char *file, time_t *time)
{
return ps_root_fileop(ctx, path, PS_UNLINK);
if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_FILEMTIME, 0,
file, strlen(file) + 1) == -1)
return -1;
return ps_root_readerror(ctx, time, sizeof(*time));
}
#ifdef HAVE_CAPSICUM
int
ps_root_getifaddrs(struct dhcpcd_ctx *ctx, struct ifaddrs **ifahead)
{
struct ifaddrs *ifa;
void *buf = NULL;
char *bp, *sap;
socklen_t salen;
size_t len;
ssize_t err;
if (ps_sendcmd(ctx, ctx->ps_root_fd,
PS_GETIFADDRS, 0, NULL, 0) == -1)
return -1;
err = ps_root_mreaderror(ctx, &buf, &len);
if (err == -1)
return -1;
/* Should be impossible - lo0 will always exist. */
if (len == 0) {
*ifahead = NULL;
return 0;
}
bp = buf;
*ifahead = (struct ifaddrs *)(void *)bp;
for (ifa = *ifahead; len != 0; ifa = ifa->ifa_next) {
if (len < ALIGN(sizeof(*ifa)) +
ALIGN(IFNAMSIZ) + ALIGN(sizeof(salen) * IFA_NADDRS))
goto err;
bp += ALIGN(sizeof(*ifa));
ifa->ifa_name = bp;
bp += ALIGN(IFNAMSIZ);
sap = bp;
bp += ALIGN(sizeof(salen) * IFA_NADDRS);
len -= ALIGN(sizeof(*ifa)) +
ALIGN(IFNAMSIZ) + ALIGN(sizeof(salen) * IFA_NADDRS);
#define COPYOUTSA(addr) \
do { \
memcpy(&salen, sap, sizeof(salen)); \
if (len < salen) \
goto err; \
if (salen != 0) { \
(addr) = (struct sockaddr *)bp; \
bp += ALIGN(salen); \
len -= ALIGN(salen); \
} \
sap += sizeof(salen); \
} while (0 /* CONSTCOND */)
COPYOUTSA(ifa->ifa_addr);
COPYOUTSA(ifa->ifa_netmask);
COPYOUTSA(ifa->ifa_broadaddr);
ifa->ifa_next = (struct ifaddrs *)(void *)bp;
}
ifa->ifa_next = NULL;
return 0;
err:
free(buf);
*ifahead = NULL;
errno = EINVAL;
return -1;
}
#endif
#if defined(__linux__) || defined(HAVE_PLEDGE)
ssize_t
ps_root_ip6forwarding(struct dhcpcd_ctx *ctx, const char *ifname)
{
if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IP6FORWARDING, 0,
ifname, ifname != NULL ? strlen(ifname) + 1 : 0) == -1)
return -1;
return ps_root_readerror(ctx, NULL, 0);
}
#endif
#ifdef PLUGIN_DEV
int
ps_root_dev_initialized(struct dhcpcd_ctx *ctx, const char *ifname)
{
if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_DEV_INITTED, 0,
ifname, strlen(ifname) + 1)== -1)
return -1;
return (int)ps_root_readerror(ctx, NULL, 0);
}
int
ps_root_dev_listening(struct dhcpcd_ctx * ctx)
{
if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_DEV_LISTENING, 0, NULL, 0)== -1)
return -1;
return (int)ps_root_readerror(ctx, NULL, 0);
}
#endif

View File

@ -34,21 +34,34 @@
pid_t ps_root_start(struct dhcpcd_ctx *ctx);
int ps_root_stop(struct dhcpcd_ctx *ctx);
ssize_t ps_root_readerror(struct dhcpcd_ctx *);
ssize_t ps_root_docopychroot(struct dhcpcd_ctx *, const char *);
ssize_t ps_root_copychroot(struct dhcpcd_ctx *, const char *);
ssize_t ps_root_readerror(struct dhcpcd_ctx *, void *, size_t);
ssize_t ps_root_mreaderror(struct dhcpcd_ctx *, void **, size_t *);
ssize_t ps_root_ioctl(struct dhcpcd_ctx *, ioctl_request_t, void *, size_t);
ssize_t ps_root_ip6forwarding(struct dhcpcd_ctx *, const char *);
ssize_t ps_root_unlink(struct dhcpcd_ctx *, const char *);
ssize_t ps_root_filemtime(struct dhcpcd_ctx *, const char *, time_t *);
ssize_t ps_root_readfile(struct dhcpcd_ctx *, const char *, void *, size_t);
ssize_t ps_root_writefile(struct dhcpcd_ctx *, const char *, mode_t,
const void *, size_t);
ssize_t ps_root_script(struct dhcpcd_ctx *, const void *, size_t);
int ps_root_getifaddrs(struct dhcpcd_ctx *, struct ifaddrs **);
ssize_t ps_root_os(struct ps_msghdr *, struct msghdr *);
#if defined(BSD) || defined(__sun)
ssize_t ps_root_route(struct dhcpcd_ctx *, void *, size_t);
ssize_t ps_root_ioctllink(struct dhcpcd_ctx *, unsigned long, void *, size_t);
ssize_t ps_root_ioctl6(struct dhcpcd_ctx *, unsigned long, void *, size_t);
ssize_t ps_root_indirectioctl(struct dhcpcd_ctx *, unsigned long, const char *,
void *, size_t);
#endif
#ifdef __linux__
ssize_t ps_root_sendnetlink(struct dhcpcd_ctx *, int, struct msghdr *);
ssize_t ps_root_writepathuint(struct dhcpcd_ctx *, const char *, unsigned int);
#endif
ssize_t ps_root_script(const struct interface *, const void *, size_t);
#ifdef PLUGIN_DEV
int ps_root_dev_initialized(struct dhcpcd_ctx *, const char *);
int ps_root_dev_listening(struct dhcpcd_ctx *);
#endif
#endif

View File

@ -34,30 +34,42 @@
/* Start flags */
#define PSF_DROPPRIVS 0x01
/* Commands */
#define PS_BOOTP 0x01
#define PS_ND 0x02
#define PS_DHCP6 0x03
#define PS_BPF_BOOTP 0x04
#define PS_BPF_ARP 0x05
#define PS_BPF_ARP_ADDR 0x06
/* Protocols */
#define PS_BOOTP 0x0001
#define PS_ND 0x0002
#define PS_DHCP6 0x0003
#define PS_BPF_BOOTP 0x0004
#define PS_BPF_ARP 0x0005
#define PS_IOCTL 0x10
#define PS_ROUTE 0x11 /* Also used for NETLINK */
#define PS_SCRIPT 0x12
#define PS_UNLINK 0x13
#define PS_COPY 0x14
/* Generic commands */
#define PS_IOCTL 0x0010
#define PS_ROUTE 0x0011 /* Also used for NETLINK */
#define PS_SCRIPT 0x0012
#define PS_UNLINK 0x0013
#define PS_READFILE 0x0014
#define PS_WRITEFILE 0x0015
#define PS_FILEMTIME 0x0016
/* BSD Commands */
#define PS_IOCTLLINK 0x15
#define PS_IOCTL6 0x16
#define PS_IOCTLLINK 0x0101
#define PS_IOCTL6 0x0102
#define PS_IOCTLINDIRECT 0x0103
#define PS_IP6FORWARDING 0x0104
#define PS_GETIFADDRS 0x0105
/* Linux commands */
#define PS_WRITEPATHUINT 0x17
/* Dev Commands */
#define PS_DEV_LISTENING 0x0201
#define PS_DEV_INITTED 0x0202
#define PS_DEV_IFCMD 0x0203
#define PS_DELETE 0x20
#define PS_START 0x40
#define PS_STOP 0x80
/* Dev Interface Commands (via flags) */
#define PS_DEV_IFADDED 0x0001
#define PS_DEV_IFREMOVED 0x0002
#define PS_DEV_IFUPDATED 0x0003
/* Process commands */
#define PS_START 0x4000
#define PS_STOP 0x8000
/* Max INET message size + meta data for IPC */
#define PS_BUFLEN ((64 * 1024) + \
@ -92,13 +104,13 @@ struct ps_addr {
struct ps_id {
struct ps_addr psi_addr;
unsigned int psi_ifindex;
uint8_t psi_cmd;
uint8_t psi_pad[3];
uint16_t psi_cmd;
uint8_t psi_pad[2];
};
struct ps_msghdr {
uint8_t ps_cmd;
uint8_t ps_pad[sizeof(unsigned long) - 1];
uint16_t ps_cmd;
uint8_t ps_pad[sizeof(unsigned long) - sizeof(uint16_t)];
unsigned long ps_flags;
struct ps_id ps_id;
socklen_t ps_namelen;
@ -112,6 +124,7 @@ struct ps_msg {
uint8_t psm_data[PS_BUFLEN];
};
struct bpf;
struct ps_process {
TAILQ_ENTRY(ps_process) next;
struct dhcpcd_ctx *psp_ctx;
@ -125,8 +138,9 @@ struct ps_process {
const char *psp_protostr;
#ifdef INET
int (*psp_filter)(struct interface *, int);
int (*psp_filter)(const struct bpf *, const struct in_addr *);
struct interface psp_ifp; /* Move BPF gubbins elsewhere */
struct bpf *psp_bpf;
#endif
};
TAILQ_HEAD(ps_process_head, ps_process);
@ -137,7 +151,6 @@ TAILQ_HEAD(ps_process_head, ps_process);
#include "privsep-bpf.h"
#endif
int ps_mkdir(char *);
int ps_init(struct dhcpcd_ctx *);
int ps_dropprivs(struct dhcpcd_ctx *);
int ps_start(struct dhcpcd_ctx *);
@ -148,11 +161,11 @@ ssize_t ps_sendpsmmsg(struct dhcpcd_ctx *, int,
struct ps_msghdr *, const struct msghdr *);
ssize_t ps_sendpsmdata(struct dhcpcd_ctx *, int,
struct ps_msghdr *, const void *, size_t);
ssize_t ps_sendmsg(struct dhcpcd_ctx *, int, uint8_t, unsigned long,
ssize_t ps_sendmsg(struct dhcpcd_ctx *, int, uint16_t, unsigned long,
const struct msghdr *);
ssize_t ps_sendcmd(struct dhcpcd_ctx *, int, uint8_t, unsigned long,
ssize_t ps_sendcmd(struct dhcpcd_ctx *, int, uint16_t, unsigned long,
const void *data, size_t len);
ssize_t ps_recvmsg(struct dhcpcd_ctx *, int, uint8_t, int);
ssize_t ps_recvmsg(struct dhcpcd_ctx *, int, uint16_t, int);
ssize_t ps_recvpsmsg(struct dhcpcd_ctx *, int,
ssize_t (*callback)(void *, struct ps_msghdr *, struct msghdr *), void *);

View File

@ -32,7 +32,7 @@
#include <arpa/inet.h>
#ifdef AF_LINK
#include <net/if_dl.h>
#elif AF_PACKET
#elif defined(AF_PACKET)
#include <linux/if_packet.h>
#endif
@ -288,7 +288,7 @@ sa_toprefix(const struct sockaddr *sa)
#ifndef NDEBUG
/* Ensure the calculation is correct */
if (!sa_inprefix) {
union sa_ss ss = { .sa.sa_family = sa->sa_family };
union sa_ss ss = { .sa = { .sa_family = sa->sa_family } };
sa_inprefix = true;
sa_fromprefix(&ss.sa, prefix);
@ -385,7 +385,7 @@ sa_addrtop(const struct sockaddr *sa, char *buf, socklen_t len)
}
return hwaddr_ntoa(CLLADDR(sdl), sdl->sdl_alen, buf, len);
}
#elif AF_PACKET
#elif defined(AF_PACKET)
if (sa->sa_family == AF_PACKET) {
const struct sockaddr_ll *sll;

View File

@ -37,5 +37,4 @@ char ** script_buftoenv(struct dhcpcd_ctx *, char *, size_t);
pid_t script_exec(char *const *, char *const *);
int send_interface(struct fd_list *, const struct interface *, int);
int script_runreason(const struct interface *, const char *);
int script_runchroot(struct dhcpcd_ctx *, char *);
#endif