Module Name: src
Committed By: roy
Date: Sun May 31 12:52:11 UTC 2020
Modified Files:
src/external/bsd/dhcpcd/dist/hooks: dhcpcd-run-hooks.in
src/external/bsd/dhcpcd/dist/src: bpf.c dhcp.c dhcp6.c dhcpcd.8.in
dhcpcd.c if-bsd.c if-options.c ipv6.c ipv6.h ipv6nd.c logerr.c
privsep.c script.c
Log Message:
Sync
To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 \
src/external/bsd/dhcpcd/dist/hooks/dhcpcd-run-hooks.in
cvs rdiff -u -r1.14 -r1.15 src/external/bsd/dhcpcd/dist/src/bpf.c
cvs rdiff -u -r1.36 -r1.37 src/external/bsd/dhcpcd/dist/src/dhcp.c \
src/external/bsd/dhcpcd/dist/src/dhcpcd.c
cvs rdiff -u -r1.18 -r1.19 src/external/bsd/dhcpcd/dist/src/dhcp6.c
cvs rdiff -u -r1.5 -r1.6 src/external/bsd/dhcpcd/dist/src/dhcpcd.8.in \
src/external/bsd/dhcpcd/dist/src/script.c
cvs rdiff -u -r1.19 -r1.20 src/external/bsd/dhcpcd/dist/src/if-bsd.c \
src/external/bsd/dhcpcd/dist/src/ipv6nd.c
cvs rdiff -u -r1.23 -r1.24 src/external/bsd/dhcpcd/dist/src/if-options.c
cvs rdiff -u -r1.11 -r1.12 src/external/bsd/dhcpcd/dist/src/ipv6.c
cvs rdiff -u -r1.10 -r1.11 src/external/bsd/dhcpcd/dist/src/ipv6.h
cvs rdiff -u -r1.3 -r1.4 src/external/bsd/dhcpcd/dist/src/logerr.c
cvs rdiff -u -r1.2 -r1.3 src/external/bsd/dhcpcd/dist/src/privsep.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/external/bsd/dhcpcd/dist/hooks/dhcpcd-run-hooks.in
diff -u src/external/bsd/dhcpcd/dist/hooks/dhcpcd-run-hooks.in:1.5 src/external/bsd/dhcpcd/dist/hooks/dhcpcd-run-hooks.in:1.6
--- src/external/bsd/dhcpcd/dist/hooks/dhcpcd-run-hooks.in:1.5 Thu Apr 2 12:41:48 2020
+++ src/external/bsd/dhcpcd/dist/hooks/dhcpcd-run-hooks.in Sun May 31 12:52:11 2020
@@ -211,7 +211,7 @@ valid_domainname_list()
}
# With the advent of alternative init systems, it's possible to have
-# more than one installed. So we need to try and guess what one we're
+# more than one installed. So we need to try to guess what one we're
# using unless overridden by configure.
detect_init()
{
Index: src/external/bsd/dhcpcd/dist/src/bpf.c
diff -u src/external/bsd/dhcpcd/dist/src/bpf.c:1.14 src/external/bsd/dhcpcd/dist/src/bpf.c:1.15
--- src/external/bsd/dhcpcd/dist/src/bpf.c:1.14 Thu Apr 2 12:41:48 2020
+++ src/external/bsd/dhcpcd/dist/src/bpf.c Sun May 31 12:52:11 2020
@@ -57,8 +57,6 @@
#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 */
@@ -85,7 +83,7 @@ size_t
bpf_frame_header_len(const struct interface *ifp)
{
- switch (ifp->family) {
+ switch (ifp->hwtype) {
case ARPHRD_ETHER:
return sizeof(struct ether_header);
default:
@@ -98,7 +96,7 @@ bpf_frame_header_src(const struct interf
{
uint8_t *f = fh;
- switch (ifp->family) {
+ switch (ifp->hwtype) {
case ARPHRD_ETHER:
*len = sizeof(((struct ether_header *)0)->ether_shost);
return f + offsetof(struct ether_header, ether_shost);
@@ -114,7 +112,7 @@ bpf_frame_header_dst(const struct interf
{
uint8_t *f = fh;
- switch (ifp->family) {
+ switch (ifp->hwtype) {
case ARPHRD_ETHER:
*len = sizeof(((struct ether_header *)0)->ether_dhost);
return f + offsetof(struct ether_header, ether_dhost);
@@ -129,12 +127,12 @@ static const uint8_t etherbcastaddr[] =
{ 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->family) {
+ switch (ifp->hwtype) {
case ARPHRD_ETHER:
- return memcmp(frame +
+ return memcmp((const char *)frame +
offsetof(struct ether_header, ether_dhost),
etherbcastaddr, sizeof(etherbcastaddr));
default:
@@ -148,15 +146,15 @@ bpf_frame_bcast(const struct interface *
const char *bpf_name = "Berkley Packet Filter";
-int
-bpf_open(struct interface *ifp, int (*filter)(struct interface *, int))
-{
- struct ipv4_state *state;
- int fd = -1;
- struct ifreq ifr;
+struct bpf *
+bpf_open(const struct interface *ifp,
+ int (*filter)(const struct bpf *, const struct in_addr *),
+ const struct in_addr *ia)
+{
+ 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
@@ -164,8 +162,13 @@ bpf_open(struct interface *ifp, int (*fi
int fd_opts;
#endif
+ bpf = calloc(1, sizeof(*bpf));
+ if (bpf == NULL)
+ return NULL;
+ bpf->bpf_ifp = ifp;
+
#ifdef _PATH_BPF
- fd = open(_PATH_BPF, O_RDWR | O_NONBLOCK
+ bpf->bpf_fd = open(_PATH_BPF, O_RDWR | O_NONBLOCK
#ifdef O_CLOEXEC
| O_CLOEXEC
#endif
@@ -176,27 +179,24 @@ bpf_open(struct interface *ifp, int (*fi
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) {
@@ -204,94 +204,84 @@ bpf_open(struct interface *ifp, int (*fi
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. */
if (bytes == -1 && errno == EINVAL) {
- lseek(fd, 0, SEEK_SET);
+ lseek(bpf->bpf_fd, 0, SEEK_SET);
continue;
}
#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;
@@ -303,29 +293,38 @@ next:
int
bpf_attach(int fd, void *filter, unsigned int filter_len)
{
- struct bpf_program pf;
+ struct bpf_program pf = { .bf_insns = filter, .bf_len = filter_len };
/* Install the filter. */
- memset(&pf, 0, sizeof(pf));
- pf.bf_insns = filter;
- pf.bf_len = filter_len;
return ioctl(fd, BIOCSETF, &pf);
}
+
+#ifdef BIOCSETWF
+static int
+bpf_wattach(int fd, void *filter, unsigned int filter_len)
+{
+ struct bpf_program pf = { .bf_insns = filter, .bf_len = filter_len };
+
+ /* Install the filter. */
+ return ioctl(fd, BIOCSETWF, &pf);
+}
+#endif
#endif
#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->family) {
+ 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);
@@ -337,27 +336,24 @@ bpf_send(const struct interface *ifp, in
}
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)
{
- struct ipv4_state *state = IPV4_STATE(ifp);
- /* Rewind the buffer on closing. */
- state->buffer_len = state->buffer_pos = 0;
- return close(fd);
+ close(bpf->bpf_fd);
+ free(bpf->bpf_buffer);
+ free(bpf);
}
-/* Normally this is needed by bootp.
- * Once that uses this again, the ARP guard here can be removed. */
#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, uint8_t *hwaddr, size_t hwaddr_len)
+ bool equal, const uint8_t *hwaddr, size_t hwaddr_len)
{
struct bpf_insn *bp;
size_t maclen, nlft, njmps;
@@ -451,7 +447,7 @@ static const struct bpf_insn bpf_arp_eth
/* Load frame header length into X */
BPF_STMT(BPF_LDX + BPF_W + BPF_IMM, sizeof(struct ether_header)),
- /* Make sure the hardware family matches. */
+ /* Make sure the hardware type matches. */
BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_hrd)),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0),
BPF_STMT(BPF_RET + BPF_K, 0),
@@ -482,28 +478,24 @@ static const struct bpf_insn bpf_arp_fil
};
#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 + \
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];
+ const struct interface *ifp = bpf->bpf_ifp;
+ struct bpf_insn buf[BPF_ARP_LEN + 1];
struct bpf_insn *bp;
- struct iarp_state *state;
uint16_t arp_len;
- struct arp_state *astate;
- size_t naddrs;
-
- if (fd == -1)
- return 0;
- bp = bpf;
+ bp = buf;
/* Check frame header. */
- switch(ifp->family) {
+ switch(ifp->hwtype) {
case ARPHRD_ETHER:
memcpy(bp, bpf_arp_ether, sizeof(bpf_arp_ether));
bp += BPF_ARP_ETHER_LEN;
@@ -520,32 +512,16 @@ bpf_arp(struct interface *ifp, int fd)
/* Ensure it's not from us. */
bp += bpf_cmp_hwaddr(bp, BPF_CMP_HWADDR_LEN, sizeof(struct arphdr),
- false, ifp->hwaddr, ifp->hwlen);
-
- state = ARP_STATE(ifp);
- /* privsep may not have an initial state yet. */
- if (state == NULL || TAILQ_FIRST(&state->arp_states) == NULL)
- goto noaddrs;
+ !recv, ifp->hwaddr, ifp->hwlen);
/* Match sender protocol address */
BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND,
- sizeof(struct arphdr) + ifp->hwlen);
+ 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++;
- naddrs = 0;
- TAILQ_FOREACH(astate, &state->arp_states, next) {
- if (IN_IS_ADDR_UNSPECIFIED(&astate->addr))
- continue;
- if (++naddrs > ARP_ADDRS_MAX) {
- errno = ENOBUFS;
- logerr(__func__);
- break;
- }
- BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
- htonl(astate->addr.s_addr), 0, 1);
- bp++;
- BPF_SET_STMT(bp, BPF_RET + BPF_K, arp_len);
- bp++;
- }
/* If we didn't match sender, then we're only interested in
* ARP probes to us, so check the null host sender. */
@@ -555,29 +531,39 @@ bpf_arp(struct interface *ifp, int fd)
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)));
+ 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++;
- naddrs = 0;
- TAILQ_FOREACH(astate, &state->arp_states, next) {
- if (++naddrs > ARP_ADDRS_MAX) {
- /* Already logged error above. */
- break;
- }
- BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
- htonl(astate->addr.s_addr), 0, 1);
- bp++;
- BPF_SET_STMT(bp, BPF_RET + BPF_K, arp_len);
- bp++;
- }
-noaddrs:
- /* Return nothing, no protocol address match. */
+ /* No match, drop it */
BPF_SET_STMT(bp, BPF_RET + BPF_K, 0);
bp++;
- return bpf_attach(fd, bpf, (unsigned int)(bp - bpf));
+#ifdef BIOCSETWF
+ 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
@@ -602,7 +588,7 @@ static const struct bpf_insn bpf_bootp_e
#define BOOTP_MIN_SIZE sizeof(struct ip) + sizeof(struct udphdr) + \
sizeof(struct bootp)
-static const struct bpf_insn bpf_bootp_filter[] = {
+static const struct bpf_insn bpf_bootp_base[] = {
/* Make sure it's an IPv4 packet. */
BPF_STMT(BPF_LD + BPF_B + BPF_IND, 0),
BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0xf0),
@@ -625,35 +611,43 @@ static const struct bpf_insn bpf_bootp_f
BPF_STMT(BPF_ALU + BPF_MUL + BPF_K, 4),
BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0),
BPF_STMT(BPF_MISC + BPF_TAX, 0),
+};
+#define BPF_BOOTP_BASE_LEN __arraycount(bpf_bootp_base)
+static const struct bpf_insn bpf_bootp_read[] = {
/* Make sure it's from and to the right port. */
BPF_STMT(BPF_LD + BPF_W + BPF_IND, 0),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (BOOTPS << 16) + BOOTPC, 1, 0),
BPF_STMT(BPF_RET + BPF_K, 0),
};
+#define BPF_BOOTP_READ_LEN __arraycount(bpf_bootp_read)
+
+#ifdef BIOCSETWF
+static const struct bpf_insn bpf_bootp_write[] = {
+ /* Make sure it's from and to the right port. */
+ BPF_STMT(BPF_LD + BPF_W + BPF_IND, 0),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (BOOTPC << 16) + BOOTPS, 1, 0),
+ BPF_STMT(BPF_RET + BPF_K, 0),
+};
+#define BPF_BOOTP_WRITE_LEN __arraycount(bpf_bootp_write)
+#endif
-#define BPF_BOOTP_FILTER_LEN __arraycount(bpf_bootp_filter)
#define BPF_BOOTP_CHADDR_LEN ((BOOTP_CHADDR_LEN / 4) * 3)
#define BPF_BOOTP_XID_LEN 4 /* BOUND check is 4 instructions */
-#define BPF_BOOTP_LEN BPF_BOOTP_ETHER_LEN + BPF_BOOTP_FILTER_LEN \
- + BPF_BOOTP_XID_LEN + BPF_BOOTP_CHADDR_LEN + 4
+#define BPF_BOOTP_LEN BPF_BOOTP_ETHER_LEN + \
+ BPF_BOOTP_BASE_LEN + BPF_BOOTP_READ_LEN + \
+ BPF_BOOTP_XID_LEN + BPF_BOOTP_CHADDR_LEN + 4
-int
-bpf_bootp(struct interface *ifp, int fd)
+static int
+bpf_bootp_rw(const struct bpf *bpf, bool read)
{
-#if 0
- const struct dhcp_state *state = D_CSTATE(ifp);
-#endif
- struct bpf_insn bpf[BPF_BOOTP_LEN];
+ 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->family) {
+ switch(bpf->bpf_ifp->hwtype) {
#ifdef ARPHRD_NONE
case ARPHRD_NONE:
memcpy(bp, bpf_bootp_none, sizeof(bpf_bootp_none));
@@ -670,48 +664,45 @@ bpf_bootp(struct interface *ifp, int fd)
}
/* Copy in the main filter. */
- memcpy(bp, bpf_bootp_filter, sizeof(bpf_bootp_filter));
- bp += BPF_BOOTP_FILTER_LEN;
+ memcpy(bp, bpf_bootp_base, sizeof(bpf_bootp_base));
+ bp += BPF_BOOTP_BASE_LEN;
- /* These checks won't work when same IP exists on other interfaces. */
-#if 0
- if (ifp->hwlen <= sizeof(((struct bootp *)0)->chaddr))
- bp += bpf_cmp_hwaddr(bp, BPF_BOOTP_CHADDR_LEN,
- offsetof(struct bootp, chaddr),
- true, ifp->hwaddr, ifp->hwlen);
-
- /* Make sure the BOOTP packet is for us. */
- if (state->state == DHS_BOUND) {
- /* If bound, we only expect FORCERENEW messages
- * and they need to be unicast to us.
- * Move back to the IP header in M0 and check dst. */
- BPF_SET_STMT(bp, BPF_LDX + BPF_W + BPF_MEM, 0);
- bp++;
- BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND,
- offsetof(struct ip, ip_dst));
- bp++;
- BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
- htonl(state->lease.addr.s_addr), 1, 0);
- bp++;
- BPF_SET_STMT(bp, BPF_RET + BPF_K, 0);
- bp++;
- } else {
- /* As we're not bound, we need to check xid to ensure
- * it's a reply to our transaction. */
- BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND,
- offsetof(struct bootp, xid));
- bp++;
- BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
- state->xid, 1, 0);
- bp++;
- BPF_SET_STMT(bp, BPF_RET + BPF_K, 0);
+#ifdef BIOCSETWF
+ if (!read) {
+ memcpy(bp, bpf_bootp_write, sizeof(bpf_bootp_write));
+ bp += BPF_BOOTP_WRITE_LEN;
+
+ /* All passed, return the packet. */
+ BPF_SET_STMT(bp, BPF_RET + BPF_K, BPF_WHOLEPACKET);
bp++;
+
+ return bpf_wattach(bpf->bpf_fd, buf, (unsigned int)(bp - buf));
}
+#else
+ UNUSED(read);
#endif
+ memcpy(bp, bpf_bootp_read, sizeof(bpf_bootp_read));
+ bp += BPF_BOOTP_READ_LEN;
+
/* All passed, return the packet. */
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(const struct bpf *bpf, __unused const struct in_addr *ia)
+{
+
+#ifdef BIOCSETWF
+ 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(bpf, true);
+#endif
}
Index: src/external/bsd/dhcpcd/dist/src/dhcp.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcp.c:1.36 src/external/bsd/dhcpcd/dist/src/dhcp.c:1.37
--- src/external/bsd/dhcpcd/dist/src/dhcp.c:1.36 Tue Apr 21 09:55:33 2020
+++ src/external/bsd/dhcpcd/dist/src/dhcp.c Sun May 31 12:52:11 2020
@@ -28,7 +28,6 @@
#include <sys/param.h>
#include <sys/socket.h>
-#include <sys/stat.h>
#include <arpa/inet.h>
#include <net/if.h>
@@ -503,7 +502,7 @@ print_rfc3361(FILE *fp, const uint8_t *d
memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
if (fprintf(fp, "%s", inet_ntoa(addr)) == -1)
return -1;
- if (dl != 0) {
+ if (dl != sizeof(addr.s_addr)) {
if (fputc(' ', fp) == EOF)
return -1;
}
@@ -782,7 +781,7 @@ make_message(struct bootp **bootpm, cons
bootp->ciaddr = state->addr->addr.s_addr;
bootp->op = BOOTREQUEST;
- bootp->htype = (uint8_t)ifp->family;
+ bootp->htype = (uint8_t)ifp->hwtype;
if (ifp->hwlen != 0 && ifp->hwlen < sizeof(bootp->chaddr)) {
bootp->hlen = (uint8_t)ifp->hwlen;
memcpy(&bootp->chaddr, &ifp->hwaddr, ifp->hwlen);
@@ -1142,30 +1141,15 @@ toobig:
return -1;
}
-static ssize_t
-write_lease(const struct interface *ifp, const struct bootp *bootp, size_t len)
-{
- int fd;
- ssize_t bytes;
- const struct dhcp_state *state = D_CSTATE(ifp);
-
- logdebugx("%s: writing lease `%s'", ifp->name, state->leasefile);
-
- fd = open(state->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (fd == -1)
- return -1;
- bytes = write(fd, bootp, len);
- close(fd);
- return bytes;
-}
-
static size_t
read_lease(struct interface *ifp, struct bootp **bootp)
{
- int fd;
- bool fd_opened;
+ union {
+ struct bootp bootp;
+ uint8_t buf[FRAMELEN_MAX];
+ } buf;
struct dhcp_state *state = D_STATE(ifp);
- struct bootp *lease;
+ ssize_t sbytes;
size_t bytes;
uint8_t type;
#ifdef AUTH
@@ -1177,29 +1161,20 @@ read_lease(struct interface *ifp, struct
*bootp = NULL;
if (state->leasefile[0] == '\0') {
- fd = fileno(stdin);
- fd_opened = false;
+ logdebugx("reading standard input");
+ sbytes = read(fileno(stdin), buf.buf, sizeof(buf.buf));
} else {
- fd = open(state->leasefile, O_RDONLY);
- fd_opened = true;
+ logdebugx("%s: reading lease `%s'",
+ ifp->name, state->leasefile);
+ sbytes = dhcp_readfile(ifp->ctx, state->leasefile,
+ buf.buf, sizeof(buf.buf));
}
- if (fd == -1) {
+ if (sbytes == -1) {
if (errno != ENOENT)
- logerr("%s: open `%s'",
- ifp->name, state->leasefile);
+ logerr("%s: %s", ifp->name, state->leasefile);
return 0;
}
- if (state->leasefile[0] == '\0')
- logdebugx("reading standard input");
- else
- logdebugx("%s: reading lease `%s'",
- ifp->name, state->leasefile);
-
- bytes = dhcp_read_lease_fd(fd, (void **)&lease);
- if (fd_opened)
- close(fd);
- if (bytes == 0)
- return 0;
+ bytes = (size_t)sbytes;
/* Ensure the packet is at lease BOOTP sized
* with a vendor area of 4 octets
@@ -1207,7 +1182,6 @@ read_lease(struct interface *ifp, struct
* code should not be needed, but of course people could
* scribble whatever in the stored lease file. */
if (bytes < DHCP_MIN_LEN) {
- free(lease);
logerrx("%s: %s: truncated lease", ifp->name, __func__);
return 0;
}
@@ -1216,20 +1190,19 @@ read_lease(struct interface *ifp, struct
goto out;
/* We may have found a BOOTP server */
- if (get_option_uint8(ifp->ctx, &type, (struct bootp *)lease, bytes,
+ if (get_option_uint8(ifp->ctx, &type, &buf.bootp, bytes,
DHO_MESSAGETYPE) == -1)
type = 0;
#ifdef AUTH
/* Authenticate the message */
- auth = get_option(ifp->ctx, (struct bootp *)lease, bytes,
+ auth = get_option(ifp->ctx, &buf.bootp, bytes,
DHO_AUTHENTICATION, &auth_len);
if (auth) {
if (dhcp_auth_validate(&state->auth, &ifp->options->auth,
- lease, bytes, 4, type, auth, auth_len) == NULL)
+ &buf.bootp, bytes, 4, type, auth, auth_len) == NULL)
{
logerr("%s: authentication failed", ifp->name);
- free(lease);
return 0;
}
if (state->auth.token)
@@ -1241,13 +1214,17 @@ read_lease(struct interface *ifp, struct
DHCPCD_AUTH_SENDREQUIRE)
{
logerrx("%s: authentication now required", ifp->name);
- free(lease);
return 0;
}
#endif
out:
- *bootp = (struct bootp *)lease;
+ *bootp = malloc(bytes);
+ if (*bootp == NULL) {
+ logerr(__func__);
+ return 0;
+ }
+ memcpy(*bootp, buf.buf, bytes);
return bytes;
}
@@ -1560,16 +1537,15 @@ dhcp_close(struct interface *ifp)
}
#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->udp_fd != -1) {
- eloop_event_delete(ctx->eloop, state->udp_fd);
- close(state->udp_fd);
- state->udp_fd = -1;
+ if (state->bpf != NULL) {
+ eloop_event_delete(ctx->eloop, state->bpf->bpf_fd);
+ bpf_close(state->bpf);
+ state->bpf = NULL;
+ }
+ if (state->udp_rfd != -1) {
+ eloop_event_delete(ctx->eloop, state->udp_rfd);
+ close(state->udp_rfd);
+ state->udp_rfd = -1;
}
state->interval = 0;
@@ -1582,7 +1558,7 @@ dhcp_openudp(struct in_addr *ia)
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;
@@ -1595,6 +1571,11 @@ dhcp_openudp(struct in_addr *ia)
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);
@@ -1692,33 +1673,28 @@ dhcp_sendudp(struct interface *ifp, stru
.sin_len = sizeof(sin),
#endif
};
+ struct udphdr udp = {
+ .uh_sport = htons(BOOTPC),
+ .uh_dport = htons(BOOTPS),
+ .uh_ulen = htons((uint16_t)(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
@@ -1794,8 +1770,7 @@ send_message(struct interface *ifp, uint
* 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);
@@ -1814,8 +1789,7 @@ send_message(struct interface *ifp, uint
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
@@ -1929,7 +1903,7 @@ dhcp_expire1(struct interface *ifp)
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
dhcp_drop(ifp, "EXPIRE");
- unlink(state->leasefile);
+ dhcp_unlink(ifp->ctx, state->leasefile);
state->interval = 0;
if (!(ifp->options->options & DHCPCD_LINK) || ifp->carrier > LINK_DOWN)
dhcp_discover(ifp);
@@ -2041,10 +2015,6 @@ dhcp_finish_dad(struct interface *ifp, s
}
#endif
- /* If we forked, stop here. */
- if (ifp->ctx->options & DHCPCD_FORKED)
- return;
-
#ifdef IPV4LL
/* Stop IPv4LL now we have a working DHCP address */
ipv4ll_drop(ifp);
@@ -2072,7 +2042,7 @@ dhcp_addr_duplicated(struct interface *i
/* RFC 2131 3.1.5, Client-server interaction */
logerrx("%s: DAD detected %s", ifp->name, inet_ntoa(*ia));
- unlink(state->leasefile);
+ dhcp_unlink(ifp->ctx, state->leasefile);
if (!(opts & DHCPCD_STATIC) && !state->lease.frominfo)
dhcp_decline(ifp);
#ifdef IN_IFF_DUPLICATED
@@ -2096,35 +2066,91 @@ dhcp_addr_duplicated(struct interface *i
}
#endif
-#if defined(ARP) && (!defined(KERNEL_RFC5227) || defined(ARPING))
+#ifdef ARP
+#ifdef KERNEL_RFC5227
static void
-dhcp_arp_not_found(struct arp_state *astate)
+dhcp_arp_announced(struct arp_state *state)
{
- struct interface *ifp;
+
+ arp_free(state);
+}
+#else
+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 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;
-#endif
+ struct arp_state *astate;
+ struct in_addr addr;
- 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) {
- struct in_addr addr = {
- .s_addr = ifo->arping[state->arping_index]
- };
- arp_change(astate, &addr);
- arp_probe(astate);
- return;
- }
- arp_free(astate);
+ 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
+ if (dhcp_arping(ifp) == 1) {
+ arp_free(astate);
return;
}
#endif
@@ -2174,15 +2200,8 @@ dhcp_arp_found(struct arp_state *astate,
arp_free(astate);
dhcp_addr_duplicated(ifp, &addr);
}
+#endif
-#ifdef KERNEL_RFC5227
-static void
-dhcp_arp_announced(struct arp_state *state)
-{
-
- arp_free(state);
-}
-#endif /* KERNEL_RFC5227 */
#endif /* ARP */
void
@@ -2253,7 +2272,7 @@ dhcp_bind(struct interface *ifp)
"rebind time, forcing to %"PRIu32" seconds",
ifp->name, lease->renewaltime);
}
- if (state->addr &&
+ if (state->state == DHS_RENEW && state->addr &&
lease->addr.s_addr == state->addr->addr.s_addr &&
!(state->added & STATE_FAKE))
logdebugx("%s: leased %s for %"PRIu32" seconds",
@@ -2299,9 +2318,13 @@ dhcp_bind(struct interface *ifp)
}
state->state = DHS_BOUND;
if (!state->lease.frominfo &&
- !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))
- if (write_lease(ifp, state->new, state->new_len) == -1)
- logerr("write_lease: %s", state->leasefile);
+ !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))) {
+ logdebugx("%s: writing lease `%s'",
+ ifp->name, state->leasefile);
+ if (dhcp_writefile(ifp->ctx, state->leasefile, 0640,
+ state->new, state->new_len) == -1)
+ logerr("dhcp_writefile: %s", state->leasefile);
+ }
/* Close the BPF filter as we can now receive DHCP messages
* on a UDP socket. */
@@ -2328,8 +2351,8 @@ dhcp_bind(struct interface *ifp)
}
#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,
@@ -2338,7 +2361,7 @@ dhcp_bind(struct interface *ifp)
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
@@ -2350,9 +2373,6 @@ dhcp_lastlease(void *arg)
loginfox("%s: timed out contacting a DHCP server, using last lease",
ifp->name);
dhcp_bind(ifp);
- /* If we forked, stop here. */
- if (ifp->ctx->options & DHCPCD_FORKED)
- return;
state->interval = 0;
dhcp_discover(ifp);
}
@@ -2385,41 +2405,6 @@ dhcp_message_new(struct bootp **bootp,
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)
@@ -2686,11 +2671,7 @@ dhcp_reboot(struct interface *ifp)
!(ia->addr_flags & IN_IFF_NOTUSEABLE) &&
#endif
dhcp_activeaddr(ifp, &state->lease.addr) == 0)
- {
arp_ifannounceaddr(ifp, &state->lease.addr);
- if (ifp->ctx->options & DHCPCD_FORKED)
- return;
- }
#endif
dhcp_new_xid(ifp);
@@ -2749,7 +2730,7 @@ dhcp_drop(struct interface *ifp, const c
return;
state->state = DHS_RELEASE;
- unlink(state->leasefile);
+ dhcp_unlink(ifp->ctx, state->leasefile);
if (ifp->carrier > LINK_DOWN &&
state->new != NULL &&
state->lease.server.s_addr != INADDR_ANY)
@@ -2772,6 +2753,10 @@ dhcp_drop(struct interface *ifp, const c
dhcp_auth_reset(&state->auth);
#endif
+ /* Close DHCP ports so a changed interface family is picked
+ * up by a new BPF state. */
+ dhcp_close(ifp);
+
state->state = DHS_NONE;
free(state->offer);
state->offer = NULL;
@@ -3110,7 +3095,7 @@ dhcp_handledhcp(struct interface *ifp, s
return;
if (!(ifp->ctx->options & DHCPCD_TEST)) {
dhcp_drop(ifp, "NAK");
- unlink(state->leasefile);
+ dhcp_unlink(ifp->ctx, state->leasefile);
}
/* If we constantly get NAKS then we should slowly back off */
@@ -3251,7 +3236,7 @@ dhcp_handledhcp(struct interface *ifp, s
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);
@@ -3390,9 +3375,11 @@ checksums_valid(void *packet,
struct ip ip;
uint16_t w[sizeof(struct ip) / 2];
} pip = {
- .ip.ip_p = IPPROTO_UDP,
- .ip.ip_src = ip->ip_src,
- .ip.ip_dst = ip->ip_dst,
+ .ip = {
+ .ip_p = IPPROTO_UDP,
+ .ip_src = ip->ip_src,
+ .ip_dst = ip->ip_dst,
+ }
};
size_t ip_hlen;
struct udphdr udp;
@@ -3466,15 +3453,16 @@ dhcp_handlebootp(struct interface *ifp,
}
void
-dhcp_packet(struct interface *ifp, uint8_t *data, size_t len)
+dhcp_packet(struct interface *ifp, uint8_t *data, size_t len,
+ unsigned int 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) {
@@ -3490,8 +3478,8 @@ dhcp_packet(struct interface *ifp, uint8
/* 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;
@@ -3507,7 +3495,7 @@ dhcp_packet(struct interface *ifp, uint8
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;
@@ -3531,15 +3519,11 @@ dhcp_readbpf(void *arg)
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);
@@ -3547,13 +3531,13 @@ dhcp_readbpf(void *arg)
}
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
@@ -3577,7 +3561,7 @@ dhcp_recvmsg(struct dhcpcd_ctx *ctx, str
return;
}
- if (state->bpf_fd != -1) {
+ if (state->bpf != NULL) {
/* Avoid a duplicate read if BPF is open for the interface. */
return;
}
@@ -3595,7 +3579,7 @@ dhcp_recvmsg(struct dhcpcd_ctx *ctx, str
}
#endif
- dhcp_handlebootp(ifp, (struct bootp *)iov->iov_base, iov->iov_len,
+ dhcp_handlebootp(ifp, iov->iov_base, iov->iov_len,
&from->sin_addr);
}
@@ -3604,10 +3588,13 @@ dhcp_readudp(struct dhcpcd_ctx *ctx, str
{
const struct dhcp_state *state;
struct sockaddr_in from;
- unsigned char buf[10 * 1024]; /* Maximum MTU */
+ union {
+ struct bootp bootp;
+ uint8_t buf[10 * 1024]; /* Maximum MTU */
+ } iovbuf;
struct iovec iov = {
- .iov_base = buf,
- .iov_len = sizeof(buf),
+ .iov_base = iovbuf.buf,
+ .iov_len = sizeof(iovbuf.buf),
};
union {
struct cmsghdr hdr;
@@ -3620,16 +3607,16 @@ dhcp_readudp(struct dhcpcd_ctx *ctx, str
struct msghdr msg = {
.msg_name = &from, .msg_namelen = sizeof(from),
.msg_iov = &iov, .msg_iovlen = 1,
- .msg_control = buf, .msg_controllen = sizeof(cmsgbuf.buf),
+ .msg_control = cmsgbuf.buf, .msg_controllen = sizeof(cmsgbuf.buf),
};
int s;
ssize_t bytes;
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) {
@@ -3674,11 +3661,11 @@ dhcp_openbpf(struct interface *ifp)
}
#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
@@ -3690,7 +3677,7 @@ dhcp_openbpf(struct interface *ifp)
}
eloop_event_add(ifp->ctx->eloop,
- state->bpf_fd, dhcp_readbpf, ifp);
+ state->bpf->bpf_fd, dhcp_readbpf, ifp);
return 0;
}
@@ -3724,10 +3711,14 @@ dhcp_free(struct interface *ifp)
}
}
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);
@@ -3751,8 +3742,7 @@ dhcp_initstate(struct interface *ifp)
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
@@ -3763,7 +3753,7 @@ static int
dhcp_init(struct interface *ifp)
{
struct dhcp_state *state;
- const struct if_options *ifo;
+ struct if_options *ifo;
uint8_t len;
char buf[(sizeof(ifo->clientid) - 1) * 3];
@@ -3781,7 +3771,7 @@ dhcp_init(struct interface *ifp)
/* We need to drop the leasefile so that dhcp_start
* doesn't load it. */
if (ifo->options & DHCPCD_REQUEST)
- unlink(state->leasefile);
+ dhcp_unlink(ifp->ctx, state->leasefile);
free(state->clientid);
state->clientid = NULL;
@@ -3823,7 +3813,7 @@ dhcp_init(struct interface *ifp)
if (state->clientid == NULL)
goto eexit;
state->clientid[0] = len;
- state->clientid[1] = (uint8_t)ifp->family;
+ state->clientid[1] = (uint8_t)ifp->hwtype;
memcpy(state->clientid + 2, ifp->hwaddr,
ifp->hwlen);
}
@@ -3834,7 +3824,7 @@ dhcp_init(struct interface *ifp)
* at device start. */
return 0;
- if (ifo->options & DHCPCD_CLIENTID)
+ if (ifo->options & DHCPCD_CLIENTID && state->clientid != NULL)
logdebugx("%s: using ClientID %s", ifp->name,
hwaddr_ntoa(state->clientid + 1, state->clientid[0],
buf, sizeof(buf)));
@@ -3855,7 +3845,6 @@ dhcp_start1(void *arg)
struct dhcpcd_ctx *ctx = ifp->ctx;
struct if_options *ifo = ifp->options;
struct dhcp_state *state;
- struct stat st;
uint32_t l;
int nolease;
@@ -3867,14 +3856,21 @@ dhcp_start1(void *arg)
* 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) {
@@ -3891,11 +3887,7 @@ dhcp_start1(void *arg)
#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
@@ -3940,6 +3932,7 @@ dhcp_start1(void *arg)
}
if (state->offer) {
struct ipv4_addr *ia;
+ time_t mtime;
get_lease(ifp, &state->lease, state->offer, state->offer_len);
state->lease.frominfo = 1;
@@ -3967,14 +3960,14 @@ dhcp_start1(void *arg)
state->offer_len = 0;
} else if (!(ifo->options & DHCPCD_LASTLEASE_EXTEND) &&
state->lease.leasetime != DHCP_INFINITE_LIFETIME &&
- stat(state->leasefile, &st) == 0)
+ dhcp_filemtime(ifp->ctx, state->leasefile, &mtime) == 0)
{
time_t now;
/* Offset lease times and check expiry */
now = time(NULL);
if (now == -1 ||
- (time_t)state->lease.leasetime < now - st.st_mtime)
+ (time_t)state->lease.leasetime < now - mtime)
{
logdebugx("%s: discarding expired lease",
ifp->name);
@@ -3999,7 +3992,7 @@ dhcp_start1(void *arg)
dhcp_drop(ifp, "EXPIRE");
#endif
} else {
- l = (uint32_t)(now - st.st_mtime);
+ l = (uint32_t)(now - mtime);
state->lease.leasetime -= l;
state->lease.renewaltime -= l;
state->lease.rebindtime -= l;
@@ -4043,7 +4036,7 @@ dhcp_start(struct interface *ifp)
/* If we haven't specified a ClientID and our hardware address
* length is greater than BOOTP CHADDR then we enforce a ClientID
- * of the hardware address family and the hardware address.
+ * of the hardware address type and the hardware address.
* If there is no hardware address and no ClientID set,
* force a DUID based ClientID. */
if (ifp->hwlen > 16)
@@ -4053,7 +4046,7 @@ dhcp_start(struct interface *ifp)
/* Firewire and InfiniBand interfaces require ClientID and
* the broadcast option being set. */
- switch (ifp->family) {
+ switch (ifp->hwtype) {
case ARPHRD_IEEE1394: /* FALLTHROUGH */
case ARPHRD_INFINIBAND:
ifp->options->options |= DHCPCD_CLIENTID | DHCPCD_BROADCAST;
@@ -4105,7 +4098,8 @@ dhcp_abort(struct interface *ifp)
if (state != NULL && state->added) {
rt_build(ifp->ctx, AF_INET);
#ifdef ARP
- arp_announceaddr(ifp->ctx, &state->addr->addr);
+ if (ifp->options->options & DHCPCD_ARP)
+ arp_announceaddr(ifp->ctx, &state->addr->addr);
#endif
}
}
Index: src/external/bsd/dhcpcd/dist/src/dhcpcd.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.36 src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.37
--- src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.36 Sun May 10 17:58:16 2020
+++ src/external/bsd/dhcpcd/dist/src/dhcpcd.c Sun May 31 12:52:11 2020
@@ -71,6 +71,9 @@ const char dhcpcd_copyright[] = "Copyrig
#include "privsep.h"
#include "script.h"
+#ifdef HAVE_CAPSICUM
+#include <sys/capsicum.h>
+#endif
#ifdef HAVE_UTIL_H
#include <util.h>
#endif
@@ -80,17 +83,23 @@ const int dhcpcd_signals[] = {
SIGTERM,
SIGINT,
SIGALRM,
- SIGPIPE,
SIGHUP,
SIGUSR1,
SIGUSR2,
};
const size_t dhcpcd_signals_len = __arraycount(dhcpcd_signals);
+
+const int dhcpcd_signals_ignore[] = {
+ SIGPIPE,
+};
+const size_t dhcpcd_signals_ignore_len = __arraycount(dhcpcd_signals_ignore);
#endif
#define IF_UPANDRUNNING(a) \
(((a)->flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING))
+const char *dhcpcd_default_script = SCRIPT;
+
static void
usage(void)
{
@@ -349,7 +358,7 @@ dhcpcd_daemonise(struct dhcpcd_ctx *ctx)
/* Don't use loginfo because this makes no sense in a log. */
if (!(loggetopts() & LOGERR_QUIET))
- fprintf(stderr, "forked to background, child pid %d\n",
+ (void)fprintf(stderr, "forked to background, child pid %d\n",
getpid());
i = EXIT_SUCCESS;
if (write(ctx->fork_fd, &i, sizeof(i)) == -1)
@@ -358,8 +367,17 @@ dhcpcd_daemonise(struct dhcpcd_ctx *ctx)
eloop_event_delete(ctx->eloop, ctx->fork_fd);
close(ctx->fork_fd);
ctx->fork_fd = -1;
- freopen(_PATH_DEVNULL, "w", stdout);
- freopen(_PATH_DEVNULL, "w", stderr);
+#ifdef PRIVSEP
+ if (ctx->options & DHCPCD_PRIVSEP) {
+ /* Aside from Linux, we don't have access to /dev/null */
+ fclose(stdout);
+ fclose(stderr);
+ } else
+#endif
+ {
+ (void)freopen(_PATH_DEVNULL, "w", stdout);
+ (void)freopen(_PATH_DEVNULL, "w", stderr);
+ }
#endif
}
@@ -826,12 +844,27 @@ warn_iaid_conflict(struct interface *ifp
ifp->name, ifn->name);
}
+static void
+dhcpcd_initduid(struct dhcpcd_ctx *ctx, struct interface *ifp)
+{
+ char buf[DUID_LEN * 3];
+
+ if (ctx->duid != NULL)
+ return;
+
+ duid_init(ctx, ifp);
+ if (ctx->duid == NULL)
+ return;
+
+ loginfox("DUID %s",
+ hwaddr_ntoa(ctx->duid, ctx->duid_len, buf, sizeof(buf)));
+}
+
void
dhcpcd_startinterface(void *arg)
{
struct interface *ifp = arg;
struct if_options *ifo = ifp->options;
- char buf[DUID_LEN * 3];
int carrier;
if (ifo->options & DHCPCD_LINK) {
@@ -864,26 +897,21 @@ dhcpcd_startinterface(void *arg)
if (ifo->options & (DHCPCD_DUID | DHCPCD_IPV6) &&
!(ifo->options & DHCPCD_ANONYMOUS))
{
+ char buf[sizeof(ifo->iaid) * 3];
#ifdef INET6
size_t i;
struct if_ia *ia;
#endif
- /* Report client DUID */
- if (ifp->ctx->duid == NULL) {
- if (duid_init(ifp) == 0)
- return;
- loginfox("DUID %s",
- hwaddr_ntoa(ifp->ctx->duid,
- ifp->ctx->duid_len,
- buf, sizeof(buf)));
- }
+ /* Try and init DUID from the interface hardware address */
+ dhcpcd_initduid(ifp->ctx, ifp);
/* Report IAIDs */
loginfox("%s: IAID %s", ifp->name,
hwaddr_ntoa(ifo->iaid, sizeof(ifo->iaid),
buf, sizeof(buf)));
warn_iaid_conflict(ifp, 0, ifo->iaid);
+
#ifdef INET6
for (i = 0; i < ifo->ia_len; i++) {
ia = &ifo->ia[i];
@@ -1137,6 +1165,9 @@ dhcpcd_linkoverflow(struct dhcpcd_ctx *c
{
socklen_t socklen;
int rcvbuflen;
+ char buf[2048];
+ ssize_t rlen;
+ size_t rcnt;
struct if_head *ifaces;
struct ifaddrs *ifaddrs;
struct interface *ifp, *ifn, *ifp1;
@@ -1153,21 +1184,16 @@ dhcpcd_linkoverflow(struct dhcpcd_ctx *c
logerrx("route socket overflowed (rcvbuflen %d)"
" - learning interface state", rcvbuflen);
- /* Close the existing socket and open a new one.
- * This is easier than draining the kernel buffer of an
- * in-determinate size. */
- eloop_event_delete(ctx->eloop, ctx->link_fd);
- close(ctx->link_fd);
- if_closesockets_os(ctx);
- if (if_opensockets_os(ctx) == -1) {
- logerr("%s: if_opensockets", __func__);
- eloop_exit(ctx->eloop, EXIT_FAILURE);
- return;
- }
-#ifndef SMALL
- dhcpcd_setlinkrcvbuf(ctx);
-#endif
- eloop_event_add(ctx->eloop, ctx->link_fd, dhcpcd_handlelink, ctx);
+ /* Drain the socket.
+ * We cannot open a new one due to privsep. */
+ rcnt = 0;
+ do {
+ rlen = read(ctx->link_fd, buf, sizeof(buf));
+ if (++rcnt % 1000 == 0)
+ logwarnx("drained %zu messages", rcnt);
+ } while (rlen != -1 || errno == ENOBUFS || errno == ENOMEM);
+ if (rcnt % 1000 != 0)
+ logwarnx("drained %zu messages", rcnt);
/* Work out the current interfaces. */
ifaces = if_discover(ctx, &ifaddrs, ctx->ifc, ctx->ifv);
@@ -1209,17 +1235,12 @@ dhcpcd_linkoverflow(struct dhcpcd_ctx *c
}
void
-dhcpcd_handlehwaddr(struct dhcpcd_ctx *ctx, const char *ifname,
- const void *hwaddr, uint8_t hwlen)
+dhcpcd_handlehwaddr(struct interface *ifp,
+ uint16_t hwtype, const void *hwaddr, uint8_t hwlen)
{
- struct interface *ifp;
char buf[sizeof(ifp->hwaddr) * 3];
- ifp = if_find(ctx->ifaces, ifname);
- if (ifp == NULL)
- return;
-
- if (!if_valid_hwaddr(hwaddr, hwlen))
+ if (hwaddr == NULL || !if_valid_hwaddr(hwaddr, hwlen))
hwlen = 0;
if (hwlen > sizeof(ifp->hwaddr)) {
@@ -1228,13 +1249,21 @@ dhcpcd_handlehwaddr(struct dhcpcd_ctx *c
return;
}
- if (ifp->hwlen == hwlen && memcmp(ifp->hwaddr, hwaddr, hwlen) == 0)
+ if (ifp->hwtype != hwtype) {
+ loginfox("%s: hardware address type changed from %d to %d",
+ ifp->name, ifp->hwtype, hwtype);
+ ifp->hwtype = hwtype;
+ }
+
+ if (ifp->hwlen == hwlen &&
+ (hwlen == 0 || memcmp(ifp->hwaddr, hwaddr, hwlen) == 0))
return;
loginfox("%s: new hardware address: %s", ifp->name,
hwaddr_ntoa(hwaddr, hwlen, buf, sizeof(buf)));
ifp->hwlen = hwlen;
- memcpy(ifp->hwaddr, hwaddr, hwlen);
+ if (hwaddr != NULL)
+ memcpy(ifp->hwaddr, hwaddr, hwlen);
}
static void
@@ -1313,13 +1342,13 @@ stop_all_interfaces(struct dhcpcd_ctx *c
ctx->options |= DHCPCD_EXITING;
/* Drop the last interface first */
TAILQ_FOREACH_REVERSE(ifp, ctx->ifaces, if_head, next) {
- if (ifp->active) {
- ifp->options->options |= opts;
- if (ifp->options->options & DHCPCD_RELEASE)
- ifp->options->options &= ~DHCPCD_PERSISTENT;
- ifp->options->options |= DHCPCD_EXITING;
- stop_interface(ifp);
- }
+ if (!ifp->active)
+ continue;
+ ifp->options->options |= opts;
+ if (ifp->options->options & DHCPCD_RELEASE)
+ ifp->options->options &= ~DHCPCD_PERSISTENT;
+ ifp->options->options |= DHCPCD_EXITING;
+ stop_interface(ifp);
}
}
@@ -1696,7 +1725,7 @@ again3:
}
dp = buf;
de = dp + dlen;
- if (*(dp - 1) != '\0') {
+ if (*(de - 1) != '\0') {
errno = EINVAL;
error = -1;
goto out;
@@ -1750,7 +1779,7 @@ main(int argc, char **argv)
struct ifaddrs *ifaddrs = NULL;
struct if_options *ifo;
struct interface *ifp;
- uint16_t family = 0;
+ sa_family_t family = AF_UNSPEC;
int opt, oi = 0, i;
unsigned int logopts, t;
ssize_t len;
@@ -1761,6 +1790,7 @@ main(int argc, char **argv)
#ifdef USE_SIGNALS
int sig = 0;
const char *siga = NULL;
+ size_t si;
#endif
/* Test for --help and --version */
@@ -1804,6 +1834,7 @@ main(int argc, char **argv)
ifo = NULL;
ctx.cffile = CONFIG;
+ ctx.script = UNCONST(dhcpcd_default_script);
ctx.control_fd = ctx.control_unpriv_fd = ctx.link_fd = -1;
ctx.pf_inet_fd = -1;
@@ -1815,13 +1846,15 @@ main(int argc, char **argv)
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;
@@ -1865,7 +1898,14 @@ main(int argc, char **argv)
i = 4;
break;
case 'q':
- logopts |= LOGERR_QUIET;
+ /* -qq disables console output entirely.
+ * This is important for systemd because it logs
+ * both console AND syslog to the same log
+ * resulting in untold confusion. */
+ if (logopts & LOGERR_QUIET)
+ logopts &= ~LOGERR_ERR;
+ else
+ logopts |= LOGERR_QUIET;
break;
case 'x':
sig = SIGTERM;
@@ -2017,8 +2057,8 @@ printpidfile:
}
#ifdef USE_SIGNALS
- /* Ignore SIGPIPE, prefer EPIPE. */
- signal(SIGPIPE, SIG_IGN);
+ for (si = 0; si < dhcpcd_signals_ignore_len; si++)
+ signal(dhcpcd_signals_ignore[si], SIG_IGN);
/* Save signal mask, block and redirect signals to our handler */
if (eloop_signal_set_cb(ctx.eloop,
@@ -2033,19 +2073,52 @@ printpidfile:
goto exit_failure;
}
+ if (sig != 0) {
+ pid = pidfile_read(ctx.pidfile);
+ if (pid != 0 && pid != -1)
+ loginfox("sending signal %s to pid %d", siga, pid);
+ if (pid == 0 || pid == -1 || kill(pid, sig) != 0) {
+ if (sig != SIGHUP && sig != SIGUSR1 && errno != EPERM)
+ logerrx(PACKAGE" not running");
+ if (pid != 0 && pid != -1 && errno != ESRCH) {
+ logerr("kill");
+ goto exit_failure;
+ }
+ unlink(ctx.pidfile);
+ if (sig != SIGHUP && sig != SIGUSR1)
+ goto exit_failure;
+ } else {
+ struct timespec ts;
+
+ if (sig == SIGHUP || sig == SIGUSR1)
+ goto exit_success;
+ /* Spin until it exits */
+ loginfox("waiting for pid %d to exit", pid);
+ ts.tv_sec = 0;
+ ts.tv_nsec = 100000000; /* 10th of a second */
+ for(i = 0; i < 100; i++) {
+ nanosleep(&ts, NULL);
+ if (pidfile_read(ctx.pidfile) == -1)
+ goto exit_success;
+ }
+ logerrx("pid %d failed to exit", pid);
+ goto exit_failure;
+ }
+ }
+#endif
+
/* Test against siga instead of sig to avoid gcc
* warning about a bogus potential signed overflow.
* The end result will be the same. */
if ((siga == NULL || i == 4 || ctx.ifc != 0) &&
!(ctx.options & DHCPCD_TEST))
{
-#endif
ctx.options |= DHCPCD_FORKED; /* avoid socket unlink */
if (!(ctx.options & DHCPCD_MASTER))
- ctx.control_fd = control_open(argv[optind],
+ ctx.control_fd = control_open(argv[optind], family,
ctx.options & DHCPCD_DUMPLEASE);
if (ctx.control_fd == -1)
- ctx.control_fd = control_open(NULL,
+ ctx.control_fd = control_open(NULL, AF_UNSPEC,
ctx.options & DHCPCD_DUMPLEASE);
if (ctx.control_fd != -1) {
if (!(ctx.options & DHCPCD_DUMPLEASE))
@@ -2074,42 +2147,6 @@ printpidfile:
}
}
ctx.options &= ~DHCPCD_FORKED;
-#ifdef USE_SIGNALS
- }
-#endif
-
-#ifdef USE_SIGNALS
- if (sig != 0) {
- pid = pidfile_read(ctx.pidfile);
- if (pid != 0 && pid != -1)
- loginfox("sending signal %s to pid %d", siga, pid);
- if (pid == 0 || pid == -1 || kill(pid, sig) != 0) {
- if (sig != SIGHUP && sig != SIGUSR1 && errno != EPERM)
- logerrx(PACKAGE" not running");
- if (pid != 0 && pid != -1 && errno != ESRCH) {
- logerr("kill");
- goto exit_failure;
- }
- unlink(ctx.pidfile);
- if (sig != SIGHUP && sig != SIGUSR1)
- goto exit_failure;
- } else {
- struct timespec ts;
-
- if (sig == SIGHUP || sig == SIGUSR1)
- goto exit_success;
- /* Spin until it exits */
- loginfox("waiting for pid %d to exit", pid);
- ts.tv_sec = 0;
- ts.tv_nsec = 100000000; /* 10th of a second */
- for(i = 0; i < 100; i++) {
- nanosleep(&ts, NULL);
- if (pidfile_read(ctx.pidfile) == -1)
- goto exit_success;
- }
- logerrx("pid %d failed to exit", pid);
- goto exit_failure;
- }
}
if (!(ctx.options & DHCPCD_TEST)) {
@@ -2127,14 +2164,12 @@ printpidfile:
goto exit_failure;
}
}
-#endif
loginfox(PACKAGE "-" VERSION " starting");
freopen(_PATH_DEVNULL, "r", stdin);
#ifdef PRIVSEP
- if (ps_init(&ctx) == 0)
- script_runchroot(&ctx, ifo->script);
+ ps_init(&ctx);
#endif
#ifdef USE_SIGNALS
@@ -2210,23 +2245,19 @@ printpidfile:
if (!(ctx.options & DHCPCD_TEST) &&
control_start(&ctx,
- ctx.options & DHCPCD_MASTER ? NULL : argv[optind]) == -1)
+ ctx.options & DHCPCD_MASTER ? NULL : argv[optind], family) == -1)
{
logerr("%s: control_start", __func__);
goto exit_failure;
}
+#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)) ==
+ if (!IN_PRIVSEP(&ctx) &&
+ (ctx.options & (DHCPCD_MASTER | DHCPCD_DEV)) ==
(DHCPCD_MASTER | DHCPCD_DEV))
- dev_start(&ctx);
-
-#ifdef PRIVSEP
- if (ctx.options & DHCPCD_PRIVSEP && ps_dropprivs(&ctx) == -1) {
- logerr("ps_dropprivs");
- goto exit_failure;
- }
+ dev_start(&ctx, dhcpcd_handleinterface);
#endif
setproctitle("%s%s%s",
@@ -2242,6 +2273,34 @@ printpidfile:
dhcpcd_setlinkrcvbuf(&ctx);
#endif
+ /* Try and create DUID from the machine UUID. */
+ dhcpcd_initduid(&ctx, NULL);
+
+ /* Cache the default vendor option. */
+ if (dhcp_vendor(ctx.vendor, sizeof(ctx.vendor)) == -1)
+ logerrx("dhcp_vendor");
+
+#ifdef PRIVSEP
+ if (ctx.options & DHCPCD_PRIVSEP) {
+ if (ps_dropprivs(&ctx) == -1) {
+ logerr("ps_dropprivs");
+ goto exit_failure;
+ }
+#ifdef HAVE_CAPSICUM
+ if (cap_enter() == -1 && errno != ENOSYS) {
+ logerr("%s: cap_enter", __func__);
+ goto exit_failure;
+ }
+#endif
+#ifdef HAVE_PLEDGE
+ if (pledge("stdio inet route dns", NULL) == -1) {
+ logerr("%s: pledge", __func__);
+ goto exit_failure;
+ }
+#endif
+ }
+#endif
+
/* When running dhcpcd against a single interface, we need to retain
* the old behaviour of waiting for an IP address */
if (ctx.ifc == 1 && !(ctx.options & DHCPCD_BACKGROUND))
@@ -2392,11 +2451,15 @@ exit1:
#ifdef INET6
ipv6_ctxfree(&ctx);
#endif
+#ifdef PLUGIN_DEV
dev_stop(&ctx);
+#endif
#ifdef PRIVSEP
eloop_free(ctx.ps_eloop);
#endif
eloop_free(ctx.eloop);
+ if (ctx.script != dhcpcd_default_script)
+ free(ctx.script);
if (ctx.options & DHCPCD_STARTED && !(ctx.options & DHCPCD_FORKED))
loginfox(PACKAGE " exited");
logclose();
Index: src/external/bsd/dhcpcd/dist/src/dhcp6.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.18 src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.19
--- src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.18 Tue Apr 21 09:55:33 2020
+++ src/external/bsd/dhcpcd/dist/src/dhcp6.c Sun May 31 12:52:11 2020
@@ -26,12 +26,11 @@
* SUCH DAMAGE.
*/
-/* TODO: We should decline dupliate addresses detected */
-
-#include <sys/stat.h>
#include <sys/utsname.h>
+#include <sys/types.h>
#include <netinet/in.h>
+#include <netinet/ip6.h>
#include <assert.h>
#include <ctype.h>
@@ -139,6 +138,7 @@ static const struct dhcp6_op dhcp6_ops[]
{ DHCP6_INFORMATION_REQ, "INFORM6" },
{ DHCP6_RELEASE, "RELEASE6" },
{ DHCP6_RECONFIGURE, "RECONFIGURE6" },
+ { DHCP6_DECLINE, "DECLINE6" },
{ 0, NULL }
};
@@ -174,6 +174,7 @@ static const char * const dhcp6_statuses
static void dhcp6_bind(struct interface *, const char *, const char *);
static void dhcp6_failinform(void *);
static void dhcp6_recvaddr(void *);
+static void dhcp6_startdecline(struct interface *);
#ifdef SMALL
#define dhcp6_hasprefixdelegation(a) (0)
@@ -181,6 +182,12 @@ static void dhcp6_recvaddr(void *);
static int dhcp6_hasprefixdelegation(struct interface *);
#endif
+#define DECLINE_IA(ia) \
+ ((ia)->addr_flags & IN6_IFF_DUPLICATED && \
+ (ia)->ia_type != 0 && (ia)->ia_type != D6_OPTION_IA_PD && \
+ !((ia)->flags & IPV6_AF_STALE) && \
+ (ia)->prefix_vltime != 0)
+
void
dhcp6_printoptions(const struct dhcpcd_ctx *ctx,
const struct dhcp_opt *opts, size_t opts_len)
@@ -252,28 +259,27 @@ static size_t
dhcp6_makevendor(void *data, const struct interface *ifp)
{
const struct if_options *ifo;
- size_t len, i;
+ size_t len, vlen, i;
uint8_t *p;
- ssize_t vlen;
const struct vivco *vivco;
- char vendor[VENDORCLASSID_MAX_LEN];
struct dhcp6_option o;
ifo = ifp->options;
len = sizeof(uint32_t); /* IANA PEN */
if (ifo->vivco_en) {
+ vlen = 0;
for (i = 0, vivco = ifo->vivco;
i < ifo->vivco_len;
i++, vivco++)
- len += sizeof(uint16_t) + vivco->len;
- vlen = 0; /* silence bogus gcc warning */
- } else {
- vlen = dhcp_vendor(vendor, sizeof(vendor));
- if (vlen == -1)
- vlen = 0;
- else
- len += sizeof(uint16_t) + (size_t)vlen;
- }
+ vlen += sizeof(uint16_t) + vivco->len;
+ len += vlen;
+ } else if (ifo->vendorclassid[0] != '\0') {
+ /* dhcpcd owns DHCPCD_IANA_PEN.
+ * If you need your own string, get your own IANA PEN. */
+ vlen = strlen(ifp->ctx->vendor);
+ len += sizeof(uint16_t) + vlen;
+ } else
+ return 0;
if (len > UINT16_MAX) {
logerrx("%s: DHCPv6 Vendor Class too big", ifp->name);
@@ -304,11 +310,11 @@ dhcp6_makevendor(void *data, const struc
memcpy(p, vivco->data, vivco->len);
p += vivco->len;
}
- } else if (vlen) {
+ } else if (ifo->vendorclassid[0] != '\0') {
hvlen = htons((uint16_t)vlen);
memcpy(p, &hvlen, sizeof(hvlen));
p += sizeof(hvlen);
- memcpy(p, vendor, (size_t)vlen);
+ memcpy(p, ifp->ctx->vendor, vlen);
}
}
@@ -672,7 +678,7 @@ dhcp6_makemessage(struct interface *ifp)
len = 0;
si = NULL;
hl = 0; /* Appease gcc */
- if (state->state != DH6S_RELEASE) {
+ if (state->state != DH6S_RELEASE && state->state != DH6S_DECLINE) {
for (l = 0, opt = ifp->ctx->dhcp6_opts;
l < ifp->ctx->dhcp6_opts_len;
l++, opt++)
@@ -750,6 +756,8 @@ dhcp6_makemessage(struct interface *ifp)
m = state->recv;
ml = state->recv_len;
/* FALLTHROUGH */
+ case DH6S_DECLINE:
+ /* FALLTHROUGH */
case DH6S_RELEASE:
/* FALLTHROUGH */
case DH6S_RENEW:
@@ -778,6 +786,8 @@ dhcp6_makemessage(struct interface *ifp)
(ap->prefix_vltime == 0 ||
state->state == DH6S_DISCOVER))
continue;
+ if (DECLINE_IA(ap) && state->state != DH6S_DECLINE)
+ continue;
if (ap->ia_type == D6_OPTION_IA_PD) {
#ifndef SMALL
len += sizeof(o) + sizeof(struct dhcp6_pd_addr);
@@ -836,6 +846,9 @@ dhcp6_makemessage(struct interface *ifp)
case DH6S_RELEASE:
type = DHCP6_RELEASE;
break;
+ case DH6S_DECLINE:
+ type = DHCP6_DECLINE;
+ break;
default:
errno = EINVAL;
return -1;
@@ -949,6 +962,8 @@ dhcp6_makemessage(struct interface *ifp)
(ap->prefix_vltime == 0 ||
state->state == DH6S_DISCOVER))
continue;
+ if (DECLINE_IA(ap) && state->state != DH6S_DECLINE)
+ continue;
if (ap->ia_type != ifia->ia_type)
continue;
if (memcmp(ap->iaid, ifia->iaid, sizeof(ap->iaid)))
@@ -1010,7 +1025,10 @@ dhcp6_makemessage(struct interface *ifp)
memcpy(o_lenp, &ia_na_len, sizeof(ia_na_len));
}
- if (state->send->type != DHCP6_RELEASE && n_options) {
+ if (state->send->type != DHCP6_RELEASE &&
+ state->send->type != DHCP6_DECLINE &&
+ n_options)
+ {
o_lenp = NEXTLEN;
o.len = 0;
COPYIN1(D6_OPTION_ORO, 0);
@@ -1072,7 +1090,9 @@ dhcp6_makemessage(struct interface *ifp)
if (!has_option_mask(ifo->nomask6, D6_OPTION_VENDOR_CLASS))
p += dhcp6_makevendor(p, ifp);
- if (state->send->type != DHCP6_RELEASE) {
+ if (state->send->type != DHCP6_RELEASE &&
+ state->send->type != DHCP6_DECLINE)
+ {
if (fqdn != FQDN_DISABLE) {
o_lenp = NEXTLEN;
COPYIN1(D6_OPTION_FQDN, 0);
@@ -1182,59 +1202,71 @@ dhcp6_update_auth(struct interface *ifp,
}
#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,
+ /* Setting the port on Linux gives EINVAL when sending.
+ * This looks like a kernel bug as the equivalent works
+ * fine with the DHCP counterpart. */
+#ifndef __linux__
.sin6_port = htons(DHCP6_SERVER_PORT),
+#endif
};
- 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((uint16_t)(sizeof(udp) + state->send_len)),
};
- unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
+ struct iovec iov[] = {
+ { .iov_base = &udp, .iov_len = sizeof(udp), },
+ { .iov_base = state->send, .iov_len = state->send_len, },
+ };
+ union {
+ struct cmsghdr hdr;
+ uint8_t buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+ } 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 &&
@@ -1248,7 +1280,6 @@ dhcp6_sendmessage(struct interface *ifp,
* 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;
@@ -1269,14 +1300,17 @@ dhcp6_sendmessage(struct interface *ifp,
* ((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 */
@@ -1303,13 +1337,13 @@ dhcp6_sendmessage(struct interface *ifp,
#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 };
dst.sin6_scope_id = ifp->index;
- msg.msg_control = ctl;
- msg.msg_controllen = sizeof(ctl);
+ msg.msg_control = cmsgbuf.buf;
+ msg.msg_controllen = sizeof(cmsgbuf.buf);
cm = CMSG_FIRSTHDR(&msg);
if (cm == NULL) /* unlikely */
return -1;
@@ -1321,46 +1355,13 @@ dhcp6_sendmessage(struct interface *ifp,
#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.
@@ -1432,6 +1433,13 @@ dhcp6_sendconfirm(void *arg)
}
static void
+dhcp6_senddecline(void *arg)
+{
+
+ dhcp6_sendmessage(arg, dhcp6_senddecline);
+}
+
+static void
dhcp6_sendrelease(void *arg)
{
@@ -1496,54 +1504,60 @@ dhcp6_dadcallback(void *arg)
struct ipv6_addr *ia = arg;
struct interface *ifp;
struct dhcp6_state *state;
- int wascompleted, valid;
+ struct ipv6_addr *ia2;
+ bool completed, valid, oneduplicated;
- wascompleted = (ia->flags & IPV6_AF_DADCOMPLETED);
+ completed = (ia->flags & IPV6_AF_DADCOMPLETED);
ia->flags |= IPV6_AF_DADCOMPLETED;
- if (ia->flags & IPV6_AF_DUPLICATED) {
- /* XXX FIXME
- * We should decline the address */
+ if (ia->addr_flags & IN6_IFF_DUPLICATED)
logwarnx("%s: DAD detected %s", ia->iface->name, ia->saddr);
- }
- if (!wascompleted) {
- ifp = ia->iface;
+#ifdef ND6_ADVERTISE
+ else
+ ipv6nd_advertise(ia);
+#endif
+ if (completed)
+ return;
- state = D6_STATE(ifp);
- if (state->state == DH6S_BOUND ||
- state->state == DH6S_DELEGATED)
- {
- struct ipv6_addr *ia2;
+ ifp = ia->iface;
+ state = D6_STATE(ifp);
+ if (state->state != DH6S_BOUND && state->state != DH6S_DELEGATED)
+ return;
#ifdef SMALL
- valid = true;
+ valid = true;
#else
- valid = (ia->delegating_prefix == NULL);
-#endif
- TAILQ_FOREACH(ia2, &state->addrs, next) {
- if (ia2->flags & IPV6_AF_ADDED &&
- !(ia2->flags & IPV6_AF_DADCOMPLETED))
- {
- wascompleted = 1;
- break;
- }
- }
- if (!wascompleted) {
- logdebugx("%s: DHCPv6 DAD completed",
- ifp->name);
- script_runreason(ifp,
-#ifndef SMALL
- ia->delegating_prefix ? "DELEGATED6" :
-#endif
- state->reason);
- if (valid)
- dhcpcd_daemonise(ifp->ctx);
- }
-#ifdef ND6_ADVERTISE
- ipv6nd_advertise(ia);
+ valid = (ia->delegating_prefix == NULL);
#endif
+ completed = true;
+ oneduplicated = false;
+ TAILQ_FOREACH(ia2, &state->addrs, next) {
+ if (ia2->flags & IPV6_AF_ADDED &&
+ !(ia2->flags & IPV6_AF_DADCOMPLETED))
+ {
+ completed = false;
+ break;
}
+ if (DECLINE_IA(ia))
+ oneduplicated = true;
+ }
+ if (!completed)
+ return;
+
+ logdebugx("%s: DHCPv6 DAD completed", ifp->name);
+
+ if (oneduplicated && state->state == DH6S_BOUND) {
+ dhcp6_startdecline(ifp);
+ return;
}
+
+ script_runreason(ifp,
+#ifndef SMALL
+ ia->delegating_prefix ? "DELEGATED6" :
+#endif
+ state->reason);
+ if (valid)
+ dhcpcd_daemonise(ifp->ctx);
}
static void
@@ -1682,7 +1696,7 @@ dhcp6_leaseextend(struct interface *ifp)
}
static void
-dhcp6_fail(struct interface* ifp)
+dhcp6_fail(struct interface *ifp)
{
struct dhcp6_state *state = D6_STATE(ifp);
@@ -1712,7 +1726,7 @@ dhcp6_fail(struct interface* ifp)
state->new_len = 0;
if (state->old != NULL)
script_runreason(ifp, "EXPIRE6");
- unlink(state->leasefile);
+ dhcp_unlink(ifp->ctx, state->leasefile);
}
if (!dhcp6_startdiscoinform(ifp)) {
@@ -1867,8 +1881,18 @@ static void
dhcp6_startconfirm(struct interface *ifp)
{
struct dhcp6_state *state;
+ struct ipv6_addr *ia;
state = D6_STATE(ifp);
+
+ TAILQ_FOREACH(ia, &state->addrs, next) {
+ if (!DECLINE_IA(ia))
+ continue;
+ logerrx("%s: prior DHCPv6 has a duplicated address", ifp->name);
+ dhcp6_startdecline(ifp);
+ return;
+ }
+
state->state = DH6S_CONFIRM;
state->RTC = 0;
state->IMD = CNF_MAX_DELAY;
@@ -1877,6 +1901,7 @@ dhcp6_startconfirm(struct interface *ifp
state->MRC = CNF_MAX_RC;
loginfox("%s: confirming prior DHCPv6 lease", ifp->name);
+
if (dhcp6_makemessage(ifp) == -1) {
logerr("%s: %s", __func__, ifp->name);
return;
@@ -1899,6 +1924,36 @@ dhcp6_startexpire(void *arg)
}
static void
+dhcp6_faildecline(void *arg)
+{
+ struct interface *ifp = arg;
+
+ logerrx("%s: failed to decline duplicated DHCPv6 addresses", ifp->name);
+ dhcp6_fail(ifp);
+}
+
+static void
+dhcp6_startdecline(struct interface *ifp)
+{
+ struct dhcp6_state *state;
+
+ state = D6_STATE(ifp);
+ loginfox("%s: declining failed DHCPv6 addresses", ifp->name);
+ state->state = DH6S_DECLINE;
+ state->RTC = 0;
+ state->IMD = 0;
+ state->IRT = DEC_TIMEOUT;
+ state->MRT = 0;
+ state->MRC = DEC_MAX_RC;
+ state->MRCcallback = dhcp6_faildecline;
+
+ if (dhcp6_makemessage(ifp) == -1)
+ logerr("%s: %s", __func__, ifp->name);
+ else
+ dhcp6_senddecline(ifp);
+}
+
+static void
dhcp6_finishrelease(void *arg)
{
struct interface *ifp;
@@ -2513,106 +2568,77 @@ dhcp6_validatelease(struct interface *if
}
static ssize_t
-dhcp6_writelease(const struct interface *ifp)
-{
- const struct dhcp6_state *state;
- int fd;
- ssize_t bytes;
-
- state = D6_CSTATE(ifp);
- logdebugx("%s: writing lease `%s'", ifp->name, state->leasefile);
-
- fd = open(state->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (fd == -1)
- return -1;
- bytes = write(fd, state->new, state->new_len);
- close(fd);
- return bytes;
-}
-
-static int
dhcp6_readlease(struct interface *ifp, int validate)
{
+ union {
+ struct dhcp6_message dhcp6;
+ uint8_t buf[UDPLEN_MAX];
+ } buf;
struct dhcp6_state *state;
- struct stat st;
+ ssize_t bytes;
int fd;
- time_t now;
- int retval;
- bool read_stdin, fd_opened;
+ time_t mtime, now;
#ifdef AUTH
uint8_t *o;
uint16_t ol;
#endif
state = D6_STATE(ifp);
- read_stdin = state->leasefile[0] == '\0';
- if (read_stdin) {
+ if (state->leasefile[0] == '\0') {
logdebugx("reading standard input");
- fd = fileno(stdin);
- fd_opened = false;
+ bytes = read(fileno(stdin), buf.buf, sizeof(buf.buf));
} else {
- logdebugx("%s: reading lease `%s'", ifp->name,state->leasefile);
- fd = open(state->leasefile, O_RDONLY);
- if (fd != -1 && fstat(fd, &st) == -1) {
- close(fd);
- fd = -1;
- }
- fd_opened = true;
+ logdebugx("%s: reading lease `%s'",
+ ifp->name, state->leasefile);
+ bytes = dhcp_readfile(ifp->ctx, state->leasefile,
+ buf.buf, sizeof(buf.buf));
}
- if (fd == -1)
- return -1;
- retval = -1;
- free(state->new);
- state->new_len = dhcp_read_lease_fd(fd, (void **)&state->new);
- if (fd_opened)
- close(fd);
+ if (bytes == -1)
+ goto ex;
- if (ifp->ctx->options & DHCPCD_DUMPLEASE || read_stdin)
- return 0;
+ if (ifp->ctx->options & DHCPCD_DUMPLEASE || state->leasefile[0] == '\0')
+ goto out;
- if (state->new_len == 0) {
- retval = 0;
+ if (bytes == 0)
goto ex;
- }
/* If not validating IA's and if they have expired,
* skip to the auth check. */
- if (!validate) {
- fd = 0;
+ if (!validate)
goto auth;
- }
+ if (dhcp_filemtime(ifp->ctx, state->leasefile, &mtime) == -1)
+ goto ex;
clock_gettime(CLOCK_MONOTONIC, &state->acquired);
if ((now = time(NULL)) == -1)
goto ex;
- state->acquired.tv_sec -= now - st.st_mtime;
+ state->acquired.tv_sec -= now - mtime;
/* Check to see if the lease is still valid */
- fd = dhcp6_validatelease(ifp, state->new, state->new_len, NULL,
+ fd = dhcp6_validatelease(ifp, &buf.dhcp6, (size_t)bytes, NULL,
&state->acquired);
if (fd == -1)
goto ex;
if (state->expire != ND6_INFINITE_LIFETIME &&
- (time_t)state->expire < now - st.st_mtime &&
+ (time_t)state->expire < now - mtime &&
!(ifp->options->options & DHCPCD_LASTLEASE_EXTEND))
{
logdebugx("%s: discarding expired lease", ifp->name);
- retval = 0;
+ bytes = 0;
goto ex;
}
auth:
- retval = 0;
#ifdef AUTH
/* Authenticate the message */
- o = dhcp6_findmoption(state->new, state->new_len, D6_OPTION_AUTH, &ol);
+ o = dhcp6_findmoption(&buf.dhcp6, (size_t)bytes, D6_OPTION_AUTH, &ol);
if (o) {
if (dhcp_auth_validate(&state->auth, &ifp->options->auth,
- (uint8_t *)state->new, state->new_len, 6, state->new->type,
- o, ol) == NULL)
+ buf.buf, (size_t)bytes, 6, buf.dhcp6.type, o, ol) == NULL)
{
logerr("%s: authentication failed", ifp->name);
+ bytes = 0;
goto ex;
}
if (state->auth.token)
@@ -2628,22 +2654,32 @@ auth:
}
#endif
- return fd;
+out:
+ free(state->new);
+ state->new = malloc((size_t)bytes);
+ if (state->new == NULL) {
+ logerr(__func__);
+ goto ex;
+ }
+
+ memcpy(state->new, buf.buf, (size_t)bytes);
+ state->new_len = (size_t)bytes;
+ return bytes;
ex:
dhcp6_freedrop_addrs(ifp, 0, NULL);
- unlink(state->leasefile);
+ dhcp_unlink(ifp->ctx, state->leasefile);
free(state->new);
state->new = NULL;
state->new_len = 0;
- return retval;
+ return bytes == 0 ? 0 : -1;
}
static void
dhcp6_startinit(struct interface *ifp)
{
struct dhcp6_state *state;
- int r;
+ ssize_t r;
uint8_t has_ta, has_non_ta;
size_t i;
@@ -2998,7 +3034,7 @@ dhcp6_bind(struct interface *ifp, const
break;
}
}
- loglevel = has_new ? LOG_INFO : LOG_DEBUG;
+ loglevel = has_new || state->state != DH6S_RENEW ? LOG_INFO : LOG_DEBUG;
if (!timedout) {
logmessage(loglevel, "%s: %s received from %s",
ifp->name, op, sfrom);
@@ -3146,12 +3182,14 @@ dhcp6_bind(struct interface *ifp, const
state->state = DH6S_BOUND;
state->failed = false;
- if (state->renew && state->renew != ND6_INFINITE_LIFETIME)
+ if ((state->renew != 0 || state->rebind != 0) &&
+ state->renew != ND6_INFINITE_LIFETIME)
eloop_timeout_add_sec(ifp->ctx->eloop,
state->renew,
state->state == DH6S_INFORMED ?
dhcp6_startinform : dhcp6_startrenew, ifp);
- if (state->rebind && state->rebind != ND6_INFINITE_LIFETIME)
+ if ((state->rebind != 0 || state->expire != 0) &&
+ state->rebind != ND6_INFINITE_LIFETIME)
eloop_timeout_add_sec(ifp->ctx->eloop,
state->rebind, dhcp6_startrebind, ifp);
if (state->expire != ND6_INFINITE_LIFETIME)
@@ -3180,9 +3218,13 @@ dhcp6_bind(struct interface *ifp, const
logmessage(loglevel, "%s: expire in %"PRIu32" seconds",
ifp->name, state->expire);
rt_build(ifp->ctx, AF_INET6);
- if (!confirmed && !timedout)
- if (dhcp6_writelease(ifp) == -1)
- logerr("dhcp6_writelease: %s",state->leasefile);
+ if (!confirmed && !timedout) {
+ logdebugx("%s: writing lease `%s'",
+ ifp->name, state->leasefile);
+ if (dhcp_writefile(ifp->ctx, state->leasefile, 0640,
+ state->new, state->new_len) == -1)
+ logerr("dhcp_writefile: %s",state->leasefile);
+ }
#ifndef SMALL
dhcp6_delegate_prefix(ifp);
#endif
@@ -3350,6 +3392,13 @@ dhcp6_recvif(struct interface *ifp, cons
if (state->state == DH6S_DISCOVER)
state->state = DH6S_REQUEST;
break;
+ case DH6S_DECLINE:
+ /* This isnt really a failure, but an
+ * acknowledgement of one. */
+ loginfox("%s: %s acknowledged DECLINE6",
+ ifp->name, sfrom);
+ dhcp6_fail(ifp);
+ return;
default:
valid_op = false;
break;
@@ -3602,7 +3651,7 @@ dhcp6_recvmsg(struct dhcpcd_ctx *ctx, st
* replay it in my code.
*/
static int replyn = 0;
- char fname[PATH_MAX], tbuf[64 * 1024];
+ char fname[PATH_MAX], tbuf[UDPLEN_MAX];
int fd;
ssize_t tlen;
uint8_t *si1, *si2;
@@ -3637,10 +3686,12 @@ static void
dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia)
{
struct sockaddr_in6 from;
- unsigned char buf[64 * 1024]; /* Maximum UDP message size */
+ union {
+ struct dhcp6_message dhcp6;
+ uint8_t buf[UDPLEN_MAX]; /* Maximum UDP message size */
+ } iovbuf;
struct iovec iov = {
- .iov_base = buf,
- .iov_len = sizeof(buf),
+ .iov_base = iovbuf.buf, .iov_len = sizeof(iovbuf.buf),
};
union {
struct cmsghdr hdr;
@@ -3654,7 +3705,7 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struc
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__);
@@ -3682,21 +3733,39 @@ dhcp6_recvctx(void *arg)
}
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)
+ goto errexit;
+
+ v = offsetof(struct udphdr, uh_sum);
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &v, sizeof(v)) == -1)
+ goto errexit;
+
+ return fd;
+
+errexit:
+ close(fd);
+ return -1;
+}
+
+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);
@@ -3706,7 +3775,7 @@ dhcp6_openudp(unsigned int ifindex, stru
if (ia != NULL) {
memcpy(&sa.sin6_addr, ia, sizeof(sa.sin6_addr));
- sa.sin6_scope_id = ifindex;
+ ipv6_setscope(&sa, ifindex);
}
if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) == -1)
@@ -3716,6 +3785,12 @@ dhcp6_openudp(unsigned int ifindex, stru
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:
@@ -3768,14 +3843,22 @@ dhcp6_start1(void *arg)
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);
@@ -3956,7 +4039,7 @@ dhcp6_freedrop(struct interface *ifp, in
dhcp6_startrelease(ifp);
return;
}
- unlink(state->leasefile);
+ dhcp_unlink(ifp->ctx, state->leasefile);
}
dhcp6_freedrop_addrs(ifp, drop, NULL);
free(state->old);
@@ -3987,10 +4070,10 @@ dhcp6_freedrop(struct interface *ifp, in
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;
}
}
Index: src/external/bsd/dhcpcd/dist/src/dhcpcd.8.in
diff -u src/external/bsd/dhcpcd/dist/src/dhcpcd.8.in:1.5 src/external/bsd/dhcpcd/dist/src/dhcpcd.8.in:1.6
--- src/external/bsd/dhcpcd/dist/src/dhcpcd.8.in:1.5 Thu Apr 2 12:41:48 2020
+++ src/external/bsd/dhcpcd/dist/src/dhcpcd.8.in Sun May 31 12:52:11 2020
@@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 27, 2020
+.Dd May 21, 2020
.Dt DHCPCD 8
.Os
.Sh NAME
@@ -109,7 +109,7 @@ to renew early.
.Pp
If any interface reports a working carrier then
.Nm
-will try and obtain a lease before forking to the background,
+will try to obtain a lease before forking to the background,
otherwise it will fork right away.
This behaviour can be modified with the
.Fl b , Fl Fl background
@@ -669,7 +669,9 @@ only responds to DHCP servers and not BO
Quiet
.Nm
on the command line, only warnings and errors will be displayed.
-The messages are still logged though.
+If this option is used another time then all console output is disabled.
+These messages are still logged via
+.Xr syslog 3 .
.It Fl T , Fl Fl test
On receipt of DHCP messages just call
.Pa @SCRIPT@
Index: src/external/bsd/dhcpcd/dist/src/script.c
diff -u src/external/bsd/dhcpcd/dist/src/script.c:1.5 src/external/bsd/dhcpcd/dist/src/script.c:1.6
--- src/external/bsd/dhcpcd/dist/src/script.c:1.5 Mon Apr 13 15:46:26 2020
+++ src/external/bsd/dhcpcd/dist/src/script.c Sun May 31 12:52:11 2020
@@ -108,6 +108,8 @@ script_exec(char *const *argv, char *con
posix_spawnattr_setsigmask(&attr, &defsigs);
for (i = 0; i < dhcpcd_signals_len; i++)
sigaddset(&defsigs, dhcpcd_signals[i]);
+ for (i = 0; i < dhcpcd_signals_ignore_len; i++)
+ sigaddset(&defsigs, dhcpcd_signals_ignore[i]);
posix_spawnattr_setsigdefault(&attr, &defsigs);
#endif
errno = 0;
@@ -250,8 +252,10 @@ make_env(struct dhcpcd_ctx *ctx, const s
fp = NULL;
tmpfd = mkstemp(tmpfile);
- if (tmpfd == -1)
- goto eexit;
+ if (tmpfd == -1) {
+ logerr("%s: mkstemp", __func__);
+ return -1;
+ }
unlink(tmpfile);
fp = fdopen(tmpfd, "w+");
if (fp == NULL) {
@@ -689,7 +693,7 @@ script_runreason(const struct interface
int status = 0;
struct fd_list *fd;
- if (ifp->options->script == NULL &&
+ if (ctx->script == NULL &&
TAILQ_FIRST(&ifp->ctx->control_fds) == NULL)
return 0;
@@ -699,23 +703,23 @@ script_runreason(const struct interface
return -1;
}
- if (ifp->options->script == NULL)
+ if (ctx->script == NULL)
goto send_listeners;
- argv[0] = ifp->options->script;
+ argv[0] = ctx->script;
argv[1] = NULL;
logdebugx("%s: executing `%s' %s", ifp->name, argv[0], reason);
#ifdef PRIVSEP
if (ctx->options & DHCPCD_PRIVSEP) {
- if (ps_root_script(ifp,
+ if (ps_root_script(ctx,
ctx->script_buf, ctx->script_buflen) == -1)
logerr(__func__);
goto send_listeners;
}
#endif
- status = script_run(ctx, argv);
+ script_run(ctx, argv);
send_listeners:
/* Send to our listeners */
@@ -732,23 +736,3 @@ send_listeners:
return status;
}
-
-#ifdef PRIVSEP
-int
-script_runchroot(struct dhcpcd_ctx *ctx, char *script)
-{
- char *argv[2];
-
- /* Make our env */
- if (make_env(ctx, NULL, "CHROOT") == -1) {
- logerr(__func__);
- return -1;
- }
-
- argv[0] = script;
- argv[1] = NULL;
- logdebugx("executing `%s' %s", argv[0], "CHROOT");
-
- return script_run(ctx, argv);
-}
-#endif
Index: src/external/bsd/dhcpcd/dist/src/if-bsd.c
diff -u src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.19 src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.20
--- src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.19 Tue Apr 21 09:55:33 2020
+++ src/external/bsd/dhcpcd/dist/src/if-bsd.c Sun May 31 12:52:11 2020
@@ -109,11 +109,6 @@ static const char * const ifnames_ignore
NULL
};
-#ifdef INET6
-static void ifa_setscope(struct sockaddr_in6 *, unsigned int);
-static unsigned int ifa_getscope(const struct sockaddr_in6 *);
-#endif
-
struct priv {
int pf_inet6_fd;
};
@@ -173,12 +168,16 @@ if_opensockets_os(struct dhcpcd_ctx *ctx
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)
+ logerr("%s: SO_RERROR", __func__);
+#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. */
@@ -303,6 +302,9 @@ if_ignore(struct dhcpcd_ctx *ctx, const
return true;
#ifdef SIOCGIFGROUP
+#ifdef HAVE_PLEDGE
+#warning Fix SIOCGIFGROUP to use privsep to remove inet pledge requirement
+#endif
struct ifgroupreq ifgr = { .ifgr_len = 0 };
struct ifg_req *ifg;
size_t ifg_len;
@@ -359,27 +361,26 @@ if_linkaddr(struct sockaddr_dl *sdl, con
}
#if defined(SIOCG80211NWID) || defined(SIOCGETVLAN)
-static int if_direct_ioctl(int s, const char *ifname,
- unsigned long cmd, void *data)
+static int if_indirect_ioctl(struct dhcpcd_ctx *ctx,
+ const char *ifname, unsigned long cmd, void *data, size_t len)
{
+ struct ifreq ifr = { .ifr_flags = 0 };
- strlcpy(data, ifname, IFNAMSIZ);
- return ioctl(s, cmd, data);
-}
-
-static int if_indirect_ioctl(int s, const char *ifname,
- unsigned long cmd, void *data)
-{
- struct ifreq ifr;
+#if defined(PRIVSEP) && defined(HAVE_PLEDGE)
+ if (IN_PRIVSEP(ctx))
+ return (int)ps_root_indirectioctl(ctx, cmd, ifname, data, len);
+#else
+ UNUSED(len);
+#endif
- memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_data = data;
- return if_direct_ioctl(s, ifname, cmd, &ifr);
+ return ioctl(ctx->pf_inet_fd, cmd, &ifr);
}
#endif
static int
-if_getssid1(int s, const char *ifname, void *ssid)
+if_getssid1(struct dhcpcd_ctx *ctx, const char *ifname, void *ssid)
{
int retval = -1;
#if defined(SIOCG80211NWID)
@@ -391,7 +392,9 @@ if_getssid1(int s, const char *ifname, v
#if defined(SIOCG80211NWID) /* NetBSD */
memset(&nwid, 0, sizeof(nwid));
- if (if_indirect_ioctl(s, ifname, SIOCG80211NWID, &nwid) == 0) {
+ if (if_indirect_ioctl(ctx, ifname, SIOCG80211NWID,
+ &nwid, sizeof(nwid)) == 0)
+ {
if (ssid == NULL)
retval = nwid.i_len;
else if (nwid.i_len > IF_SSIDLEN)
@@ -408,7 +411,7 @@ if_getssid1(int s, const char *ifname, v
ireq.i_val = -1;
memset(nwid, 0, sizeof(nwid));
ireq.i_data = &nwid;
- if (ioctl(s, SIOCG80211, &ireq) == 0) {
+ if (ioctl(ctx->pf_inet_fd, SIOCG80211, &ireq) == 0) {
if (ssid == NULL)
retval = ireq.i_len;
else if (ireq.i_len > IF_SSIDLEN)
@@ -430,7 +433,7 @@ if_getssid(struct interface *ifp)
{
int r;
- r = if_getssid1(ifp->ctx->pf_inet_fd, ifp->name, ifp->ssid);
+ r = if_getssid1(ifp->ctx, ifp->name, ifp->ssid);
if (r != -1)
ifp->ssid_len = (unsigned int)r;
else
@@ -447,12 +450,11 @@ if_getssid(struct interface *ifp)
* returning the SSID gives an error.
*/
int
-if_vimaster(const struct dhcpcd_ctx *ctx, const char *ifname)
+if_vimaster(struct dhcpcd_ctx *ctx, const char *ifname)
{
int r;
- struct ifmediareq ifmr;
+ struct ifmediareq ifmr = { .ifm_active = 0 };
- memset(&ifmr, 0, sizeof(ifmr));
strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
r = ioctl(ctx->pf_inet_fd, SIOCGIFMEDIA, &ifmr);
if (r == -1)
@@ -460,7 +462,7 @@ if_vimaster(const struct dhcpcd_ctx *ctx
if (ifmr.ifm_status & IFM_AVALID &&
IFM_TYPE(ifmr.ifm_active) == IFM_IEEE80211)
{
- if (if_getssid1(ctx->pf_inet_fd, ifname, NULL) == -1)
+ if (if_getssid1(ctx, ifname, NULL) == -1)
return 1;
}
return 0;
@@ -470,17 +472,15 @@ unsigned short
if_vlanid(const struct interface *ifp)
{
#ifdef SIOCGETVLAN
- struct vlanreq vlr;
+ struct vlanreq vlr = { .vlr_tag = 0 };
- memset(&vlr, 0, sizeof(vlr));
- if (if_indirect_ioctl(ifp->ctx->pf_inet_fd,
- ifp->name, SIOCGETVLAN, &vlr) != 0)
+ if (if_indirect_ioctl(ifp->ctx, ifp->name, SIOCGETVLAN,
+ &vlr, sizeof(vlr)) != 0)
return 0; /* 0 means no VLANID */
return vlr.vlr_tag;
#elif defined(SIOCGVNETID)
- struct ifreq ifr;
+ struct ifreq ifr = { .ifr_vnetid = 0 };
- memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
if (ioctl(ifp->ctx->pf_inet_fd, SIOCGVNETID, &ifr) != 0)
return 0; /* 0 means no VLANID */
@@ -580,7 +580,7 @@ if_findsa(struct dhcpcd_ctx *ctx, const
struct ipv6_addr *ia;
sin = (const void *)sa;
- scope = ifa_getscope(sin);
+ scope = ipv6_getscope(sin);
if (scope != 0)
return if_findindex(ctx->ifaces, scope);
if ((ia = ipv6_findmaskaddr(ctx, &sin->sin6_addr)))
@@ -737,7 +737,7 @@ if_route(unsigned char cmd, const struct
if_copysa(&gateway.sa, &rt->rt_gateway);
#ifdef INET6
if (gateway.sa.sa_family == AF_INET6)
- ifa_setscope(&gateway.sin6, rt->rt_ifp->index);
+ ipv6_setscope(&gateway.sin6, rt->rt_ifp->index);
#endif
ADDSA(&gateway.sa);
}
@@ -960,44 +960,6 @@ if_addrflags(const struct interface *ifp
#endif /* INET */
#ifdef INET6
-static void
-ifa_setscope(struct sockaddr_in6 *sin, unsigned int ifindex)
-{
-
-#ifdef __KAME__
- /* KAME based systems want to store the scope inside the sin6_addr
- * for link local addresses */
- if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
- uint16_t scope = htons((uint16_t)ifindex);
- memcpy(&sin->sin6_addr.s6_addr[2], &scope,
- sizeof(scope));
- }
- sin->sin6_scope_id = 0;
-#else
- if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
- sin->sin6_scope_id = ifindex;
- else
- sin->sin6_scope_id = 0;
-#endif
-}
-
-static unsigned int
-ifa_getscope(const struct sockaddr_in6 *sin)
-{
-#ifdef __KAME__
- uint16_t scope;
-#endif
-
- if (!IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
- return 0;
-#ifdef __KAME__
- memcpy(&scope, &sin->sin6_addr.s6_addr[2], sizeof(scope));
- return (unsigned int)ntohs(scope);
-#else
- return (unsigned int)sin->sin6_scope_id;
-#endif
-}
-
static int
if_ioctl6(struct dhcpcd_ctx *ctx, unsigned long req, void *data, size_t len)
{
@@ -1042,7 +1004,7 @@ if_address6(unsigned char cmd, const str
}
ADDADDR(&ifa.ifra_addr, &ia->addr);
- ifa_setscope(&ifa.ifra_addr, ia->iface->index);
+ ipv6_setscope(&ifa.ifra_addr, ia->iface->index);
ipv6_mask(&mask, ia->prefix_len);
ADDADDR(&ifa.ifra_prefixmask, &mask);
@@ -1120,7 +1082,7 @@ if_addrflags6(const struct interface *if
strlcpy(ifr6.ifr_name, ifp->name, sizeof(ifr6.ifr_name));
ifr6.ifr_addr.sin6_family = AF_INET6;
ifr6.ifr_addr.sin6_addr = *addr;
- ifa_setscope(&ifr6.ifr_addr, ifp->index);
+ ipv6_setscope(&ifr6.ifr_addr, ifp->index);
priv = (struct priv *)ifp->ctx->priv;
if (ioctl(priv->pf_inet6_fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
flags = ifr6.ifr_ifru.ifru_flags6;
@@ -1141,7 +1103,7 @@ if_getlifetime6(struct ipv6_addr *ia)
strlcpy(ifr6.ifr_name, ia->iface->name, sizeof(ifr6.ifr_name));
ifr6.ifr_addr.sin6_family = AF_INET6;
ifr6.ifr_addr.sin6_addr = ia->addr;
- ifa_setscope(&ifr6.ifr_addr, ia->iface->index);
+ ipv6_setscope(&ifr6.ifr_addr, ia->iface->index);
priv = (struct priv *)ia->iface->ctx->priv;
if (ioctl(priv->pf_inet6_fd, SIOCGIFALIFETIME_IN6, &ifr6) == -1)
return -1;
@@ -1330,7 +1292,8 @@ if_ifa(struct dhcpcd_ctx *ctx, const str
break;
#endif
memcpy(&sdl, rti_info[RTAX_IFA], rti_info[RTAX_IFA]->sa_len);
- dhcpcd_handlehwaddr(ctx, ifp->name, CLLADDR(&sdl),sdl.sdl_alen);
+ dhcpcd_handlehwaddr(ifp, ifp->hwtype,
+ CLLADDR(&sdl), sdl.sdl_alen);
break;
}
#ifdef INET
@@ -1516,7 +1479,7 @@ if_missfilter0(struct dhcpcd_ctx *ctx, s
#ifdef INET6
if (sa->sa_family == AF_INET6)
- ifa_setscope(satosin6(sa), ifp->index);
+ ipv6_setscope(satosin6(sa), ifp->index);
#else
UNUSED(ifp);
#endif
@@ -1529,7 +1492,7 @@ if_missfilter0(struct dhcpcd_ctx *ctx, s
#ifdef INET6
if (sa->sa_family == AF_INET6)
- ifa_setscope(satosin6(sa), 0);
+ ipv6_setscope(satosin6(sa), 0);
#endif
return 0;
@@ -1597,7 +1560,7 @@ if_handlelink(struct dhcpcd_ctx *ctx)
}
#ifndef SYS_NMLN /* OSX */
-# define SYS_NMLN 256
+# define SYS_NMLN __SYS_NAMELEN
#endif
#ifndef HW_MACHINE_ARCH
# ifdef HW_MODEL /* OpenBSD */
@@ -1608,13 +1571,8 @@ int
if_machinearch(char *str, size_t len)
{
int mib[2] = { CTL_HW, HW_MACHINE_ARCH };
- char march[SYS_NMLN];
- size_t marchlen = sizeof(march);
- if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
- march, &marchlen, NULL, 0) != 0)
- return -1;
- return snprintf(str, len, ":%s", march);
+ return sysctl(mib, sizeof(mib) / sizeof(mib[0]), str, &len, NULL, 0);
}
#ifdef INET6
@@ -1648,18 +1606,30 @@ if_applyra(const struct ra *rap)
#ifdef SIOCSIFINFO_IN6
struct in6_ndireq nd = { .ndi.chlim = 0 };
struct dhcpcd_ctx *ctx = rap->iface->ctx;
- struct priv *priv = ctx->priv;
int error;
strlcpy(nd.ifname, rap->iface->name, sizeof(nd.ifname));
+
+#ifdef IPV6CTL_ACCEPT_RTADV
+ struct priv *priv = ctx->priv;
+
+ /*
+ * NetBSD changed SIOCSIFINFO_IN6 to NOT set flags when kernel
+ * RA was removed, however both FreeBSD and DragonFlyBSD still do.
+ * linkmtu was also removed.
+ * Hopefully this guard will still work if either remove kernel RA.
+ */
if (ioctl(priv->pf_inet6_fd, SIOCGIFINFO_IN6, &nd, sizeof(nd)) == -1)
return -1;
nd.ndi.linkmtu = rap->mtu;
+#endif
+
nd.ndi.chlim = rap->hoplimit;
nd.ndi.retrans = rap->retrans;
nd.ndi.basereachable = rap->reachable;
error = if_ioctl6(ctx, SIOCSIFINFO_IN6, &nd, sizeof(nd));
+#ifdef IPV6CTL_ACCEPT_RTADV
if (error == -1 && errno == EINVAL) {
/*
* Very likely that this is caused by a dodgy MTU
@@ -1671,6 +1641,7 @@ if_applyra(const struct ra *rap)
nd.ndi.linkmtu = 0;
error = if_ioctl6(ctx, SIOCSIFINFO_IN6, &nd, sizeof(nd));
}
+#endif
return error;
#else
#warning OS does not allow setting of RA bits hoplimit, retrans or reachable
@@ -1812,8 +1783,7 @@ if_setup_inet6(const struct interface *i
#endif
#ifdef ND6_IFF_AUTO_LINKLOCAL
- /* Unlike the kernel,
- * dhcpcd make make a stable private address. */
+ /* Unlike the kernel, dhcpcd make make a stable private address. */
flags &= ~ND6_IFF_AUTO_LINKLOCAL;
#endif
Index: src/external/bsd/dhcpcd/dist/src/ipv6nd.c
diff -u src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.19 src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.20
--- src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.19 Tue Apr 21 09:55:33 2020
+++ src/external/bsd/dhcpcd/dist/src/ipv6nd.c Sun May 31 12:52:11 2020
@@ -188,36 +188,45 @@ ipv6nd_printoptions(const struct dhcpcd_
}
}
-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;
-
- on = 1;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
- &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;
+
+ 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;
@@ -231,7 +240,7 @@ eexit:
#ifdef __sun
int
-ipv6nd_open(struct interface *ifp)
+ipv6nd_openif(struct interface *ifp)
{
int fd;
struct ipv6_mreq mreq = {
@@ -244,7 +253,7 @@ ipv6nd_open(struct interface *ifp)
if (state->nd_fd != -1)
return state->nd_fd;
- fd = ipv6nd_open0();
+ fd = ipv6nd_open(true);
if (fd == -1)
return -1;
@@ -266,24 +275,6 @@ ipv6nd_open(struct interface *ifp)
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
@@ -328,15 +319,21 @@ ipv6nd_sendrsprobe(void *arg)
.sin6_scope_id = ifp->index,
};
struct iovec iov = { .iov_base = state->rs, .iov_len = state->rslen };
- unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
+ union {
+ struct cmsghdr hdr;
+ uint8_t buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+ } cmsgbuf = { .buf = { 0 } };
struct msghdr msg = {
.msg_name = &dst, .msg_namelen = sizeof(dst),
.msg_iov = &iov, .msg_iovlen = 1,
- .msg_control = ctl, .msg_controllen = sizeof(ctl),
+ .msg_control = cmsgbuf.buf, .msg_controllen = sizeof(cmsgbuf.buf),
};
struct cmsghdr *cm;
struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
int s;
+#ifndef __sun
+ struct dhcpcd_ctx *ctx = ifp->ctx;
+#endif
if (ipv6_linklocal(ifp) == NULL) {
logdebugx("%s: delaying Router Solicitation for LL address",
@@ -367,8 +364,22 @@ ipv6nd_sendrsprobe(void *arg)
}
#endif
#ifdef __sun
+ if (state->nd_fd == -1) {
+ if (ipv6nd_openif(ifp) == -1) {
+ logerr(__func__);
+ return;
+ }
+ }
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) {
@@ -402,11 +413,14 @@ ipv6nd_sendadvertisement(void *arg)
.sin6_scope_id = ifp->index,
};
struct iovec iov = { .iov_base = ia->na, .iov_len = ia->na_len };
- unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
+ union {
+ struct cmsghdr hdr;
+ uint8_t buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+ } cmsgbuf = { .buf = { 0 } };
struct msghdr msg = {
.msg_name = &dst, .msg_namelen = sizeof(dst),
.msg_iov = &iov, .msg_iovlen = 1,
- .msg_control = ctl, .msg_controllen = sizeof(ctl),
+ .msg_control = cmsgbuf.buf, .msg_controllen = sizeof(cmsgbuf.buf),
};
struct cmsghdr *cm;
struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
@@ -518,6 +532,12 @@ ipv6nd_advertise(struct ipv6_addr *ia)
na->nd_na_type = ND_NEIGHBOR_ADVERT;
na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE;
+#if defined(PRIVSEP) && (defined(__linux__) || defined(HAVE_PLEDGE))
+ if (IN_PRIVSEP(ctx)) {
+ if (ps_root_ip6forwarding(ctx, ifp->name) == 1)
+ na->nd_na_flags_reserved |= ND_NA_FLAG_ROUTER;
+ } else
+#endif
if (ip6_forwarding(ifp->name) == 1)
na->nd_na_flags_reserved |= ND_NA_FLAG_ROUTER;
na->nd_na_target = ia->addr;
@@ -628,18 +648,25 @@ ipv6nd_sortrouters(struct dhcpcd_ctx *ct
}
static void
-ipv6nd_applyra(struct dhcpcd_ctx *ctx, struct interface *ifp)
+ipv6nd_applyra(struct interface *ifp)
{
struct ra *rap;
struct rs_state *state = RS_STATE(ifp);
+ struct ra defra = {
+ .iface = ifp,
+ .hoplimit = IPV6_DEFHLIM ,
+ .reachable = REACHABLE_TIME,
+ .retrans = RETRANS_TIMER,
+ };
- TAILQ_FOREACH(rap, ctx->ra_routers, next) {
+ TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) {
if (rap->iface == ifp)
break;
}
- if (rap == NULL)
- return;
+ /* If we have no Router Advertisement, then set default values. */
+ if (rap == NULL || rap->expired || rap->willexpire)
+ rap = &defra;
state->retrans = rap->retrans;
if (if_applyra(rap) == -1 && errno != ENOENT)
@@ -681,7 +708,7 @@ ipv6nd_neighbour(struct dhcpcd_ctx *ctx,
/* See if we can install a reachable default router. */
ipv6nd_sortrouters(ctx);
- ipv6nd_applyra(ctx, rap->iface);
+ ipv6nd_applyra(rap->iface);
rt_build(ctx, AF_INET6);
if (reachable)
@@ -927,7 +954,7 @@ ipv6nd_dadcallback(void *arg)
ifp = ia->iface;
wascompleted = (ia->flags & IPV6_AF_DADCOMPLETED);
ia->flags |= IPV6_AF_DADCOMPLETED;
- if (ia->flags & IPV6_AF_DUPLICATED) {
+ if (ia->addr_flags & IN6_IFF_DUPLICATED) {
ia->dadcounter++;
logwarnx("%s: DAD detected %s", ifp->name, ia->saddr);
@@ -1117,6 +1144,23 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
return;
}
+#ifdef NOCARRIER_PRESERVE_IP
+ /*
+ * Because we preserve RA's and expire them quickly after
+ * carrier up, it's important to reset the kernels notion of
+ * reachable timers back to default values before applying
+ * new RA values.
+ */
+ TAILQ_FOREACH(rap, ctx->ra_routers, next) {
+ if (ifp == rap->iface)
+ break;
+ }
+ if (rap != NULL && rap->willexpire) {
+ logerrx("settng def RA");
+ ipv6nd_applyra(ifp);
+ }
+#endif
+
TAILQ_FOREACH(rap, ctx->ra_routers, next) {
if (ifp == rap->iface &&
IN6_ARE_ADDR_EQUAL(&rap->from, &from->sin6_addr))
@@ -1435,7 +1479,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
script_runreason(ifp, "TEST");
goto handle_flag;
}
- ipv6nd_applyra(ifp->ctx, ifp);
+ ipv6nd_applyra(ifp);
ipv6_addaddrs(&rap->addrs);
#ifdef IPV6_MANAGETEMPADDR
ipv6_addtempaddrs(ifp, &rap->acquired);
@@ -1693,7 +1737,7 @@ ipv6nd_expirera(void *arg)
if (rap->lifetime) {
elapsed = (uint32_t)eloop_timespec_diff(&now,
&rap->acquired, NULL);
- if (elapsed > rap->lifetime || rap->doexpire) {
+ if (elapsed >= rap->lifetime || rap->doexpire) {
if (!rap->expired) {
logwarnx("%s: %s: router expired",
ifp->name, rap->sfrom);
@@ -1722,7 +1766,7 @@ ipv6nd_expirera(void *arg)
}
elapsed = (uint32_t)eloop_timespec_diff(&now,
&ia->acquired, NULL);
- if (elapsed > ia->prefix_vltime || rap->doexpire) {
+ if (elapsed >= ia->prefix_vltime || rap->doexpire) {
if (ia->flags & IPV6_AF_ADDED) {
logwarnx("%s: expired %s %s",
ia->iface->name,
@@ -1803,7 +1847,7 @@ ipv6nd_expirera(void *arg)
}
ltime = ntohl(ltime);
- if (elapsed > ltime) {
+ if (elapsed >= ltime) {
expired = true;
continue;
}
@@ -1829,6 +1873,8 @@ ipv6nd_expirera(void *arg)
if (expired) {
logwarnx("%s: part of a Router Advertisement expired",
ifp->name);
+ ipv6nd_sortrouters(ifp->ctx);
+ ipv6nd_applyra(ifp);
rt_build(ifp->ctx, AF_INET6);
script_runreason(ifp, "ROUTERADVERT");
}
@@ -1851,6 +1897,7 @@ ipv6nd_drop(struct interface *ifp)
}
}
if (expired) {
+ ipv6nd_applyra(ifp);
rt_build(ifp->ctx, AF_INET6);
if ((ifp->options->options & DHCPCD_NODROP) != DHCPCD_NODROP)
script_runreason(ifp, "ROUTERADVERT");
@@ -1904,10 +1951,12 @@ ipv6nd_handledata(void *arg)
struct dhcpcd_ctx *ctx;
int fd;
struct sockaddr_in6 from;
- unsigned char buf[64 * 1024]; /* Maximum ICMPv6 size */
+ union {
+ struct icmp6_hdr hdr;
+ uint8_t buf[64 * 1024]; /* Maximum ICMPv6 size */
+ } iovbuf;
struct iovec iov = {
- .iov_base = buf,
- .iov_len = sizeof(buf),
+ .iov_base = iovbuf.buf, .iov_len = sizeof(iovbuf.buf),
};
union {
struct cmsghdr hdr;
@@ -1963,20 +2012,6 @@ ipv6nd_startrs1(void *arg)
#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);
Index: src/external/bsd/dhcpcd/dist/src/if-options.c
diff -u src/external/bsd/dhcpcd/dist/src/if-options.c:1.23 src/external/bsd/dhcpcd/dist/src/if-options.c:1.24
--- src/external/bsd/dhcpcd/dist/src/if-options.c:1.23 Tue Apr 21 09:55:33 2020
+++ src/external/bsd/dhcpcd/dist/src/if-options.c Sun May 31 12:52:11 2020
@@ -27,7 +27,6 @@
*/
#include <sys/param.h>
-#include <sys/stat.h>
#include <sys/types.h>
#include <arpa/inet.h>
@@ -56,58 +55,6 @@
#include "logerr.h"
#include "sa.h"
-/* 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
-
const struct option cf_options[] = {
{"background", no_argument, NULL, 'b'},
{"script", required_argument, NULL, 'c'},
@@ -214,8 +161,6 @@ const struct option cf_options[] = {
{NULL, 0, NULL, '\0'}
};
-static const char *default_script = SCRIPT;
-
static char *
add_environ(char ***array, const char *value, int uniq)
{
@@ -728,26 +673,32 @@ parse_option(struct dhcpcd_ctx *ctx, con
break;
case 'c':
ARG_REQUIRED;
- if (ifo->script != default_script)
- free(ifo->script);
+ if (ifname != NULL) {
+ logerrx("%s: per interface scripts"
+ " are no longer supported",
+ ifname);
+ return -1;
+ }
+ if (ctx->script != dhcpcd_default_script)
+ free(ctx->script);
s = parse_nstring(NULL, 0, arg);
if (s == 0) {
- ifo->script = NULL;
+ ctx->script = NULL;
break;
}
dl = (size_t)s;
- if (s == -1 || (ifo->script = malloc(dl)) == NULL) {
- ifo->script = NULL;
+ if (s == -1 || (ctx->script = malloc(dl)) == NULL) {
+ ctx->script = NULL;
logerr(__func__);
return -1;
}
- s = parse_nstring(ifo->script, dl, arg);
+ s = parse_nstring(ctx->script, dl, arg);
if (s == -1 ||
- ifo->script[0] == '\0' ||
- strcmp(ifo->script, "/dev/null") == 0)
+ ctx->script[0] == '\0' ||
+ strcmp(ctx->script, "/dev/null") == 0)
{
- free(ifo->script);
- ifo->script = NULL;
+ free(ctx->script);
+ ctx->script = NULL;
}
break;
case 'd':
@@ -1291,7 +1242,7 @@ parse_option(struct dhcpcd_ctx *ctx, con
del_option_mask(ifo->nomask, DHO_DNSSEARCH);
#endif
-#ifdef INET6
+#ifdef DHCP6
del_option_mask(ifo->nomask6, D6_OPTION_DNS_SERVERS);
del_option_mask(ifo->nomask6, D6_OPTION_DOMAIN_LIST);
del_option_mask(ifo->nomask6, D6_OPTION_SOL_MAX_RT);
@@ -2145,7 +2096,7 @@ invalid_token:
logerr(__func__);
return -1;
}
- while ((i = getgrnam_r(arg, &grpbuf, p, (size_t)l, &grp)) ==
+ while ((i = getgrnam_r(arg, &grpbuf, p, dl, &grp)) ==
ERANGE)
{
size_t nl = dl * 2;
@@ -2170,7 +2121,8 @@ invalid_token:
return -1;
}
if (grp == NULL) {
- logerrx("controlgroup: %s: not found", arg);
+ if (!ctx->control_group)
+ logerrx("controlgroup: %s: not found", arg);
free(p);
return -1;
}
@@ -2179,7 +2131,8 @@ invalid_token:
#else
grp = getgrnam(arg);
if (grp == NULL) {
- logerrx("controlgroup: %s: not found", arg);
+ if (!ctx->control_group)
+ logerrx("controlgroup: %s: not found", arg);
return -1;
}
ctx->control_group = grp->gr_gid;
@@ -2308,45 +2261,6 @@ finish_config(struct if_options *ifo)
~(DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS);
}
-/* 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. */
-static char *
-get_line(char ** __restrict buf, size_t * __restrict buflen,
- FILE * __restrict fp)
-{
- char *p, *c;
- ssize_t bytes;
- int quoted;
-
- do {
- bytes = getline(buf, buflen, fp);
- if (bytes == -1)
- return NULL;
- for (p = *buf; *p == ' ' || *p == '\t'; p++)
- ;
- } while (*p == '\0' || *p == '\n' || *p == '#' || *p == ';');
- if ((*buf)[--bytes] == '\n')
- (*buf)[bytes] = '\0';
-
- /* Strip embedded comments unless in a quoted string or escaped */
- quoted = 0;
- for (c = p; *c != '\0'; c++) {
- if (*c == '\\') {
- c++; /* escaped */
- continue;
- }
- if (*c == '"')
- quoted = !quoted;
- else if (*c == '#' && !quoted) {
- *c = '\0';
- break;
- }
- }
- return p;
-}
-
struct if_options *
default_config(struct dhcpcd_ctx *ctx)
{
@@ -2360,7 +2274,6 @@ default_config(struct dhcpcd_ctx *ctx)
ifo->options |= DHCPCD_IF_UP | DHCPCD_LINK | DHCPCD_INITIAL_DELAY;
ifo->timeout = DEFAULT_TIMEOUT;
ifo->reboot = DEFAULT_REBOOT;
- ifo->script = UNCONST(default_script);
ifo->metric = -1;
ifo->auth.options |= DHCPCD_AUTH_REQUIRE;
rb_tree_init(&ifo->routes, &rt_compare_list_ops);
@@ -2382,16 +2295,11 @@ read_config(struct dhcpcd_ctx *ctx,
const char *ifname, const char *ssid, const char *profile)
{
struct if_options *ifo;
- FILE *fp;
- struct stat sb;
- char *line, *buf, *option, *p;
- size_t buflen;
- ssize_t vlen;
+ char buf[UDPLEN_MAX], *bp; /* 64k max config file size */
+ char *line, *option, *p;
+ ssize_t buflen;
+ size_t vlen;
int skip, have_profile, new_block, had_block;
-#ifndef EMBEDDED_CONFIG
- const char * const *e;
- size_t ol;
-#endif
#if !defined(INET) || !defined(INET6)
size_t i;
struct dhcp_opt *opt;
@@ -2414,12 +2322,9 @@ read_config(struct dhcpcd_ctx *ctx,
ifo->options |= DHCPCD_DHCP6;
#endif
- vlen = dhcp_vendor((char *)ifo->vendorclassid + 1,
- sizeof(ifo->vendorclassid) - 1);
- ifo->vendorclassid[0] = (uint8_t)(vlen == -1 ? 0 : vlen);
-
- buf = NULL;
- buflen = 0;
+ vlen = strlcpy((char *)ifo->vendorclassid + 1, ctx->vendor,
+ sizeof(ifo->vendorclassid) - 1);
+ ifo->vendorclassid[0] = (uint8_t)(vlen > 255 ? 0 : vlen);
/* Reset route order */
ctx->rt_order = 0;
@@ -2455,38 +2360,27 @@ read_config(struct dhcpcd_ctx *ctx,
/* Now load our embedded config */
#ifdef EMBEDDED_CONFIG
- fp = fopen(EMBEDDED_CONFIG, "r");
- if (fp == NULL)
- logerr("%s: fopen `%s'", __func__, EMBEDDED_CONFIG);
-
- while (fp && (line = get_line(&buf, &buflen, fp))) {
+ buflen = dhcp_readfile(ctx, EMBEDDED_CONFIG, buf, sizeof(buf));
+ if (buflen == -1) {
+ logerr("%s: %s", __func__, EMBEDDED_CONFIG);
+ return ifo;
+ }
+ if (buf[buflen - 1] != '\0') {
+ if (buflen < sizeof(buf) - 1)
+ bulen++;
+ buf[buflen - 1] = '\0';
+ }
#else
- buflen = 80;
- buf = malloc(buflen);
- if (buf == NULL) {
- logerr(__func__);
- free_options(ctx, ifo);
- return NULL;
+ buflen = (ssize_t)strlcpy(buf, dhcpcd_embedded_conf,
+ sizeof(buf));
+ if ((size_t)buflen >= sizeof(buf)) {
+ logerrx("%s: embedded config too big", __func__);
+ return ifo;
}
- ldop = edop = NULL;
- for (e = dhcpcd_embedded_conf; *e; e++) {
- ol = strlen(*e) + 1;
- if (ol > buflen) {
- char *nbuf;
-
- buflen = ol;
- nbuf = realloc(buf, buflen);
- if (nbuf == NULL) {
- logerr(__func__);
- free(buf);
- free_options(ctx, ifo);
- return NULL;
- }
- buf = nbuf;
- }
- memcpy(buf, *e, ol);
- line = buf;
+ /* Our embedded config is NULL terminated */
#endif
+ bp = buf;
+ while ((line = get_line(&bp, &buflen)) != NULL) {
option = strsep(&line, " \t");
if (line)
line = strskipwhite(line);
@@ -2500,13 +2394,8 @@ read_config(struct dhcpcd_ctx *ctx,
}
parse_config_line(ctx, NULL, ifo, option, line,
&ldop, &edop);
-
}
-#ifdef EMBEDDED_CONFIG
- if (fp)
- fclose(fp);
-#endif
#ifdef INET
ctx->dhcp_opts = ifo->dhcp_override;
ctx->dhcp_opts_len = ifo->dhcp_override_len;
@@ -2551,26 +2440,25 @@ read_config(struct dhcpcd_ctx *ctx,
}
/* Parse our options file */
-#ifdef PRIVSEP
- if (ctx->options & DHCPCD_PRIVSEP &&
- ps_root_copychroot(ctx, ctx->cffile) == -1)
- logwarn("%s: ps_root_copychroot `%s'", __func__, ctx->cffile);
-#endif
- fp = fopen(ctx->cffile, "r");
- if (fp == NULL) {
+ buflen = dhcp_readfile(ctx, ctx->cffile, buf, sizeof(buf));
+ if (buflen == -1) {
/* dhcpcd can continue without it, but no DNS options
* would be requested ... */
- logwarn("%s: fopen `%s'", __func__, ctx->cffile);
- free(buf);
+ logerr("%s: %s", __func__, ctx->cffile);
return ifo;
}
- if (stat(ctx->cffile, &sb) == 0)
- ifo->mtime = sb.st_mtime;
+ if (buf[buflen - 1] != '\0') {
+ if ((size_t)buflen < sizeof(buf) - 1)
+ buflen++;
+ buf[buflen - 1] = '\0';
+ }
+ dhcp_filemtime(ctx, ctx->cffile, &ifo->mtime);
ldop = edop = NULL;
skip = have_profile = new_block = 0;
had_block = ifname == NULL ? 1 : 0;
- while ((line = get_line(&buf, &buflen, fp))) {
+ bp = buf;
+ while ((line = get_line(&bp, &buflen)) != NULL) {
option = strsep(&line, " \t");
if (line)
line = strskipwhite(line);
@@ -2644,10 +2532,9 @@ read_config(struct dhcpcd_ctx *ctx,
continue;
if (skip)
continue;
+
parse_config_line(ctx, ifname, ifo, option, line, &ldop, &edop);
}
- fclose(fp);
- free(buf);
if (profile && !have_profile) {
free_options(ctx, ifo);
@@ -2738,8 +2625,6 @@ free_options(struct dhcpcd_ctx *ctx, str
#endif
rt_headclear0(ctx, &ifo->routes, AF_UNSPEC);
- if (ifo->script != default_script)
- free(ifo->script);
free(ifo->arping);
free(ifo->blacklist);
free(ifo->fallback);
Index: src/external/bsd/dhcpcd/dist/src/ipv6.c
diff -u src/external/bsd/dhcpcd/dist/src/ipv6.c:1.11 src/external/bsd/dhcpcd/dist/src/ipv6.c:1.12
--- src/external/bsd/dhcpcd/dist/src/ipv6.c:1.11 Tue Apr 21 09:55:33 2020
+++ src/external/bsd/dhcpcd/dist/src/ipv6.c Sun May 31 12:52:11 2020
@@ -69,6 +69,7 @@
#include "ipv6.h"
#include "ipv6nd.h"
#include "logerr.h"
+#include "privsep.h"
#include "sa.h"
#include "script.h"
@@ -139,25 +140,27 @@ ipv6_init(struct dhcpcd_ctx *ctx)
#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 ssize_t
ipv6_readsecret(struct dhcpcd_ctx *ctx)
{
- FILE *fp;
char line[1024];
unsigned char *p;
size_t len;
uint32_t r;
- int x;
- if ((ctx->secret_len = read_hwaddr_aton(&ctx->secret, SECRET)) != 0)
+ ctx->secret_len = dhcp_read_hwaddr_aton(ctx, &ctx->secret, SECRET);
+ if (ctx->secret_len != 0)
return (ssize_t)ctx->secret_len;
if (errno != ENOENT)
- logerr("%s: %s", __func__, SECRET);
+ logerr("%s: cannot read secret", __func__);
/* Chaining arc4random should be good enough.
* RFC7217 section 5.1 states the key SHOULD be at least 128 bits.
@@ -177,27 +180,18 @@ ipv6_readsecret(struct dhcpcd_ctx *ctx)
p += sizeof(r);
}
- /* Ensure that only the dhcpcd user can read the secret.
- * Write permission is also denied as changing it would remove
- * it's stability. */
- if ((fp = fopen(SECRET, "w")) == NULL ||
- chmod(SECRET, S_IRUSR) == -1)
- goto eexit;
- x = fprintf(fp, "%s\n",
- hwaddr_ntoa(ctx->secret, ctx->secret_len, line, sizeof(line)));
- if (fclose(fp) == EOF)
- x = -1;
- fp = NULL;
- if (x > 0)
- return (ssize_t)ctx->secret_len;
-
-eexit:
- logerr("%s: %s", __func__, SECRET);
- if (fp != NULL)
- fclose(fp);
- unlink(SECRET);
- ctx->secret_len = 0;
- return -1;
+ hwaddr_ntoa(ctx->secret, ctx->secret_len, line, sizeof(line));
+ len = strlen(line);
+ if (len < sizeof(line) - 2) {
+ line[len++] = '\n';
+ line[len] = '\0';
+ }
+ if (dhcp_writefile(ctx, SECRET, S_IRUSR, line, len) == -1) {
+ logerr("%s: cannot write secret", __func__);
+ ctx->secret_len = 0;
+ return -1;
+ }
+ return (ssize_t)ctx->secret_len;
}
/* http://www.iana.org/assignments/ipv6-interface-ids/ipv6-interface-ids.xhtml
@@ -600,6 +594,7 @@ static void
ipv6_deletedaddr(struct ipv6_addr *ia)
{
+#ifdef DHCP6
#ifdef PRIVSEP
if (!(ia->iface->ctx->options & DHCPCD_MASTER))
ps_inet_closedhcp6(ia);
@@ -613,6 +608,9 @@ ipv6_deletedaddr(struct ipv6_addr *ia)
if (ia->delegating_prefix != NULL)
ia->delegating_prefix->flags &= ~IPV6_AF_NOREJECT;
#endif
+#else
+ UNUSED(ia);
+#endif
}
void
@@ -1094,10 +1092,33 @@ ipv6_anyglobal(struct interface *sifp)
struct interface *ifp;
struct ipv6_state *state;
struct ipv6_addr *ia;
+#ifdef BSD
+ bool forwarding;
+
+#if defined(PRIVSEP) && defined(HAVE_PLEDGE)
+ if (IN_PRIVSEP(sifp->ctx))
+ forwarding = ps_root_ip6forwarding(sifp->ctx, NULL) == 1;
+ else
+#endif
+ forwarding = ip6_forwarding(NULL) == 1;
+#endif
+
TAILQ_FOREACH(ifp, sifp->ctx->ifaces, next) {
+#ifdef BSD
+ if (ifp != sifp && !forwarding)
+ continue;
+#else
+#if defined(PRIVSEP) && defined(__linux__)
+ if (IN_PRIVSEP(sifp->ctx)) {
+ if (ifp != sifp &&
+ ps_root_ip6forwarding(sifp->ctx, ifp->name) != 1)
+ continue;
+ } else
+#endif
if (ifp != sifp && ip6_forwarding(ifp->name) != 1)
continue;
+#endif
state = IPV6_STATE(ifp);
if (state == NULL)
@@ -1227,11 +1248,8 @@ ipv6_handleifa(struct dhcpcd_ctx *ctx,
}
#endif
- if (ia->dadcallback) {
+ if (ia->dadcallback)
ia->dadcallback(ia);
- if (ctx->options & DHCPCD_FORKED)
- goto out;
- }
if (IN6_IS_ADDR_LINKLOCAL(&ia->addr) &&
!(ia->addr_flags & IN6_IFF_NOTUSEABLE))
@@ -1246,8 +1264,6 @@ ipv6_handleifa(struct dhcpcd_ctx *ctx,
cb, next);
cb->callback(cb->arg);
free(cb);
- if (ctx->options & DHCPCD_FORKED)
- goto out;
}
}
}
@@ -1263,7 +1279,6 @@ ipv6_handleifa(struct dhcpcd_ctx *ctx,
dhcp6_handleifa(cmd, ia, pid);
#endif
-out:
/* Done with the ia now, so free it. */
if (cmd == RTM_DELADDR)
ipv6_freeaddr(ia);
@@ -1406,7 +1421,7 @@ ipv6_addlinklocal(struct interface *ifp)
/* Check sanity before malloc */
if (!(ifp->options->options & DHCPCD_SLAACPRIVATE)) {
- switch (ifp->family) {
+ switch (ifp->hwtype) {
case ARPHRD_ETHER:
/* Check for a valid hardware address */
if (ifp->hwlen != 6 && ifp->hwlen != 8) {
@@ -1446,7 +1461,7 @@ nextslaacprivate:
ap->dadcounter = dadcounter;
} else {
memcpy(ap->addr.s6_addr, ap->prefix.s6_addr, 8);
- switch (ifp->family) {
+ switch (ifp->hwtype) {
case ARPHRD_ETHER:
if (ifp->hwlen == 6) {
ap->addr.s6_addr[ 8] = ifp->hwaddr[0];
@@ -1532,6 +1547,44 @@ ipv6_tryaddlinklocal(struct interface *i
return ipv6_addlinklocal(ifp);
}
+void
+ipv6_setscope(struct sockaddr_in6 *sin, unsigned int ifindex)
+{
+
+#ifdef __KAME__
+ /* KAME based systems want to store the scope inside the sin6_addr
+ * for link local addresses */
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
+ uint16_t scope = htons((uint16_t)ifindex);
+ memcpy(&sin->sin6_addr.s6_addr[2], &scope,
+ sizeof(scope));
+ }
+ sin->sin6_scope_id = 0;
+#else
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
+ sin->sin6_scope_id = ifindex;
+ else
+ sin->sin6_scope_id = 0;
+#endif
+}
+
+unsigned int
+ipv6_getscope(const struct sockaddr_in6 *sin)
+{
+#ifdef __KAME__
+ uint16_t scope;
+#endif
+
+ if (!IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
+ return 0;
+#ifdef __KAME__
+ memcpy(&scope, &sin->sin6_addr.s6_addr[2], sizeof(scope));
+ return (unsigned int)ntohs(scope);
+#else
+ return (unsigned int)sin->sin6_scope_id;
+#endif
+}
+
struct ipv6_addr *
ipv6_newaddr(struct interface *ifp, const struct in6_addr *addr,
uint8_t prefix_len, unsigned int flags)
@@ -1635,7 +1688,7 @@ ipv6_staticdadcallback(void *arg)
wascompleted = (ia->flags & IPV6_AF_DADCOMPLETED);
ia->flags |= IPV6_AF_DADCOMPLETED;
- if (ia->flags & IPV6_AF_DUPLICATED)
+ if (ia->addr_flags & IN6_IFF_DUPLICATED)
logwarnx("%s: DAD detected %s", ia->iface->name,
ia->saddr);
else if (!wascompleted) {
@@ -1838,16 +1891,13 @@ ipv6_handleifa_addrs(int cmd,
}
break;
case RTM_NEWADDR:
+ ia->addr_flags = addr->addr_flags;
/* Safety - ignore tentative announcements */
- if (addr->addr_flags &
+ if (ia->addr_flags &
(IN6_IFF_DETACHED | IN6_IFF_TENTATIVE))
break;
if ((ia->flags & IPV6_AF_DADCOMPLETED) == 0) {
found++;
- if (addr->addr_flags & IN6_IFF_DUPLICATED)
- ia->flags |= IPV6_AF_DUPLICATED;
- else
- ia->flags &= ~IPV6_AF_DUPLICATED;
if (ia->dadcallback)
ia->dadcallback(ia);
/* We need to set this here in-case the
@@ -1890,7 +1940,7 @@ ipv6_tempdadcallback(void *arg)
{
struct ipv6_addr *ia = arg;
- if (ia->flags & IPV6_AF_DUPLICATED) {
+ if (ia->addr_flags & IN6_IFF_DUPLICATED) {
struct ipv6_addr *ia1;
struct timespec tv;
@@ -2076,10 +2126,22 @@ ipv6_regentempaddrs(void *arg)
ipv6_regen_desync(ifp, true);
clock_gettime(CLOCK_MONOTONIC, &tv);
+
+ /* Mark addresses for regen so we don't infinite loop. */
TAILQ_FOREACH(ia, &state->addrs, next) {
if (ia->flags & IPV6_AF_TEMPORARY &&
!(ia->flags & IPV6_AF_STALE))
+ ia->flags |= IPV6_AF_REGEN;
+ else
+ ia->flags &= ~IPV6_AF_REGEN;
+ }
+
+ /* Now regen temp addrs */
+ TAILQ_FOREACH(ia, &state->addrs, next) {
+ if (ia->flags & IPV6_AF_REGEN) {
ipv6_regentempaddr0(ia, &tv);
+ ia->flags &= ~IPV6_AF_REGEN;
+ }
}
}
#endif /* IPV6_MANAGETEMPADDR */
Index: src/external/bsd/dhcpcd/dist/src/ipv6.h
diff -u src/external/bsd/dhcpcd/dist/src/ipv6.h:1.10 src/external/bsd/dhcpcd/dist/src/ipv6.h:1.11
--- src/external/bsd/dhcpcd/dist/src/ipv6.h:1.10 Mon Apr 13 15:46:26 2020
+++ src/external/bsd/dhcpcd/dist/src/ipv6.h Sun May 31 12:52:11 2020
@@ -216,16 +216,16 @@ struct ipv6_addr {
#define IPV6_AF_STALE (1U << 2)
#define IPV6_AF_ADDED (1U << 3)
#define IPV6_AF_AUTOCONF (1U << 4)
-#define IPV6_AF_DUPLICATED (1U << 5)
-#define IPV6_AF_DADCOMPLETED (1U << 6)
-#define IPV6_AF_DELEGATED (1U << 7)
-#define IPV6_AF_DELEGATEDPFX (1U << 8)
-#define IPV6_AF_NOREJECT (1U << 9)
-#define IPV6_AF_REQUEST (1U << 10)
-#define IPV6_AF_STATIC (1U << 11)
-#define IPV6_AF_DELEGATEDLOG (1U << 12)
-#define IPV6_AF_RAPFX (1U << 13)
-#define IPV6_AF_EXTENDED (1U << 14)
+#define IPV6_AF_DADCOMPLETED (1U << 5)
+#define IPV6_AF_DELEGATED (1U << 6)
+#define IPV6_AF_DELEGATEDPFX (1U << 7)
+#define IPV6_AF_NOREJECT (1U << 8)
+#define IPV6_AF_REQUEST (1U << 9)
+#define IPV6_AF_STATIC (1U << 10)
+#define IPV6_AF_DELEGATEDLOG (1U << 11)
+#define IPV6_AF_RAPFX (1U << 12)
+#define IPV6_AF_EXTENDED (1U << 13)
+#define IPV6_AF_REGEN (1U << 14)
#ifdef IPV6_MANAGETEMPADDR
#define IPV6_AF_TEMPORARY (1U << 15)
#endif
@@ -287,8 +287,10 @@ struct ipv6_addr *ipv6_findmaskaddr(stru
const struct in6_addr *);
#define ipv6_linklocal(ifp) ipv6_iffindaddr((ifp), NULL, IN6_IFF_NOTUSEABLE)
int ipv6_addlinklocalcallback(struct interface *, void (*)(void *), void *);
-struct ipv6_addr *ipv6_newaddr(struct interface *, const struct in6_addr *, uint8_t,
- unsigned int);
+void ipv6_setscope(struct sockaddr_in6 *, unsigned int);
+unsigned int ipv6_getscope(const struct sockaddr_in6 *);
+struct ipv6_addr *ipv6_newaddr(struct interface *, const struct in6_addr *,
+ uint8_t, unsigned int);
void ipv6_freeaddr(struct ipv6_addr *);
void ipv6_freedrop(struct interface *, int);
#define ipv6_free(ifp) ipv6_freedrop((ifp), 0)
Index: src/external/bsd/dhcpcd/dist/src/logerr.c
diff -u src/external/bsd/dhcpcd/dist/src/logerr.c:1.3 src/external/bsd/dhcpcd/dist/src/logerr.c:1.4
--- src/external/bsd/dhcpcd/dist/src/logerr.c:1.3 Thu Apr 2 12:41:48 2020
+++ src/external/bsd/dhcpcd/dist/src/logerr.c Sun May 31 12:52:11 2020
@@ -104,7 +104,6 @@ logprintdate(FILE *stream)
return -1;
now = tv.tv_sec;
- tzset();
if (localtime_r(&now, &tmnow) == NULL)
return -1;
if (strftime(buf, sizeof(buf), "%b %d %T ", &tmnow) == 0)
@@ -238,6 +237,7 @@ vlogerrmessage(int pri, const char *fmt,
vsnprintf(buf, sizeof(buf), fmt, args);
logmessage(pri, "%s: %s", buf, strerror(_errno));
+ errno = _errno;
}
__printflike(2, 3) void
@@ -366,6 +366,9 @@ logopen(const char *path)
{
struct logctx *ctx = &_logctx;
+ /* Cache timezone */
+ tzset();
+
if (path == NULL) {
int opts = 0;
Index: src/external/bsd/dhcpcd/dist/src/privsep.c
diff -u src/external/bsd/dhcpcd/dist/src/privsep.c:1.2 src/external/bsd/dhcpcd/dist/src/privsep.c:1.3
--- src/external/bsd/dhcpcd/dist/src/privsep.c:1.2 Wed Apr 15 15:55:24 2020
+++ src/external/bsd/dhcpcd/dist/src/privsep.c Sun May 31 12:52:11 2020
@@ -63,6 +63,7 @@
#include "arp.h"
#include "common.h"
#include "control.h"
+#include "dev.h"
#include "dhcp.h"
#include "dhcp6.h"
#include "eloop.h"
@@ -70,36 +71,18 @@
#include "logerr.h"
#include "privsep.h"
+#ifdef HAVE_CAPSICUM
+#include <sys/capsicum.h>
+#endif
#ifdef HAVE_UTIL_H
#include <util.h>
#endif
int
-ps_mkdir(char *path)
-{
- char *slash;
- bool done;
-
- slash = path;
- for (;;) {
- slash += strspn(slash, "/");
- slash += strcspn(slash, "/");
- done = (*slash == '\0');
- *slash = '\0';
- if (mkdir(path, 0755) == -1 && errno != EEXIST)
- return -1;
- if (done)
- break;
- *slash = '/';
- }
- return 0;
-}
-
-int
ps_init(struct dhcpcd_ctx *ctx)
{
- char path[PATH_MAX];
- struct passwd *pw = ctx->ps_user;
+ struct passwd *pw;
+ struct stat st;
errno = 0;
if ((ctx->ps_user = pw = getpwnam(PRIVSEP_USER)) == NULL) {
@@ -113,25 +96,14 @@ ps_init(struct dhcpcd_ctx *ctx)
return -1;
}
- /* If we pickup the _dhcp user refuse the default directory */
- if (strcmp(pw->pw_dir, "/var/empty") == 0) {
+ if (stat(pw->pw_dir, &st) == -1 || !S_ISDIR(st.st_mode)) {
ctx->options &= ~DHCPCD_PRIVSEP;
- logerrx("refusing chroot: %s: %s", PRIVSEP_USER, pw->pw_dir);
+ logerrx("refusing chroot: %s: %s",
+ PRIVSEP_USER, pw->pw_dir);
errno = 0;
return -1;
}
- /* Create the database directory. */
- if (snprintf(path, sizeof(path), "%s%s", pw->pw_dir, DBDIR) == -1 ||
- ps_mkdir(path) == -1 ||
- chown(path, pw->pw_uid, pw->pw_gid) == -1 ||
- chmod(path, 0755) == -1)
- logerr("%s: %s", __func__, path);
-
- /* Ensure we have a localtime to correctly format dates. */
- if (ps_root_docopychroot(ctx, "/etc/localtime") == -1 && errno!=ENOENT)
- logerr("%s: %s", __func__, "/etc/localtime");
-
ctx->options |= DHCPCD_PRIVSEP;
return 0;
}
@@ -142,8 +114,7 @@ ps_dropprivs(struct dhcpcd_ctx *ctx)
struct passwd *pw = ctx->ps_user;
if (!(ctx->options & DHCPCD_FORKED))
- logdebugx("chrooting to `%s'", pw->pw_dir);
-
+ logdebugx("chrooting to `%s' as %s", pw->pw_dir, pw->pw_name);
if (chroot(pw->pw_dir) == -1)
logerr("%s: chroot `%s'", __func__, pw->pw_dir);
if (chdir("/") == -1)
@@ -170,6 +141,11 @@ ps_dostart(struct dhcpcd_ctx *ctx,
int stype;
int fd[2];
pid_t pid;
+#ifdef HAVE_CAPSICUM
+ cap_rights_t rights;
+
+ cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_EVENT, CAP_SHUTDOWN);
+#endif
stype = SOCK_CLOEXEC | SOCK_NONBLOCK;
if (socketpair(AF_UNIX, SOCK_DGRAM | stype, 0, fd) == -1) {
@@ -189,8 +165,17 @@ ps_dostart(struct dhcpcd_ctx *ctx,
*priv_pid = pid;
*priv_fd = fd[0];
close(fd[1]);
- if (recv_unpriv_msg != NULL &&
- eloop_event_add(ctx->eloop, *priv_fd,
+ if (recv_unpriv_msg == NULL)
+ ;
+#ifdef HAVE_CAPSICUM
+ else if (cap_rights_limit(*priv_fd, &rights) == -1
+ && errno != ENOSYS)
+ {
+ logerr("%s: cap_rights_limit", __func__);
+ return -1;
+ }
+#endif
+ else if (eloop_event_add(ctx->eloop, *priv_fd,
recv_unpriv_msg, recv_ctx) == -1)
{
logerr("%s: eloop_event_add", __func__);
@@ -234,6 +219,11 @@ ps_dostart(struct dhcpcd_ctx *ctx,
goto errexit;
}
+#ifdef HAVE_CAPSICUM
+ if (cap_rights_limit(*priv_fd, &rights) == -1 && errno != ENOSYS)
+ goto errexit;
+#endif
+
if (eloop_event_add(ctx->eloop, *priv_fd, recv_msg, recv_ctx) == -1)
{
logerr("%s: eloop_event_add", __func__);
@@ -246,8 +236,8 @@ ps_dostart(struct dhcpcd_ctx *ctx,
if (!(ctx->options & DHCPCD_DEBUG) &&
(!(ctx->options & DHCPCD_TEST) || loggetopts() & LOGERR_QUIET))
{
- freopen(_PATH_DEVNULL, "w", stdout);
- freopen(_PATH_DEVNULL, "w", stderr);
+ (void)freopen(_PATH_DEVNULL, "w", stdout);
+ (void)freopen(_PATH_DEVNULL, "w", stderr);
}
if (flags & PSF_DROPPRIVS)
@@ -258,7 +248,7 @@ ps_dostart(struct dhcpcd_ctx *ctx,
errexit:
/* Failure to start root or inet processes is fatal. */
if (priv_fd == &ctx->ps_root_fd || priv_fd == &ctx->ps_inet_fd)
- ps_sendcmd(ctx, *priv_fd, PS_STOP, 0, NULL, 0);
+ (void)ps_sendcmd(ctx, *priv_fd, PS_STOP, 0, NULL, 0);
shutdown(*priv_fd, SHUT_RDWR);
*priv_fd = -1;
return -1;
@@ -288,6 +278,18 @@ ps_dostop(struct dhcpcd_ctx *ctx, pid_t
logerr(__func__);
#endif
status = 0;
+
+#ifdef HAVE_CAPSICUM
+ unsigned int cap_mode = 0;
+ int cap_err = cap_getmode(&cap_mode);
+
+ if (cap_err == -1) {
+ if (errno != ENOSYS)
+ logerr("%s: cap_getmode", __func__);
+ } else if (cap_mode != 0)
+ goto nowait;
+#endif
+
/* Wait for the process to finish */
while (waitpid(*pid, &status, 0) == -1) {
if (errno != EINTR) {
@@ -300,6 +302,9 @@ ps_dostop(struct dhcpcd_ctx *ctx, pid_t
logerr("%s: waitpid ", __func__);
#endif
}
+#ifdef HAVE_CAPSICUM
+nowait:
+#endif
*pid = 0;
#ifdef PRIVSEP_DEBUG
@@ -318,6 +323,7 @@ ps_start(struct dhcpcd_ctx *ctx)
switch (pid = ps_root_start(ctx)) {
case -1:
+ logerr("ps_root_start");
return -1;
case 0:
return 0;
@@ -327,7 +333,7 @@ ps_start(struct dhcpcd_ctx *ctx)
/* No point in spawning the generic network listener if we're
* not going to use it. */
- if (!(ctx->options & (DHCPCD_MASTER | DHCPCD_IPV6RS)))
+ if (!(ctx->options & (DHCPCD_MASTER | DHCPCD_IPV6)))
goto started;
switch (pid = ps_inet_start(ctx)) {
@@ -342,6 +348,13 @@ ps_start(struct dhcpcd_ctx *ctx)
}
started:
+
+#ifdef ARC4RANDOM_H
+ /* Seed the random number generator early incase it needs /dev/urandom
+ * which won't be available in the chroot. */
+ arc4random();
+#endif
+
return 1;
}
@@ -374,14 +387,6 @@ ps_stop(struct dhcpcd_ctx *ctx)
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) {
@@ -392,6 +397,10 @@ ps_freeprocess(struct ps_process *psp)
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);
}
@@ -452,26 +461,24 @@ ps_unrollmsg(struct msghdr *msg, struct
return 0;
}
-
ssize_t
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);
+ int i;
psm->ps_namelen = msg->msg_namelen;
psm->ps_controllen = (socklen_t)msg->msg_controllen;
@@ -481,10 +488,18 @@ ps_sendpsmmsg(struct dhcpcd_ctx *ctx, in
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 < (int)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;
@@ -513,18 +528,19 @@ ps_sendpsmdata(struct dhcpcd_ctx *ctx, i
ssize_t
-ps_sendmsg(struct dhcpcd_ctx *ctx, int fd, uint8_t cmd, unsigned long flags,
+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));
@@ -555,7 +571,7 @@ ps_sendmsg(struct dhcpcd_ctx *ctx, int f
}
ssize_t
-ps_sendcmd(struct dhcpcd_ctx *ctx, int fd, uint8_t cmd, unsigned long flags,
+ps_sendcmd(struct dhcpcd_ctx *ctx, int fd, uint16_t cmd, unsigned long flags,
const void *data, size_t len)
{
struct ps_msghdr psm = {
@@ -573,7 +589,7 @@ ps_sendcmd(struct dhcpcd_ctx *ctx, int f
}
static ssize_t
-ps_sendcmdmsg(int fd, uint8_t cmd, const struct msghdr *msg)
+ps_sendcmdmsg(int fd, uint16_t cmd, const struct msghdr *msg)
{
struct ps_msghdr psm = { .ps_cmd = cmd };
uint8_t data[PS_BUFLEN], *p = data;
@@ -616,7 +632,7 @@ nobufs:
}
ssize_t
-ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, uint8_t cmd, int wfd)
+ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, uint16_t cmd, int wfd)
{
struct sockaddr_storage ss = { .ss_family = AF_UNSPEC };
uint8_t controlbuf[sizeof(struct sockaddr_storage)] = { 0 };
@@ -688,6 +704,9 @@ ps_recvpsmsg(struct dhcpcd_ctx *ctx, int
logdebugx("process %d stopping", getpid());
#endif
ps_free(ctx);
+#ifdef PLUGIN_DEV
+ dev_stop(ctx);
+#endif
eloop_exit(ctx->eloop, len != -1 ? EXIT_SUCCESS : EXIT_FAILURE);
return len;
}
@@ -696,6 +715,9 @@ ps_recvpsmsg(struct dhcpcd_ctx *ctx, int
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);
}