Except for the priviledged process.
This is quite an in-depth change:
* ARP is now one process per address
* BPF flags are now returned via privsep
* BPF write filters are locked when supported
* The root process sends to the network
The last step is done by opening RAW sockets and then sending a UDP
header (where applicable) to avoid binding to an address
which is already in use by the reader sockets.
This is slightly wasteful for OS's without sandboxing but does
have the very nice side effect of not needing a source address
to unicast DHCPs replies from which makes the code smaller.
__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->hwtype);
ar.ar_pro = htons(ETHERTYPE_IP);
#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;
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",
}
void
-arp_packet(struct interface *ifp, uint8_t *data, size_t len)
+arp_packet(struct interface *ifp, uint8_t *data, size_t len, uint8_t bpf_flags)
{
size_t fl = bpf_frame_header_len(ifp), falen;
const struct interface *ifn;
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
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__);
}
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 */
goto skip_request;
#endif
- if (arp_request(ifp, &astate->addr, &astate->addr) == -1)
+ if (arp_request(astate, &astate->addr) == -1)
logerr(__func__);
#ifndef __linux__
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);
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)))
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);
- if (state->bpf_fd != -1) {
- if (bpf_arp(ifp, state->bpf_fd) == -1)
- logerr(__func__); /* try and continue */
- }
return astate;
}
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);
+ 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
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 */
}
#define RATE_LIMIT_INTERVAL 60
#define DEFEND_INTERVAL 10
+#include "bpf.h"
#include "dhcpcd.h"
#include "if.h"
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;
};
((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, uint8_t);
struct arp_state *arp_new(struct interface *, const struct in_addr *);
void arp_probe(struct arp_state *);
void arp_announce(struct arp_state *);
#include "if.h"
#include "logerr.h"
-#define ARP_ADDRS_MAX 3
-
/* BPF helper macros */
#ifdef __linux__
#define BPF_WHOLEPACKET 0x7fffffff /* work around buggy LPF filters */
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
int
-bpf_frame_bcast(const struct interface *ifp, const char *frame)
+bpf_frame_bcast(const struct interface *ifp, const void *frame)
{
switch (ifp->hwtype) {
case ARPHRD_ETHER:
- return memcmp(frame +
+ return memcmp((const char *)frame +
offsetof(struct ether_header, ether_dhost),
etherbcastaddr, sizeof(etherbcastaddr));
default:
const char *bpf_name = "Berkley Packet Filter";
-int
-bpf_open(struct interface *ifp, int (*filter)(struct interface *, int))
+struct bpf *
+bpf_open(const struct interface *ifp,
+ int (*filter)(const struct bpf *, const struct in_addr *),
+ const struct in_addr *ia)
{
- struct ipv4_state *state;
- int fd = -1;
- struct ifreq ifr;
+ struct bpf *bpf;
+ struct bpf_version pv = { .bv_major = 0, .bv_minor = 0 };
+ struct ifreq ifr = { .ifr_flags = 0 };
int ibuf_len = 0;
- size_t buf_len;
- struct bpf_version pv;
#ifdef BIOCIMMEDIATE
unsigned int flags;
#endif
char device[32];
int n = 0;
+ bpf = calloc(1, sizeof(*bpf));
+ if (bpf == NULL)
+ return NULL;
+ bpf->bpf_ifp = ifp;
+
do {
snprintf(device, sizeof(device), "/dev/bpf%d", n++);
- fd = open(device, O_RDWR | O_NONBLOCK
+ bpf->bpf_fd = open(device, O_RDWR | O_NONBLOCK
#ifdef O_CLOEXEC
| O_CLOEXEC
#endif
);
- } while (fd == -1 && errno == EBUSY);
+ } while (bpf->bpf_fd == -1 && errno == EBUSY);
#endif
- if (fd == -1)
- return -1;
+ if (bpf->bpf_fd == -1)
+ goto eexit;
#ifndef O_CLOEXEC
- if ((fd_opts = fcntl(fd, F_GETFD)) == -1 ||
- fcntl(fd, F_SETFD, fd_opts | FD_CLOEXEC) == -1) {
- close(fd);
- return -1;
- }
+ if ((fd_opts = fcntl(bpf->bpf_fd, F_GETFD)) == -1 ||
+ fcntl(bpf->bpf_fd, F_SETFD, fd_opts | FD_CLOEXEC) == -1)
+ goto eexit;
#endif
- memset(&pv, 0, sizeof(pv));
- if (ioctl(fd, BIOCVERSION, &pv) == -1)
+ if (ioctl(bpf->bpf_fd, BIOCVERSION, &pv) == -1)
goto eexit;
if (pv.bv_major != BPF_MAJOR_VERSION ||
pv.bv_minor < BPF_MINOR_VERSION) {
goto eexit;
}
- if (filter(ifp, fd) != 0)
- goto eexit;
-
- memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
- if (ioctl(fd, BIOCSETIF, &ifr) == -1)
+ if (ioctl(bpf->bpf_fd, BIOCSETIF, &ifr) == -1)
goto eexit;
- /* Get the required BPF buffer length from the kernel. */
- if (ioctl(fd, BIOCGBLEN, &ibuf_len) == -1)
- goto eexit;
- buf_len = (size_t)ibuf_len;
- state = ipv4_getstate(ifp);
- if (state == NULL)
- goto eexit;
- if (state->buffer_size != buf_len) {
- void *nb;
-
- if ((nb = realloc(state->buffer, buf_len)) == NULL)
- goto eexit;
- state->buffer = nb;
- state->buffer_size = buf_len;
- }
-
#ifdef BIOCIMMEDIATE
flags = 1;
- if (ioctl(fd, BIOCIMMEDIATE, &flags) == -1)
+ if (ioctl(bpf->bpf_fd, BIOCIMMEDIATE, &flags) == -1)
goto eexit;
#endif
- return fd;
+ if (filter(bpf, ia) != 0)
+ goto eexit;
+
+ /* Get the required BPF buffer length from the kernel. */
+ if (ioctl(bpf->bpf_fd, BIOCGBLEN, &ibuf_len) == -1)
+ goto eexit;
+ bpf->bpf_size = (size_t)ibuf_len;
+ bpf->bpf_buffer = malloc(bpf->bpf_size);
+ if (bpf->bpf_buffer == NULL)
+ goto eexit;
+ return bpf;
eexit:
- close(fd);
- return -1;
+ if (bpf->bpf_fd != -1)
+ close(bpf->bpf_fd);
+ free(bpf);
+ return NULL;
}
/* BPF requires that we read the entire buffer.
* So we pass the buffer in the API so we can loop on >1 packet. */
ssize_t
-bpf_read(struct interface *ifp, int fd, void *data, size_t len,
- unsigned int *flags)
+bpf_read(struct bpf *bpf, void *data, size_t len)
{
ssize_t bytes;
- struct ipv4_state *state = IPV4_STATE(ifp);
-
struct bpf_hdr packet;
const char *payload;
- *flags &= ~BPF_EOF;
+ bpf->bpf_flags &= ~BPF_EOF;
for (;;) {
- if (state->buffer_len == 0) {
- bytes = read(fd, state->buffer, state->buffer_size);
+ if (bpf->bpf_len == 0) {
+ bytes = read(bpf->bpf_fd, bpf->bpf_buffer,
+ bpf->bpf_size);
#if defined(__sun)
/* After 2^31 bytes, the kernel offset overflows.
* To work around this bug, lseek 0. */
#endif
if (bytes == -1 || bytes == 0)
return bytes;
- state->buffer_len = (size_t)bytes;
- state->buffer_pos = 0;
+ bpf->bpf_len = (size_t)bytes;
+ bpf->bpf_pos = 0;
}
bytes = -1;
- memcpy(&packet, state->buffer + state->buffer_pos,
- sizeof(packet));
- if (state->buffer_pos + packet.bh_caplen + packet.bh_hdrlen >
- state->buffer_len)
+ payload = (const char *)bpf->bpf_buffer + bpf->bpf_pos;
+ memcpy(&packet, payload, sizeof(packet));
+ if (bpf->bpf_pos + packet.bh_caplen + packet.bh_hdrlen >
+ bpf->bpf_len)
goto next; /* Packet beyond buffer, drop. */
- payload = state->buffer + state->buffer_pos + packet.bh_hdrlen;
- if (bpf_frame_bcast(ifp, payload) == 0)
- *flags |= BPF_BCAST;
- else
- *flags &= ~BPF_BCAST;
+ payload += packet.bh_hdrlen;
if (packet.bh_caplen > len)
bytes = (ssize_t)len;
else
bytes = (ssize_t)packet.bh_caplen;
+ if (bpf_frame_bcast(bpf->bpf_ifp, payload) == 0)
+ bpf->bpf_flags |= BPF_BCAST;
+ else
+ bpf->bpf_flags &= ~BPF_BCAST;
memcpy(data, payload, (size_t)bytes);
next:
- state->buffer_pos += BPF_WORDALIGN(packet.bh_hdrlen +
+ bpf->bpf_pos += BPF_WORDALIGN(packet.bh_hdrlen +
packet.bh_caplen);
- if (state->buffer_pos >= state->buffer_len) {
- state->buffer_len = state->buffer_pos = 0;
- *flags |= BPF_EOF;
+ if (bpf->bpf_pos >= bpf->bpf_len) {
+ bpf->bpf_len = bpf->bpf_pos = 0;
+ bpf->bpf_flags |= BPF_EOF;
}
if (bytes != -1)
return bytes;
#ifndef __sun
/* SunOS is special too - sending via BPF goes nowhere. */
ssize_t
-bpf_send(const struct interface *ifp, int fd, uint16_t protocol,
+bpf_send(const struct bpf *bpf, uint16_t protocol,
const void *data, size_t len)
{
struct iovec iov[2];
struct ether_header eh;
- switch(ifp->hwtype) {
+ switch(bpf->bpf_ifp->hwtype) {
case ARPHRD_ETHER:
memset(&eh.ether_dhost, 0xff, sizeof(eh.ether_dhost));
- memcpy(&eh.ether_shost, ifp->hwaddr, sizeof(eh.ether_shost));
+ memcpy(&eh.ether_shost, bpf->bpf_ifp->hwaddr,
+ sizeof(eh.ether_shost));
eh.ether_type = htons(protocol);
iov[0].iov_base = &eh;
iov[0].iov_len = sizeof(eh);
}
iov[1].iov_base = UNCONST(data);
iov[1].iov_len = len;
- return writev(fd, iov, 2);
+ return writev(bpf->bpf_fd, iov, 2);
}
#endif
-int
-bpf_close(struct interface *ifp, int fd)
+void
+bpf_close(struct bpf *bpf)
+{
+
+ close(bpf->bpf_fd);
+ free(bpf->bpf_buffer);
+ free(bpf);
+}
+
+#ifdef ARP
+#define BPF_CMP_HWADDR_LEN ((((HWADDR_LEN / 4) + 2) * 2) + 1)
+static unsigned int
+bpf_cmp_hwaddr(struct bpf_insn *bpf, size_t bpf_len, size_t off,
+ bool equal, const uint8_t *hwaddr, size_t hwaddr_len)
{
- struct ipv4_state *state = IPV4_STATE(ifp);
+ struct bpf_insn *bp;
+ size_t maclen, nlft, njmps;
+ uint32_t mac32;
+ uint16_t mac16;
+ uint8_t jt, jf;
+
+ /* Calc the number of jumps */
+ if ((hwaddr_len / 4) >= 128) {
+ errno = EINVAL;
+ return 0;
+ }
+ njmps = (hwaddr_len / 4) * 2; /* 2 instructions per check */
+ /* We jump after the 1st check. */
+ if (njmps)
+ njmps -= 2;
+ nlft = hwaddr_len % 4;
+ if (nlft) {
+ njmps += (nlft / 2) * 2;
+ nlft = nlft % 2;
+ if (nlft)
+ njmps += 2;
+
+ }
+
+ /* Skip to positive finish. */
+ njmps++;
+ if (equal) {
+ jt = (uint8_t)njmps;
+ jf = 0;
+ } else {
+ jt = 0;
+ jf = (uint8_t)njmps;
+ }
- /* Rewind the buffer on closing. */
- state->buffer_len = state->buffer_pos = 0;
- return close(fd);
+ bp = bpf;
+ for (; hwaddr_len > 0;
+ hwaddr += maclen, hwaddr_len -= maclen, off += maclen)
+ {
+ if (bpf_len < 3) {
+ errno = ENOBUFS;
+ return 0;
+ }
+ bpf_len -= 3;
+
+ if (hwaddr_len >= 4) {
+ maclen = sizeof(mac32);
+ memcpy(&mac32, hwaddr, maclen);
+ BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, off);
+ bp++;
+ BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
+ htonl(mac32), jt, jf);
+ } else if (hwaddr_len >= 2) {
+ maclen = sizeof(mac16);
+ memcpy(&mac16, hwaddr, maclen);
+ BPF_SET_STMT(bp, BPF_LD + BPF_H + BPF_IND, off);
+ bp++;
+ BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
+ htons(mac16), jt, jf);
+ } else {
+ maclen = sizeof(*hwaddr);
+ BPF_SET_STMT(bp, BPF_LD + BPF_B + BPF_IND, off);
+ bp++;
+ BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
+ *hwaddr, jt, jf);
+ }
+ if (jt)
+ jt = (uint8_t)(jt - 2);
+ if (jf)
+ jf = (uint8_t)(jf - 2);
+ bp++;
+ }
+
+ /* Last step is always return failure.
+ * Next step is a positive finish. */
+ BPF_SET_STMT(bp, BPF_RET + BPF_K, 0);
+ bp++;
+
+ return (unsigned int)(bp - bpf);
}
+#endif
#ifdef ARP
static const struct bpf_insn bpf_arp_ether [] = {
};
#define BPF_ARP_FILTER_LEN __arraycount(bpf_arp_filter)
-#define BPF_ARP_ADDRS_LEN 1 + (ARP_ADDRS_MAX * 2) + 3 + \
- (ARP_ADDRS_MAX * 2) + 1
+/* One address is two checks of two statements. */
+#define BPF_NADDRS 1
+#define BPF_ARP_ADDRS_LEN 5 + ((BPF_NADDRS * 2) * 2)
-#define BPF_ARP_LEN BPF_ARP_ETHER_LEN + BPF_ARP_FILTER_LEN
+#define BPF_ARP_LEN BPF_ARP_ETHER_LEN + BPF_ARP_FILTER_LEN + \
+ BPF_CMP_HWADDR_LEN + BPF_ARP_ADDRS_LEN
-int
-bpf_arp(struct interface *ifp, int fd)
+static int
+bpf_arp_rw(const struct bpf *bpf, const struct in_addr *ia, bool recv)
{
- struct bpf_insn bpf[BPF_ARP_LEN + 1];
+ const struct interface *ifp = bpf->bpf_ifp;
+ struct bpf_insn buf[BPF_ARP_LEN + 1];
struct bpf_insn *bp;
uint16_t arp_len;
- if (fd == -1)
- return 0;
-
- bp = bpf;
+ bp = buf;
/* Check frame header. */
switch(ifp->hwtype) {
case ARPHRD_ETHER:
memcpy(bp, bpf_arp_filter, sizeof(bpf_arp_filter));
bp += BPF_ARP_FILTER_LEN;
- /* Past the filer so return the packet. */
+ /* Ensure it's not from us. */
+ bp += bpf_cmp_hwaddr(bp, BPF_CMP_HWADDR_LEN, sizeof(struct arphdr),
+ !recv, ifp->hwaddr, ifp->hwlen);
+
+ /* Match sender protocol address */
+ BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND,
+ sizeof(struct arphdr) + ifp->hwlen);
+ bp++;
+ BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, htonl(ia->s_addr), 0, 1);
+ bp++;
BPF_SET_STMT(bp, BPF_RET + BPF_K, arp_len);
bp++;
- if (bpf_attach(fd, bpf, (unsigned int)(bp - bpf)) == -1)
- return -1;
+ /* If we didn't match sender, then we're only interested in
+ * ARP probes to us, so check the null host sender. */
+ BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, INADDR_ANY, 1, 0);
+ bp++;
+ BPF_SET_STMT(bp, BPF_RET + BPF_K, 0);
+ bp++;
+
+ /* Match target protocol address */
+ BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, (sizeof(struct arphdr) +
+ (size_t)(ifp->hwlen * 2) + sizeof(in_addr_t)));
+ bp++;
+ BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, htonl(ia->s_addr), 0, 1);
+ bp++;
+ BPF_SET_STMT(bp, BPF_RET + BPF_K, arp_len);
+ bp++;
+
+ /* No match, drop it */
+ BPF_SET_STMT(bp, BPF_RET + BPF_K, 0);
+ bp++;
#ifdef BIOCSETWF
- if (bpf_wattach(fd, bpf, (unsigned int)(bp - bpf)) == -1 ||
- ioctl(fd, BIOCLOCK) == -1)
- return -1;
+ if (!recv)
+ return bpf_wattach(bpf->bpf_fd, buf, (unsigned int)(bp - buf));
#endif
+ return bpf_attach(bpf->bpf_fd, buf, (unsigned int)(bp - buf));
+}
+
+int
+bpf_arp(const struct bpf *bpf, const struct in_addr *ia)
+{
+
+#ifdef BIOCSETWF
+ if (bpf_arp_rw(bpf, ia, true) == -1 ||
+ bpf_arp_rw(bpf, ia, false) == -1 ||
+ ioctl(bpf->bpf_fd, BIOCLOCK) == -1)
+ return -1;
return 0;
+#else
+ return bpf_arp_rw(bpf, ia, true);
+#endif
}
#endif
BPF_BOOTP_XID_LEN + BPF_BOOTP_CHADDR_LEN + 4
static int
-bpf_bootp_rw(struct interface *ifp, int fd, bool read)
+bpf_bootp_rw(const struct bpf *bpf, bool read)
{
- struct bpf_insn bpf[BPF_BOOTP_LEN + 1];
+ struct bpf_insn buf[BPF_BOOTP_LEN + 1];
struct bpf_insn *bp;
- if (fd == -1)
- return 0;
-
- bp = bpf;
+ bp = buf;
/* Check frame header. */
- switch(ifp->hwtype) {
+ switch(bpf->bpf_ifp->hwtype) {
#ifdef ARPHRD_NONE
case ARPHRD_NONE:
memcpy(bp, bpf_bootp_none, sizeof(bpf_bootp_none));
BPF_SET_STMT(bp, BPF_RET + BPF_K, BPF_WHOLEPACKET);
bp++;
- return bpf_wattach(fd, bpf, (unsigned int)(bp - bpf));
+ return bpf_wattach(bpf->bpf_fd, buf, (unsigned int)(bp - buf));
}
#else
UNUSED(read);
BPF_SET_STMT(bp, BPF_RET + BPF_K, BPF_WHOLEPACKET);
bp++;
- return bpf_attach(fd, bpf, (unsigned int)(bp - bpf));
+ return bpf_attach(bpf->bpf_fd, buf, (unsigned int)(bp - buf));
}
int
-bpf_bootp(struct interface *ifp, int fd)
+bpf_bootp(const struct bpf *bpf, __unused const struct in_addr *ia)
{
#ifdef BIOCSETWF
- if (bpf_bootp_rw(ifp, fd, true) == -1 ||
- bpf_bootp_rw(ifp, fd, false) == -1 ||
- ioctl(fd, BIOCLOCK) == -1)
+ if (bpf_bootp_rw(bpf, true) == -1 ||
+ bpf_bootp_rw(bpf, false) == -1 ||
+ ioctl(bpf->bpf_fd, BIOCLOCK) == -1)
return -1;
return 0;
#else
- return bpf_bootp_rw(ifp, fd, true);
+ return bpf_bootp_rw(bpf, true);
#endif
}
#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 0x01
+#define BPF_PARTIALCSUM 0x02
+#define BPF_BCAST 0x04
/*
* Even though we program the BPF filter should we trust it?
#include "dhcpcd.h"
+struct bpf {
+ const struct interface *bpf_ifp;
+ int bpf_fd;
+ uint8_t 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
{
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)
if (get_option_uint32(ctx, &lease->renewaltime,
bootp, len, DHO_RENEWALTIME) != 0)
lease->renewaltime = 0;
+ lease->renewaltime = 5;
if (get_option_uint32(ctx, &lease->rebindtime,
bootp, len, DHO_REBINDTIME) != 0)
lease->rebindtime = 0;
}
#endif
- if (state->bpf_fd != -1) {
- eloop_event_delete(ctx->eloop, state->bpf_fd);
- bpf_close(ifp, state->bpf_fd);
- state->bpf_fd = -1;
- state->bpf_flags |= BPF_EOF;
+ if (state->bpf != NULL) {
+ eloop_event_delete(ctx->eloop, state->bpf->bpf_fd);
+ bpf_close(state->bpf);
+ state->bpf = NULL;
}
- if (state->udp_fd != -1) {
- eloop_event_delete(ctx->eloop, state->udp_fd);
- close(state->udp_fd);
- state->udp_fd = -1;
+ if (state->udp_rfd != -1) {
+ eloop_event_delete(ctx->eloop, state->udp_rfd);
+ close(state->udp_rfd);
+ state->udp_rfd = -1;
}
state->interval = 0;
struct sockaddr_in sin;
int n;
- if ((s = xsocket(PF_INET, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_UDP)) == -1)
+ if ((s = xsocket(PF_INET, SOCK_DGRAM | SOCK_CXNB, IPPROTO_UDP)) == -1)
return -1;
n = 1;
if (setsockopt(s, IPPROTO_IP, IP_RECVPKTINFO, &n, sizeof(n)) == -1)
goto errexit;
#endif
+#ifdef SO_RERROR
+ if (setsockopt(s, SOL_SOCKET, SO_RERROR, &n, sizeof(n)) == -1)
+ goto errexit;
+#endif
+
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(BOOTPC);
.sin_len = sizeof(sin),
#endif
};
+ struct udphdr udp = {
+ .uh_sport = htons(BOOTPC),
+ .uh_dport = htons(BOOTPS),
+ .uh_ulen = htons(sizeof(udp) + len),
+ };
struct iovec iov[] = {
- { .iov_base = data, .iov_len = len }
+ { .iov_base = &udp, .iov_len = sizeof(udp), },
+ { .iov_base = data, .iov_len = len, },
};
struct msghdr msg = {
.msg_name = (void *)&sin,
.msg_namelen = sizeof(sin),
.msg_iov = iov,
- .msg_iovlen = 1,
+ .msg_iovlen = __arraycount(iov),
};
- struct dhcp_state *state = D_STATE(ifp);
- ssize_t r;
- int fd;
+ struct dhcpcd_ctx *ctx = ifp->ctx;
#ifdef PRIVSEP
- if (ifp->ctx->options & DHCPCD_PRIVSEP)
- return ps_inet_sendbootp(state->addr, &msg);
+ if (ctx->options & DHCPCD_PRIVSEP)
+ return ps_inet_sendbootp(ifp, &msg);
#endif
- fd = state->udp_fd;
- if (fd == -1) {
- fd = dhcp_openudp(&state->addr->addr);
- if (fd == -1)
- return -1;
- }
- r = sendmsg(fd, &msg, 0);
- if (state->udp_fd == -1)
- close(fd);
- return r;
+ return sendmsg(ctx->udp_wfd, &msg, 0);
}
static void
* interface we want to configure because we can't dictate the
* interface via IP_PKTINFO unlike for IPv6.
*/
- if (to.s_addr != INADDR_BROADCAST)
- {
+ if (to.s_addr != INADDR_BROADCAST) {
if (dhcp_sendudp(ifp, &to, bootp, len) != -1)
goto out;
logerr("%s: dhcp_sendudp", ifp->name);
free(udp);
#endif
} else {
- r = bpf_send(ifp, state->bpf_fd,
- ETHERTYPE_IP, (uint8_t *)udp, ulen);
+ r = bpf_send(state->bpf, ETHERTYPE_IP, udp, ulen);
free(udp);
}
/* If we failed to send a raw packet this normally means
}
#endif
-#if defined(ARP) && (!defined(KERNEL_RFC5227) || defined(ARPING))
+#ifdef ARP
+#ifndef KERNEL_RFC5227
static void
-dhcp_arp_not_found(struct arp_state *astate)
+dhcp_arp_defend_failed(struct arp_state *astate)
{
- struct interface *ifp;
+ struct interface *ifp = astate->iface;
+
+ dhcp_drop(ifp, "EXPIRED");
+ dhcp_start1(ifp);
+}
+#endif
+
+#if !defined(KERNEL_RFC5227) || defined(ARPING)
+static void dhcp_arp_not_found(struct arp_state *);
+
+static struct arp_state *
+dhcp_arp_new(struct interface *ifp, struct in_addr *addr)
+{
+ struct arp_state *astate;
+
+ astate = arp_new(ifp, addr);
+ if (astate == NULL)
+ return NULL;
+
+ astate->found_cb = dhcp_arp_found;
+ astate->not_found_cb = dhcp_arp_not_found;
+#ifdef KERNEL_RFC5227
+ astate->announced_cb = dhcp_arp_announced;
+#else
+ astate->announced_cb = NULL;
+ astate->defend_failed_cb = dhcp_arp_defend_failed;
+#endif
+ return astate;
+}
+#endif
+
#ifdef ARPING
+static int
+dhcp_arping(struct interface *ifp)
+{
struct dhcp_state *state;
struct if_options *ifo;
+ struct arp_state *astate;
+ struct in_addr addr;
+
+ state = D_STATE(ifp);
+ ifo = ifp->options;
+
+ if (ifo->arping_len == 0 || state->arping_index > ifo->arping_len)
+ return 0;
+
+ if (state->arping_index + 1 == ifo->arping_len) {
+ state->arping_index++;
+ dhcpcd_startinterface(ifp);
+ return 1;
+ }
+
+ addr.s_addr = ifo->arping[++state->arping_index];
+ astate = dhcp_arp_new(ifp, &addr);
+ if (astate == NULL) {
+ logerr(__func__);
+ return -1;
+ }
+ arp_probe(astate);
+ return 1;
+}
#endif
+#if !defined(KERNEL_RFC5227) || defined(ARPING)
+static void
+dhcp_arp_not_found(struct arp_state *astate)
+{
+ struct interface *ifp;
+
ifp = astate->iface;
#ifdef ARPING
- state = D_STATE(ifp);
- ifo = ifp->options;
- if (ifo->arping_len && state->arping_index < ifo->arping_len) {
- /* We didn't find a profile for this
- * address or hwaddr, so move to the next
- * arping profile */
- if (++state->arping_index < ifo->arping_len) {
- arp_probe(astate);
- return;
- }
+ if (dhcp_arping(ifp) == 1) {
arp_free(astate);
- dhcpcd_startinterface(ifp);
return;
}
#endif
arp_free(astate);
dhcp_addr_duplicated(ifp, &addr);
}
+#endif
#ifdef KERNEL_RFC5227
static void
}
#endif
- state->udp_fd = dhcp_openudp(&state->addr->addr);
- if (state->udp_fd == -1) {
+ state->udp_rfd = dhcp_openudp(&state->addr->addr);
+ if (state->udp_rfd == -1) {
logerr(__func__);
/* Address sharing without master mode is not supported.
* It's also possible another DHCP client could be running,
dhcp_openbpf(ifp);
return;
}
- eloop_event_add(ctx->eloop, state->udp_fd, dhcp_handleifudp, ifp);
+ eloop_event_add(ctx->eloop, state->udp_rfd, dhcp_handleifudp, ifp);
}
static void
return sizeof(**bootp);
}
-#ifdef ARP
-#ifndef KERNEL_RFC5227
-static void
-dhcp_arp_defend_failed(struct arp_state *astate)
-{
- struct interface *ifp = astate->iface;
-
- dhcp_drop(ifp, "EXPIRED");
- dhcp_start1(ifp);
-}
-#endif
-
-#if !defined(KERNEL_RFC5227) || defined(ARPING)
-static struct arp_state *
-dhcp_arp_new(struct interface *ifp, struct in_addr *addr)
-{
- struct arp_state *astate;
-
- astate = arp_new(ifp, addr);
- if (astate == NULL)
- return NULL;
-
- astate->found_cb = dhcp_arp_found;
- astate->not_found_cb = dhcp_arp_not_found;
-#ifdef KERNEL_RFC5227
- astate->announced_cb = dhcp_arp_announced;
-#else
- astate->announced_cb = NULL;
- astate->defend_failed_cb = dhcp_arp_defend_failed;
-#endif
- return astate;
-}
-#endif
-#endif /* ARP */
-
#if defined(ARP) || defined(KERNEL_RFC5227)
static int
dhcp_arp_address(struct interface *ifp)
state->reason = "TEST";
script_runreason(ifp, state->reason);
eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
- state->bpf_flags |= BPF_EOF;
+ state->bpf->bpf_flags |= BPF_EOF;
return;
}
eloop_timeout_delete(ifp->ctx->eloop, send_discover, ifp);
}
void
-dhcp_packet(struct interface *ifp, uint8_t *data, size_t len)
+dhcp_packet(struct interface *ifp, uint8_t *data, size_t len, uint8_t bpf_flags)
{
struct bootp *bootp;
struct in_addr from;
size_t udp_len;
- const struct dhcp_state *state = D_CSTATE(ifp);
size_t fl = bpf_frame_header_len(ifp);
-
#ifdef PRIVSEP
+ const struct dhcp_state *state = D_CSTATE(ifp);
+
/* Ignore double reads */
if (IN_PRIVSEP(ifp->ctx)) {
switch (state->state) {
/* Trim frame header */
if (fl != 0) {
if (len < fl) {
- logerrx("%s: %s: short frame header",
- __func__, ifp->name);
+ logerrx("%s: %s: short frame header %zu",
+ __func__, ifp->name, len);
return;
}
len -= fl;
return;
}
- if (!checksums_valid(data, &from, state->bpf_flags)) {
+ if (!checksums_valid(data, &from, bpf_flags)) {
logerrx("%s: checksum failure from %s",
ifp->name, inet_ntoa(from));
return;
uint8_t buf[FRAMELEN_MAX];
ssize_t bytes;
struct dhcp_state *state = D_STATE(ifp);
+ struct bpf *bpf = state->bpf;
- /* 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) {
if (state->state != DHS_NONE) {
logerr("%s: %s", __func__, ifp->name);
}
break;
}
- dhcp_packet(ifp, buf, (size_t)bytes);
+ dhcp_packet(ifp, buf, (size_t)bytes, bpf->bpf_flags);
/* Check we still have a state after processing. */
if ((state = D_STATE(ifp)) == NULL)
break;
+ if ((bpf = state->bpf) == NULL)
+ break;
}
- if (state != NULL)
- state->bpf_flags &= ~BPF_READING;
}
void
return;
}
- if (state->bpf_fd != -1) {
+ if (state->bpf != NULL) {
/* Avoid a duplicate read if BPF is open for the interface. */
return;
}
if (ifp != NULL) {
state = D_CSTATE(ifp);
- s = state->udp_fd;
+ s = state->udp_rfd;
} else
- s = ctx->udp_fd;
+ s = ctx->udp_rfd;
bytes = recvmsg(s, &msg, 0);
if (bytes == -1) {
}
#endif
- if (state->bpf_fd != -1)
+ if (state->bpf != NULL)
return 0;
- state->bpf_fd = bpf_open(ifp, bpf_bootp);
- if (state->bpf_fd == -1) {
+ state->bpf = bpf_open(ifp, bpf_bootp, NULL);
+ if (state->bpf == NULL) {
if (errno == ENOENT) {
logerrx("%s not found", bpf_name);
/* May as well disable IPv4 entirely at
}
eloop_event_add(ifp->ctx->eloop,
- state->bpf_fd, dhcp_readbpf, ifp);
+ state->bpf->bpf_fd, dhcp_readbpf, ifp);
return 0;
}
}
}
if (ifp == NULL) {
- if (ctx->udp_fd != -1) {
- eloop_event_delete(ctx->eloop, ctx->udp_fd);
- close(ctx->udp_fd);
- ctx->udp_fd = -1;
+ if (ctx->udp_rfd != -1) {
+ eloop_event_delete(ctx->eloop, ctx->udp_rfd);
+ close(ctx->udp_rfd);
+ ctx->udp_rfd = -1;
+ }
+ if (ctx->udp_wfd != -1) {
+ close(ctx->udp_wfd);
+ ctx->udp_wfd = -1;
}
free(ctx->opt_buffer);
state->state = DHS_NONE;
/* 0 is a valid fd, so init to -1 */
- state->bpf_fd = -1;
- state->udp_fd = -1;
+ state->udp_rfd = -1;
#ifdef ARPING
state->arping_index = -1;
#endif
* Only do this in master mode so we don't swallow messages
* for dhcpcd running on another interface. */
if ((ctx->options & (DHCPCD_MASTER|DHCPCD_PRIVSEP)) == DHCPCD_MASTER
- && ctx->udp_fd == -1)
+ && ctx->udp_rfd == -1)
{
- ctx->udp_fd = dhcp_openudp(NULL);
- if (ctx->udp_fd == -1) {
+ ctx->udp_rfd = dhcp_openudp(NULL);
+ if (ctx->udp_rfd == -1) {
+ logerr(__func__);
+ return;
+ }
+ eloop_event_add(ctx->eloop, ctx->udp_rfd, dhcp_handleudp, ctx);
+ }
+ if (!IN_PRIVSEP(ctx) && ctx->udp_wfd == -1) {
+ ctx->udp_wfd = xsocket(PF_INET, SOCK_RAW|SOCK_CXNB,IPPROTO_UDP);
+ if (ctx->udp_wfd == -1) {
logerr(__func__);
return;
}
- eloop_event_add(ctx->eloop, ctx->udp_fd, dhcp_handleudp, ctx);
}
if (dhcp_init(ifp) == -1) {
#ifdef ARPING
if (ifo->arping_len && state->arping_index < ifo->arping_len) {
- struct arp_state *astate;
-
- astate = dhcp_arp_new(ifp, NULL);
- if (astate)
- dhcp_arp_not_found(astate);
+ dhcp_arping(ifp);
return;
}
#endif
#include <stdint.h>
#include "arp.h"
+#include "bpf.h"
#include "auth.h"
#include "dhcp-common.h"
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;
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, uint8_t);
void dhcp_recvmsg(struct dhcpcd_ctx *, struct msghdr *);
void dhcp_printoptions(const struct dhcpcd_ctx *,
const struct dhcp_opt *, size_t);
*/
#include <sys/utsname.h>
+#include <sys/types.h>
#include <netinet/in.h>
+#include <netinet/ip6.h>
#include <assert.h>
#include <ctype.h>
}
#endif
+static const struct in6_addr alldhcp = IN6ADDR_LINKLOCAL_ALLDHCP_INIT;
static int
dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *))
{
struct dhcp6_state *state = D6_STATE(ifp);
struct dhcpcd_ctx *ctx = ifp->ctx;
+ unsigned int RT;
+ bool broadcast = true;
struct sockaddr_in6 dst = {
.sin6_family = AF_INET6,
.sin6_port = htons(DHCP6_SERVER_PORT),
};
- unsigned int RT;
- const char *broad_uni;
- const struct in6_addr alldhcp = IN6ADDR_LINKLOCAL_ALLDHCP_INIT;
- struct ipv6_addr *lla;
- int s;
- struct iovec iov = {
- .iov_base = state->send, .iov_len = state->send_len,
+ struct udphdr udp = {
+ .uh_sport = htons(DHCP6_CLIENT_PORT),
+ .uh_dport = htons(DHCP6_SERVER_PORT),
+ .uh_ulen = htons(sizeof(udp) + state->send_len),
+ };
+ struct iovec iov[] = {
+ { .iov_base = &udp, .iov_len = sizeof(udp), },
+ { .iov_base = state->send, .iov_len = state->send_len, },
};
union {
struct cmsghdr hdr;
} cmsgbuf = { .buf = { 0 } };
struct msghdr msg = {
.msg_name = &dst, .msg_namelen = sizeof(dst),
- .msg_iov = &iov, .msg_iovlen = 1,
+ .msg_iov = iov, .msg_iovlen = __arraycount(iov),
};
+ char uaddr[INET6_ADDRSTRLEN];
if (!callback && ifp->carrier <= LINK_DOWN)
return 0;
-#ifdef HAVE_SA_LEN
- dst.sin6_len = sizeof(dst);
-#endif
-
- lla = ipv6_linklocal(ifp);
- /* We need to ensure we have sufficient scope to unicast the address */
- /* XXX FIXME: We should check any added addresses we have like from
- * a Router Advertisement */
- if (IN6_IS_ADDR_UNSPECIFIED(&state->unicast) ||
- (state->state == DH6S_REQUEST &&
- (!IN6_IS_ADDR_LINKLOCAL(&state->unicast) || lla == NULL)))
- {
- dst.sin6_addr = alldhcp;
- broad_uni = "broadcasting";
- } else {
- dst.sin6_addr = state->unicast;
- broad_uni = "unicasting";
+ if (!IN6_IS_ADDR_UNSPECIFIED(&state->unicast)) {
+ switch (state->send->type) {
+ case DHCP6_SOLICIT: /* FALLTHROUGH */
+ case DHCP6_CONFIRM: /* FALLTHROUGH */
+ case DHCP6_REBIND:
+ /* Unicasting is denied for these types. */
+ break;
+ default:
+ broadcast = false;
+ inet_ntop(AF_INET6, &state->unicast, uaddr,
+ sizeof(uaddr));
+ break;
+ }
}
+ dst.sin6_addr = broadcast ? alldhcp : state->unicast;
if (!callback) {
- logdebugx("%s: %s %s with xid 0x%02x%02x%02x",
+ logdebugx("%s: %s %s with xid 0x%02x%02x%02x%s%s",
ifp->name,
- broad_uni,
+ broadcast ? "broadcasting" : "unicasting",
dhcp6_get_op(state->send->type),
state->send->xid[0],
state->send->xid[1],
- state->send->xid[2]);
+ state->send->xid[2],
+ !broadcast ? " " : "",
+ !broadcast ? uaddr : "");
RT = 0;
} else {
if (state->IMD &&
* 1 second grace seems to be the sweet spot. */
if (ifp->flags & IFF_POINTOPOINT)
state->RT += MSEC_PER_SEC;
- broad_uni = "delaying";
} else if (state->RTC == 0)
state->RT = state->IRT * MSEC_PER_SEC;
* ((float)lr / DHCP6_RAND_DIV));
if (ifp->carrier > LINK_DOWN)
- logdebugx("%s: %s %s (xid 0x%02x%02x%02x),"
+ logdebugx("%s: %s %s (xid 0x%02x%02x%02x)%s%s,"
" next in %0.1f seconds",
ifp->name,
- broad_uni,
+ state->IMD != 0 ? "delaying" :
+ broadcast ? "broadcasting" : "unicasting",
dhcp6_get_op(state->send->type),
state->send->xid[0],
state->send->xid[1],
state->send->xid[2],
+ state->IMD == 0 && !broadcast ? " " : "",
+ state->IMD == 0 && !broadcast ? uaddr : "",
(float)RT / MSEC_PER_SEC);
/* Wait the initial delay */
#endif
/* Set the outbound interface */
- if (IN6_ARE_ADDR_EQUAL(&dst.sin6_addr, &alldhcp)) {
+ if (broadcast) {
struct cmsghdr *cm;
struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
#ifdef PRIVSEP
if (IN_PRIVSEP(ifp->ctx)) {
- struct ipv6_addr *ia;
-
- if (IN6_ARE_ADDR_EQUAL(&dst.sin6_addr, &alldhcp))
- ia = lla;
- else {
- /* Find an IA to send from */
- TAILQ_FOREACH(ia, &state->addrs, next) {
- if (ia->flags & IPV6_AF_STALE)
- continue;
- if (ia->addr_flags & IN6_IFF_NOTUSEABLE)
- continue;
- if (ia->ia_type == D6_OPTION_IA_PD)
- continue;
- break;
- }
- }
- if (ia == NULL) {
- if (lla == NULL) {
- logerrx("%s: no address to send from",
- ifp->name);
- return -1;
- }
- ia = lla;
- }
- if (ps_inet_senddhcp6(ia, &msg) == -1)
+ if (ps_inet_senddhcp6(ifp, &msg) == -1)
logerr(__func__);
goto sent;
}
#endif
- if (ctx->dhcp6_fd != -1)
- s = ctx->dhcp6_fd;
- else if (lla != NULL && lla->dhcp6_fd != -1)
- s = lla->dhcp6_fd;
- else {
- logerrx("%s: no socket to send from", ifp->name);
- return -1;
- }
-
- if (sendmsg(s, &msg, 0) == -1) {
+ if (sendmsg(ctx->dhcp6_wfd, &msg, 0) == -1) {
logerr("%s: %s: sendmsg", __func__, ifp->name);
/* Allow DHCPv6 to continue .... the errors
* would be rate limited by the protocol.
int s;
ssize_t bytes;
- s = ia != NULL ? ia->dhcp6_fd : ctx->dhcp6_fd;
+ s = ia != NULL ? ia->dhcp6_fd : ctx->dhcp6_rfd;
bytes = recvmsg(s, &msg, 0);
if (bytes == -1) {
logerr(__func__);
dhcp6_recv(ctx, NULL);
}
+int
+dhcp6_openraw(void)
+{
+ int fd, v;
+
+ fd = socket(PF_INET6, SOCK_RAW | SOCK_CXNB, IPPROTO_UDP);
+ if (fd == -1)
+ return -1;
+
+ v = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &v, sizeof(v)) == -1)
+ return -1;
+
+ v = offsetof(struct udphdr, uh_sum);
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &v, sizeof(v)) == -1)
+ return -1;
+
+ return fd;
+}
+
int
dhcp6_openudp(unsigned int ifindex, struct in6_addr *ia)
{
struct sockaddr_in6 sa;
int n, s;
-#define SOCK_FLAGS SOCK_CLOEXEC | SOCK_NONBLOCK
- s = xsocket(PF_INET6, SOCK_DGRAM | SOCK_FLAGS, IPPROTO_UDP);
-#undef SOCK_FLAGS
+ s = xsocket(PF_INET6, SOCK_DGRAM | SOCK_CXNB, IPPROTO_UDP);
if (s == -1)
goto errexit;
- n = 1;
- if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &n, sizeof(n)) == -1)
- goto errexit;
-
memset(&sa, 0, sizeof(sa));
sa.sin6_family = AF_INET6;
sa.sin6_port = htons(DHCP6_CLIENT_PORT);
if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &n, sizeof(n)) == -1)
goto errexit;
+#ifdef SO_RERROR
+ n = 1;
+ if (setsockopt(s, SOL_SOCKET, SO_RERROR, &n, sizeof(n)) == -1)
+ goto errexit;
+#endif
+
return s;
errexit:
const struct dhcp_compat *dhc;
if ((ctx->options & (DHCPCD_MASTER|DHCPCD_PRIVSEP)) == DHCPCD_MASTER &&
- ctx->dhcp6_fd == -1)
+ ctx->dhcp6_rfd == -1)
{
- 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(__func__);
+ return;
+ }
+ eloop_event_add(ctx->eloop, ctx->dhcp6_rfd, dhcp6_recvctx, ctx);
+ }
+
+ if (!IN_PRIVSEP(ctx) && ctx->dhcp6_wfd == -1) {
+ ctx->dhcp6_wfd = dhcp6_openraw();
+ if (ctx->dhcp6_wfd == -1) {
logerr(__func__);
return;
}
- eloop_event_add(ctx->eloop, ctx->dhcp6_fd, dhcp6_recvctx, ctx);
}
state = D6_STATE(ifp);
break;
}
}
- if (ifp == NULL && ctx->dhcp6_fd != -1) {
- eloop_event_delete(ctx->eloop, ctx->dhcp6_fd);
- close(ctx->dhcp6_fd);
- ctx->dhcp6_fd = -1;
+ if (ifp == NULL && ctx->dhcp6_rfd != -1) {
+ eloop_event_delete(ctx->eloop, ctx->dhcp6_rfd);
+ close(ctx->dhcp6_rfd);
+ ctx->dhcp6_rfd = -1;
}
}
(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 *,
#include "privsep.h"
#include "script.h"
+#ifdef HAVE_CAPSICUM
+#include <sys/capsicum.h>
+#endif
#ifdef HAVE_UTIL_H
#include <util.h>
#endif
static void
dhcpcd_drop(struct interface *ifp, int stop)
{
+ return;
#ifdef DHCP6
dhcp6_drop(ifp, stop ? NULL : "EXPIRE6");
ctx.dev_fd = -1;
#endif
#ifdef INET
- ctx.udp_fd = -1;
+ ctx.udp_rfd = -1;
+ ctx.udp_wfd = -1;
#endif
#if defined(INET6) && !defined(__sun)
ctx.nd_fd = -1;
#endif
#ifdef DHCP6
- ctx.dhcp6_fd = -1;
+ ctx.dhcp6_rfd = -1;
+ ctx.dhcp6_wfd = -1;
#endif
#ifdef PRIVSEP
ctx.ps_root_fd = ctx.ps_data_fd = -1;
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
#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
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);
priv->pf_inet6_fd = -1;
#endif
-#define SOCK_FLAGS (SOCK_CLOEXEC | SOCK_NONBLOCK)
- ctx->link_fd = xsocket(PF_ROUTE, SOCK_RAW | SOCK_FLAGS, AF_UNSPEC);
-#undef SOCK_FLAGS
+ ctx->link_fd = xsocket(PF_ROUTE, SOCK_RAW | SOCK_CXNB, AF_UNSPEC);
if (ctx->link_fd == -1)
return -1;
+#ifdef SO_RERROR
+ n = 1;
+ if (setsockopt(ctx->link_fd, SOL_SOCKET, SO_RERROR, &n,sizeof(n)) == -1)
+ goto errexit;
+#endif
+
/* Ignore our own route(4) messages.
* Sadly there is no way of doing this for route(4) messages
* generated from addresses we add/delete. */
}
TAILQ_INIT(ifs);
-#ifdef HAVE_CAPSICUM
+#if defined(PRIVSEP) && defined(HAVE_CAPSICUM)
if (ctx->options & DHCPCD_PRIVSEP) {
if (ps_root_getifaddrs(ctx, ifaddrs) == -1) {
logerr("ps_root_getifaddrs");
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)
#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);
return NULL;
}
TAILQ_INIT(&state->addrs);
- state->buffer_size = state->buffer_len = state->buffer_pos = 0;
- state->buffer = NULL;
}
return state;
}
TAILQ_REMOVE(&state->addrs, ia, next);
free(ia);
}
- free(state->buffer);
free(state);
}
struct ipv4_state {
struct ipv4_addrhead addrs;
-
- /* Buffer for BPF */
- size_t buffer_size, buffer_len, buffer_pos;
- char *buffer;
};
#define IPV4_STATE(ifp) \
#ifndef __sun
ctx->nd_fd = -1;
#endif
- ctx->dhcp6_fd = -1;
+#ifdef DHCP6
+ ctx->dhcp6_rfd = -1;
+ ctx->dhcp6_wfd = -1;
+#endif
return 0;
}
}
}
-static int
-ipv6nd_open0(void)
+int
+ipv6nd_open(bool recv)
{
int fd, on;
struct icmp6_filter filt;
-#define SOCK_FLAGS SOCK_CLOEXEC | SOCK_NONBLOCK
- fd = xsocket(PF_INET6, SOCK_RAW | SOCK_FLAGS, IPPROTO_ICMPV6);
-#undef SOCK_FLAGS
+ fd = xsocket(PF_INET6, SOCK_RAW | SOCK_CXNB, IPPROTO_ICMPV6);
if (fd == -1)
return -1;
+ ICMP6_FILTER_SETBLOCKALL(&filt);
+
/* RFC4861 4.1 */
on = 255;
if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
&on, sizeof(on)) == -1)
goto eexit;
- on = 1;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
- &on, sizeof(on)) == -1)
- goto eexit;
+ if (recv) {
+ on = 1;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+ &on, sizeof(on)) == -1)
+ goto eexit;
- on = 1;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
- &on, sizeof(on)) == -1)
- goto eexit;
+ on = 1;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
+ &on, sizeof(on)) == -1)
+ goto eexit;
+
+ ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
+
+#ifdef SO_RERROR
+ on = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_RERROR,
+ &on, sizeof(on)) == -1)
+ goto eexit;
+#endif
+ }
- ICMP6_FILTER_SETBLOCKALL(&filt);
- ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER,
&filt, sizeof(filt)) == -1)
goto eexit;
#ifdef __sun
int
-ipv6nd_open(struct interface *ifp)
+ipv6nd_openif(struct interface *ifp)
{
int fd;
struct ipv6_mreq mreq = {
if (state->nd_fd != -1)
return state->nd_fd;
- fd = ipv6nd_open0();
+ fd = ipv6nd_open0(true);
if (fd == -1)
return -1;
eloop_event_add(ifp->ctx->eloop, fd, ipv6nd_handledata, ifp);
return fd;
}
-#else
-int
-ipv6nd_open(struct dhcpcd_ctx *ctx)
-{
- int fd;
-
- if (ctx->nd_fd != -1)
- return ctx->nd_fd;
-
- fd = ipv6nd_open0();
- if (fd == -1)
- return -1;
-
- ctx->nd_fd = fd;
- if (!(IN_PRIVSEP(ctx)))
- eloop_event_add(ctx->eloop, fd, ipv6nd_handledata, ctx);
- return fd;
-}
#endif
static int
struct cmsghdr *cm;
struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
int s;
+ struct dhcpcd_ctx *ctx = ifp->ctx;
if (ipv6_linklocal(ifp) == NULL) {
logdebugx("%s: delaying Router Solicitation for LL address",
#ifdef __sun
s = state->nd_fd;
#else
+ if (ctx->nd_fd == -1) {
+ ctx->nd_fd = ipv6nd_open(true);
+ if (ctx->nd_fd == -1) {
+ logerr(__func__);
+ return;
+ }
+ eloop_event_add(ctx->eloop, ctx->nd_fd, ipv6nd_handledata, ctx);
+ }
s = ifp->ctx->nd_fd;
#endif
if (sendmsg(s, &msg, 0) == -1) {
#endif
}
- if (!(IN_PRIVSEP(ifp->ctx))) {
-#ifdef __sun
- if (ipv6nd_open(ifp) == -1) {
- logerr(__func__);
- return;
- }
-#else
- if (ipv6nd_open(ifp->ctx) == -1) {
- logerr(__func__);
- return;
- }
-#endif
- }
-
/* Always make a new probe as the underlying hardware
* address could have changed. */
ipv6nd_makersprobe(ifp);
#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 *);
ps_bpf_recvbpf(void *arg)
{
struct ps_process *psp = arg;
- unsigned int flags;
- uint8_t buf[FRAMELEN_MAX];
+ struct bpf *bpf = psp->psp_bpf;
+ uint8_t buf[sizeof(bpf->bpf_flags) + FRAMELEN_MAX];
ssize_t len;
struct ps_msghdr psm = {
.ps_id = psp->psp_id,
.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(bpf->bpf_flags),
+ sizeof(buf) - sizeof(bpf->bpf_flags));
if (len == -1)
logerr(__func__);
if (len == -1 || len == 0)
break;
+ memcpy(buf, &bpf->bpf_flags, sizeof(bpf->bpf_flags));
len = ps_sendpsmdata(psp->psp_ctx, psp->psp_ctx->ps_data_fd,
- &psm, buf, (size_t)len);
+ &psm, buf, (size_t)len + sizeof(bpf->bpf_flags));
if (len == -1 && errno != ECONNRESET)
logerr(__func__);
if (len == -1 || len == 0)
}
}
-#ifdef ARP
-#if !defined(HAVE_CAPSICUM) && !defined(HAVE_PLEDGE)
-static ssize_t
-ps_bpf_arp_addr(uint16_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
-#endif
-
static ssize_t
-ps_bpf_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
+ps_bpf_recvmsgcb(void *arg, __unused 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))
-#if !defined(HAVE_CAPSICUM) && !defined(HAVE_PLEDGE)
- return ps_bpf_arp_addr(psm->ps_cmd, psp, msg);
-#else
- return 0;
-#endif
-#endif
-
- return bpf_send(&psp->psp_ifp, psp->psp_work_fd, psp->psp_proto,
+ return bpf_send(psp->psp_bpf, psp->psp_proto,
iov->iov_base, iov->iov_len);
}
{
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;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_EVENT, CAP_IOCTL);
#endif
- setproctitle("[BPF %s] %s", psp->psp_protostr, psp->psp_ifname);
-
+ 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_work_fd, &rights) == -1 &&
+ 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;
{
struct iovec *iov = msg->msg_iov;
struct interface *ifp;
+ uint8_t bpf_flags, *bpf;
+ size_t bpf_len;
ifp = if_findindex(ctx->ifaces, psm->ps_id.psi_ifindex);
+ bpf = iov->iov_base;
+ bpf_len = iov->iov_len;
+ memcpy(&bpf_flags, bpf, sizeof(bpf_flags));
+ bpf += sizeof(bpf_flags);
+ bpf_len -= sizeof(bpf_flags);
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, bpf_flags);
break;
#endif
case PS_BPF_BOOTP:
- dhcp_packet(ifp, iov->iov_base, iov->iov_len);
+ dhcp_packet(ifp, bpf, bpf_len, bpf_flags);
break;
default:
errno = ENOTSUP;
}
static ssize_t
-ps_bpf_send(const struct interface *ifp, uint16_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)
-{
-
- return ps_bpf_send(ifp, PS_BPF_ARP | PS_START, ifp, sizeof(*ifp));
-}
-
-ssize_t
-ps_bpf_addaddr(const struct interface *ifp, const struct in_addr *addr)
+ps_bpf_openarp(const struct interface *ifp, const struct in_addr *ia)
{
- return ps_bpf_send(ifp, PS_BPF_ARP_ADDR | PS_START, addr, sizeof(*addr));
+ assert(ia != NULL);
+ return ps_bpf_send(ifp, ia, PS_BPF_ARP | PS_START,
+ ifp, sizeof(*ifp));
}
ssize_t
-ps_bpf_deladdr(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_DELETE, addr, sizeof(*addr));
+ return ps_bpf_send(ifp, ia, PS_BPF_ARP | PS_STOP, NULL, 0);
}
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)
+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, data, len);
+ assert(ia != NULL);
+ return ps_bpf_send(ifp, ia, PS_BPF_ARP, data, len);
}
#endif
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);
}
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 *);
{
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
{
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
#ifdef HAVE_CAPSICUM
cap_rights_t rights;
- cap_rights_init(&rights, CAP_RECV, CAP_CONNECT, CAP_SEND, CAP_EVENT);
+ cap_rights_init(&rights, CAP_RECV, CAP_EVENT);
#endif
if (ctx->options & DHCPCD_MASTER)
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__);
#ifdef HAVE_CAPSICUM
- else if (cap_rights_limit(ctx->udp_fd, &rights) == -1
+ else if (cap_rights_limit(ctx->udp_rfd, &rights) == -1
&& errno != ENOSYS)
{
logerr("%s: cap_rights_limit", __func__);
- close(ctx->udp_fd);
- ctx->udp_fd = -1;
+ close(ctx->udp_rfd);
+ ctx->udp_rfd = -1;
}
#endif
- else if (eloop_event_add(ctx->eloop, ctx->udp_fd,
+ 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
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__);
#ifdef HAVE_CAPSICUM
- else if (cap_rights_limit(ctx->dhcp6_fd, &rights) == -1
+ else if (cap_rights_limit(ctx->dhcp6_rfd, &rights) == -1
&& errno != ENOSYS)
{
logerr("%s: cap_rights_limit", __func__);
- close(ctx->dhcp6_fd);
- ctx->dhcp6_fd = -1;
+ close(ctx->dhcp6_rfd);
+ ctx->dhcp6_rfd = -1;
}
#endif
- else if (eloop_event_add(ctx->eloop, ctx->dhcp6_fd,
+ 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++;
}
}
static ssize_t
-ps_inet_recvmsg_cb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
+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;
+ s = ctx->udp_wfd;
break;
#endif
#if defined(INET6) && !defined(__sun)
#endif
#ifdef DHCP6
case PS_DHCP6:
- s = ctx->dhcp6_fd;
+ s = ctx->dhcp6_wfd;
break;
#endif
default:
}
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__);
}
PSF_DROPPRIVS);
#ifdef HAVE_CAPSICUM
-#if 0 /* This breaks sendmsg() */
- if (cap_enter() == -1 && errno != ENOSYS)
+ if (pid == 0 && cap_enter() == -1 && errno != ENOSYS)
logerr("%s: cap_enter", __func__);
#endif
-#endif
#ifdef HAVE_PLEDGE
if (pid == 0 && pledge("stdio inet", NULL) == -1)
logerr("%s: pledge", __func__);
#ifdef HAVE_CAPSICUM
cap_rights_t rights;
- cap_rights_init(&rights, CAP_RECV, CAP_CONNECT, CAP_SEND, CAP_EVENT);
+ cap_rights_init(&rights, CAP_RECV, CAP_EVENT);
#endif
inet_ntop(AF_INET, ia, buf, sizeof(buf));
#ifdef HAVE_CAPSICUM
cap_rights_t rights;
- cap_rights_init(&rights, CAP_RECV, CAP_CONNECT, CAP_SEND, CAP_EVENT);
+ cap_rights_init(&rights, CAP_RECV, CAP_EVENT);
#endif
setproctitle("[ND network proxy]");
#ifdef HAVE_CAPSICUM
cap_rights_t rights;
- cap_rights_init(&rights, CAP_RECV, CAP_CONNECT, CAP_SEND, CAP_EVENT);
+ cap_rights_init(&rights, CAP_RECV, CAP_EVENT);
#endif
inet_ntop(AF_INET6, ia, buf, sizeof(buf));
}
#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)
{
uint16_t cmd;
struct ps_process *psp;
pid_t start;
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
return -1;
case 0:
#ifdef HAVE_CAPSICUM
-#if 0 /* This breaks sendmsg() */
if (cap_enter() == -1 && errno != ENOSYS)
logerr("%s: cap_enter", __func__);
#endif
-#endif
#ifdef HAVE_PLEDGE
if (pledge("stdio inet", NULL) == -1)
logerr("%s: pledge", __func__);
}
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 */
ps_inet_sendnd(struct interface *ifp, const struct msghdr *msg)
{
- return ps_sendmsg(ifp->ctx, ifp->ctx->ps_inet_fd, PS_ND, 0, msg);
+ return ps_sendmsg(ifp->ctx, ifp->ctx->ps_root_fd, PS_ND, 0, msg);
}
#endif
}
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 */
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
#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
#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 "dhcpcd.h"
+#include "dhcp6.h"
#include "eloop.h"
#include "if.h"
+#include "ipv6nd.h"
#include "logerr.h"
#include "privsep.h"
#include "sa.h"
ssize_t err;
bool free_rdata= false;
- cmd = (uint16_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);
return ps_sendpsmmsg(ctx, psp->psp_fd, psm, msg);
}
- 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 */
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
+
return 0;
}
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;
close(fd[1]);
if (eloop_event_add(ctx->eloop, ctx->ps_data_fd,
ps_root_dispatch, ctx) == -1)
- logerr(__func__);
+ return -1;
- if ((ctx->ps_eloop = eloop_new()) == NULL) {
- logerr(__func__);
+ 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;
}
switch (pid = ps_root_start(ctx)) {
case -1:
+ logerr("ps_root_start");
return -1;
case 0:
return 0;
void
ps_freeprocess(struct ps_process *psp)
{
-#ifdef INET
- struct ipv4_state *istate = IPV4_STATE(&psp->psp_ifp);
-
- if (istate != NULL) {
- free(istate->buffer);
- free(istate);
- }
-#endif
TAILQ_REMOVE(&psp->psp_ctx->ps_processes, psp, next);
if (psp->psp_fd != -1) {
eloop_event_delete(psp->psp_ctx->eloop, psp->psp_work_fd);
close(psp->psp_work_fd);
}
+#ifdef INET
+ if (psp->psp_bpf != NULL)
+ bpf_close(psp->psp_bpf);
+#endif
free(psp);
}
ps_sendpsmmsg(struct dhcpcd_ctx *ctx, int fd,
struct ps_msghdr *psm, const struct msghdr *msg)
{
- assert(msg == NULL || msg->msg_iovlen == 1);
-
struct iovec iov[] = {
{ .iov_base = UNCONST(psm), .iov_len = sizeof(*psm) },
{ .iov_base = NULL, }, /* name */
{ .iov_base = NULL, }, /* control */
- { .iov_base = NULL, }, /* payload */
+ { .iov_base = NULL, }, /* payload 1 */
+ { .iov_base = NULL, }, /* payload 2 */
+ { .iov_base = NULL, }, /* payload 3 */
};
- int iovlen = __arraycount(iov);
+ int iovlen;
ssize_t len;
if (msg != NULL) {
struct iovec *iovp = &iov[1];
-
- assert(msg->msg_iovlen == 1);
+ size_t i;
psm->ps_namelen = msg->msg_namelen;
psm->ps_controllen = (socklen_t)msg->msg_controllen;
iovp++;
iovp->iov_base = msg->msg_control;
iovp->iov_len = msg->msg_controllen;
- iovp++;
- iovp->iov_base = msg->msg_iov[0].iov_base;
- iovp->iov_len = msg->msg_iov[0].iov_len;
- iovlen = __arraycount(iov);
+ iovlen = 3;
+
+ for (i = 0; i < (size_t)msg->msg_iovlen; i++) {
+ if ((size_t)iovlen + i > __arraycount(iov)) {
+ errno = ENOBUFS;
+ return -1;
+ }
+ iovp++;
+ iovp->iov_base = msg->msg_iov[i].iov_base;
+ iovp->iov_len = msg->msg_iov[i].iov_len;
+ }
+ iovlen += i;
} else
iovlen = 1;
ps_sendmsg(struct dhcpcd_ctx *ctx, int fd, uint16_t cmd, unsigned long flags,
const struct msghdr *msg)
{
- assert(msg->msg_iovlen == 1);
-
struct ps_msghdr psm = {
.ps_cmd = cmd,
.ps_flags = flags,
.ps_namelen = msg->msg_namelen,
.ps_controllen = (socklen_t)msg->msg_controllen,
- .ps_datalen = msg->msg_iov[0].iov_len,
};
+ size_t i;
+
+ for (i = 0; i < (size_t)msg->msg_iovlen; i++)
+ psm.ps_datalen += msg->msg_iov[i].iov_len;
#if 0 /* For debugging structure padding. */
logerrx("psa.family %lu %zu", offsetof(struct ps_addr, psa_family), sizeof(psm.ps_id.psi_addr.psa_family));
if (ps_unrollmsg(&msg, &psm.psm_hdr, psm.psm_data, dlen) == -1)
return -1;
+ if (callback == NULL)
+ return 0;
+
errno = 0;
return callback(cbctx, &psm.psm_hdr, &msg);
}
#define PS_DHCP6 0x0003
#define PS_BPF_BOOTP 0x0004
#define PS_BPF_ARP 0x0005
-#define PS_BPF_ARP_ADDR 0x0006
/* Generic commands */
#define PS_IOCTL 0x0010
#define PS_WRITEPATHUINT 0x0201
/* Process commands */
-#define PS_DELETE 0x2000
#define PS_START 0x4000
#define PS_STOP 0x8000
uint8_t psm_data[PS_BUFLEN];
};
+struct bpf;
struct ps_process {
TAILQ_ENTRY(ps_process) next;
struct dhcpcd_ctx *psp_ctx;
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);