Import dhcpcd-8.0.3 With the following changes:

*  DHCP: Work with IP headers with options
 *  script: Assert that env string are correctly terminated
 *  script: Terminate env strings with no value
 *  script: Don't attempt to use an invalid env string
 *  route: Fix NULL deference error when using static routes
 *  ARP: Respect IFF_NOARP
 *  DHCP: Allow full DHCP support for PtP interfaces, but not by default
 *  control: sends correct buffer to listeners

dhcpcd-ui now correctly reports SSD association and all the addresses obtained (regression from dhcpcd-7)
This commit is contained in:
roy 2019-08-21 17:10:29 +00:00
parent b6a3a94eb1
commit 4dfdf2681a
18 changed files with 311 additions and 206 deletions

View File

@ -558,6 +558,15 @@ bpf_arp(struct interface *ifp, int fd)
#define BPF_M_UDP 3
#define BPF_M_UDPLEN 4
#ifdef ARPHRD_NONE
static const struct bpf_insn bpf_bootp_none[] = {
/* Set the frame header length to zero. */
BPF_STMT(BPF_LD + BPF_IMM, 0),
BPF_STMT(BPF_ST, BPF_M_FHLEN),
};
#define BPF_BOOTP_NONE_LEN __arraycount(bpf_bootp_none)
#endif
static const struct bpf_insn bpf_bootp_ether[] = {
/* Make sure this is an IP packet. */
BPF_STMT(BPF_LD + BPF_H + BPF_ABS,
@ -665,6 +674,12 @@ bpf_bootp(struct interface *ifp, int fd)
bp = bpf;
/* Check frame header. */
switch(ifp->family) {
#ifdef ARPHRD_NONE
case ARPHRD_NONE:
memcpy(bp, bpf_bootp_none, sizeof(bpf_bootp_none));
bp += BPF_BOOTP_NONE_LEN;
break;
#endif
case ARPHRD_ETHER:
memcpy(bp, bpf_bootp_ether, sizeof(bpf_bootp_ether));
bp += BPF_BOOTP_ETHER_LEN;

View File

@ -52,27 +52,6 @@
(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
#endif
static void
control_queue_purge(struct dhcpcd_ctx *ctx, char *data)
{
int found;
struct fd_list *fp;
struct fd_data *fpd;
/* If no other fd queue has the same data, free it */
found = 0;
TAILQ_FOREACH(fp, &ctx->control_fds, next) {
TAILQ_FOREACH(fpd, &fp->queue, next) {
if (fpd->data == data) {
found = 1;
break;
}
}
}
if (!found)
free(data);
}
static void
control_queue_free(struct fd_list *fd)
{
@ -80,14 +59,20 @@ control_queue_free(struct fd_list *fd)
while ((fdp = TAILQ_FIRST(&fd->queue))) {
TAILQ_REMOVE(&fd->queue, fdp, next);
if (fdp->freeit)
control_queue_purge(fd->ctx, fdp->data);
if (fdp->data_size != 0)
free(fdp->data);
free(fdp);
}
fd->queue_len = 0;
#ifdef CTL_FREE_LIST
while ((fdp = TAILQ_FIRST(&fd->free_queue))) {
TAILQ_REMOVE(&fd->free_queue, fdp, next);
if (fdp->data_size != 0)
free(fdp->data);
free(fdp);
}
#endif
}
static void
@ -161,29 +146,33 @@ control_handle1(struct dhcpcd_ctx *ctx, int lfd, unsigned int fd_flags)
len = sizeof(run);
if ((fd = accept(lfd, (struct sockaddr *)&run, &len)) == -1)
return;
goto error;
if ((flags = fcntl(fd, F_GETFD, 0)) == -1 ||
fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
{
close(fd);
return;
}
goto error;
if ((flags = fcntl(fd, F_GETFL, 0)) == -1 ||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
{
close(fd);
return;
}
goto error;
l = malloc(sizeof(*l));
if (l) {
l->ctx = ctx;
l->fd = fd;
l->flags = fd_flags;
TAILQ_INIT(&l->queue);
TAILQ_INIT(&l->free_queue);
TAILQ_INSERT_TAIL(&ctx->control_fds, l, next);
eloop_event_add(ctx->eloop, l->fd, control_handle_data, l);
} else
if (l == NULL)
goto error;
l->ctx = ctx;
l->fd = fd;
l->flags = fd_flags;
TAILQ_INIT(&l->queue);
l->queue_len = 0;
#ifdef CTL_FREE_LIST
TAILQ_INIT(&l->free_queue);
#endif
TAILQ_INSERT_TAIL(&ctx->control_fds, l, next);
eloop_event_add(ctx->eloop, l->fd, control_handle_data, l);
return;
error:
logerr(__func__);
if (fd != -1)
close(fd);
}
@ -374,40 +363,85 @@ control_writeone(void *arg)
}
TAILQ_REMOVE(&fd->queue, data, next);
if (data->freeit)
control_queue_purge(fd->ctx, data->data);
data->data = NULL; /* safety */
data->data_len = 0;
fd->queue_len--;
#ifdef CTL_FREE_LIST
TAILQ_INSERT_TAIL(&fd->free_queue, data, next);
#else
if (data->data_size != 0)
free(data->data);
free(data);
#endif
if (TAILQ_FIRST(&fd->queue) == NULL)
eloop_event_remove_writecb(fd->ctx->eloop, fd->fd);
}
int
control_queue(struct fd_list *fd, char *data, size_t data_len, uint8_t fit)
control_queue(struct fd_list *fd, void *data, size_t data_len, bool fit)
{
struct fd_data *d;
size_t n;
d = TAILQ_FIRST(&fd->free_queue);
if (d) {
TAILQ_REMOVE(&fd->free_queue, d, next);
} else {
n = 0;
TAILQ_FOREACH(d, &fd->queue, next) {
if (++n == CONTROL_QUEUE_MAX) {
errno = ENOBUFS;
return -1;
#ifdef CTL_FREE_LIST
struct fd_data *df;
d = NULL;
TAILQ_FOREACH(df, &fd->free_queue, next) {
if (!fit) {
if (df->data_size == 0) {
d = df;
break;
}
continue;
}
d = malloc(sizeof(*d));
if (d == NULL || d->data_size < df->data_size) {
d = df;
if (d->data_size <= data_len)
break;
}
}
if (d != NULL)
TAILQ_REMOVE(&fd->free_queue, d, next);
else
#endif
{
if (fd->queue_len == CONTROL_QUEUE_MAX) {
errno = ENOBUFS;
return -1;
}
fd->queue_len++;
d = calloc(1, sizeof(*d));
if (d == NULL)
return -1;
}
d->data = data;
if (!fit) {
#ifdef CTL_FREE_LIST
if (d->data_size != 0) {
free(d->data);
d->data_size = 0;
}
#endif
d->data = data;
d->data_len = data_len;
goto queue;
}
if (d->data_size == 0)
d->data = NULL;
if (d->data_size < data_len) {
void *nbuf = realloc(d->data, data_len);
if (nbuf == NULL) {
free(d->data);
free(d);
return -1;
}
d->data = nbuf;
d->data_size = data_len;
}
memcpy(d->data, data, data_len);
d->data_len = data_len;
d->freeit = fit;
queue:
TAILQ_INSERT_TAIL(&fd->queue, d, next);
eloop_event_add_w(fd->ctx->eloop, fd->fd, control_writeone, fd);
return 0;

View File

@ -31,14 +31,20 @@
#include "dhcpcd.h"
#if !defined(CTL_FREE_LIST)
#define CTL_FREE_LIST 1
#elif CTL_FREE_LIST == 0
#undef CTL_FREE_LIST
#endif
/* Limit queue size per fd */
#define CONTROL_QUEUE_MAX 100
struct fd_data {
TAILQ_ENTRY(fd_data) next;
char *data;
void *data;
size_t data_size;
size_t data_len;
uint8_t freeit;
};
TAILQ_HEAD(fd_data_head, fd_data);
@ -48,7 +54,10 @@ struct fd_list {
int fd;
unsigned int flags;
struct fd_data_head queue;
size_t queue_len;
#ifdef CTL_FREE_LIST
struct fd_data_head free_queue;
#endif
};
TAILQ_HEAD(fd_list_head, fd_list);
@ -59,7 +68,7 @@ int control_start(struct dhcpcd_ctx *, const char *);
int control_stop(struct dhcpcd_ctx *);
int control_open(const char *);
ssize_t control_send(struct dhcpcd_ctx *, int, char * const *);
int control_queue(struct fd_list *fd, char *data, size_t data_len, uint8_t fit);
int control_queue(struct fd_list *, void *, size_t, bool);
void control_close(struct dhcpcd_ctx *ctx);
#endif

View File

@ -29,7 +29,7 @@
#define CONFIG_H
#define PACKAGE "dhcpcd"
#define VERSION "8.0.2"
#define VERSION "8.0.3"
#ifndef CONFIG
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf"

View File

@ -622,6 +622,7 @@ print_option(FILE *fp, const char *prefix, const struct dhcp_opt *opt,
int vname,
const uint8_t *data, size_t dl, const char *ifname)
{
fpos_t fp_pos;
const uint8_t *e, *t;
uint16_t u16;
int16_t s16;
@ -636,25 +637,32 @@ print_option(FILE *fp, const char *prefix, const struct dhcp_opt *opt,
if ((ssize_t)dl == -1)
return 0;
if (fprintf(fp, "%s", prefix) == -1)
if (fgetpos(fp, &fp_pos) == -1)
return -1;
if (fprintf(fp, "%s", prefix) == -1)
goto err;
/* We printed something, so always goto err from now-on
* to terminate the string. */
if (vname) {
if (fprintf(fp, "_%s", opt->var) == -1)
return -1;
goto err;
}
if (fputc('=', fp) == EOF)
return -1;
goto err;
if (dl == 0)
return 1;
goto done;
if (opt->type & OT_RFC1035) {
char domain[NS_MAXDNAME];
sl = decode_rfc1035(domain, sizeof(domain), data, dl);
if (sl == 0 || sl == -1)
return sl;
if (sl == -1)
goto err;
if (sl == 0)
goto done;
if (valid_domainname(domain, opt->type) == -1)
return -1;
goto err;
return efprintf(fp, "%s", domain);
}
@ -670,7 +678,7 @@ print_option(FILE *fp, const char *prefix, const struct dhcp_opt *opt,
char buf[1024];
if (print_string(buf, sizeof(buf), opt->type, data, dl) == -1)
return -1;
goto err;
return efprintf(fp, "%s", buf);
}
@ -690,12 +698,10 @@ print_option(FILE *fp, const char *prefix, const struct dhcp_opt *opt,
*data & (1 << sl))
{
if (fputc(opt->bitflags[l], fp) == EOF)
return -1;
goto err;
}
}
if (fputc('\0', fp) == EOF)
return -1;
return 1;
goto done;
}
t = data;
@ -703,66 +709,71 @@ print_option(FILE *fp, const char *prefix, const struct dhcp_opt *opt,
while (data < e) {
if (data != t) {
if (fputc(' ', fp) == EOF)
return -1;
goto err;
}
if (opt->type & OT_UINT8) {
if (fprintf(fp, "%u", *data) == -1)
return -1;
goto err;
data++;
} else if (opt->type & OT_INT8) {
if (fprintf(fp, "%d", *data) == -1)
return -1;
goto err;
data++;
} else if (opt->type & OT_UINT16) {
memcpy(&u16, data, sizeof(u16));
u16 = ntohs(u16);
if (fprintf(fp, "%u", u16) == -1)
return -1;
goto err;
data += sizeof(u16);
} else if (opt->type & OT_INT16) {
memcpy(&u16, data, sizeof(u16));
s16 = (int16_t)ntohs(u16);
if (fprintf(fp, "%d", s16) == -1)
return -1;
goto err;
data += sizeof(u16);
} else if (opt->type & OT_UINT32) {
memcpy(&u32, data, sizeof(u32));
u32 = ntohl(u32);
if (fprintf(fp, "%u", u32) == -1)
return -1;
goto err;
data += sizeof(u32);
} else if (opt->type & OT_INT32) {
memcpy(&u32, data, sizeof(u32));
s32 = (int32_t)ntohl(u32);
if (fprintf(fp, "%d", s32) == -1)
return -1;
goto err;
data += sizeof(u32);
} else if (opt->type & OT_ADDRIPV4) {
memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
if (fprintf(fp, "%s", inet_ntoa(addr)) == -1)
return -1;
goto err;
data += sizeof(addr.s_addr);
} else if (opt->type & OT_ADDRIPV6) {
char buf[INET6_ADDRSTRLEN];
if (inet_ntop(AF_INET6, data, buf, sizeof(buf)) == NULL)
return -1;
goto err;
if (fprintf(fp, "%s", buf) == -1)
return -1;
goto err;
if (data[0] == 0xfe && (data[1] & 0xc0) == 0x80) {
if (fprintf(fp,"%%%s", ifname) == -1)
return -1;
goto err;
}
data += 16;
} else {
errno = EINVAL;
return -1;
goto err;
}
}
done:
if (fputc('\0', fp) == EOF)
return -1;
return 1;
err:
(void)fsetpos(fp, &fp_pos);
return -1;
}
int

View File

@ -1584,24 +1584,24 @@ eexit:
}
static uint16_t
checksum(const void *data, size_t len)
in_cksum(void *data, size_t len, uint32_t *isum)
{
const uint8_t *addr = data;
uint32_t sum = 0;
const uint16_t *word = data;
uint32_t sum = isum != NULL ? *isum : 0;
while (len > 1) {
sum += (uint32_t)(addr[0] * 256 + addr[1]);
addr += 2;
len -= 2;
}
for (; len > 1; len -= sizeof(*word))
sum += *word++;
if (len == 1)
sum += (uint32_t)(*addr * 256);
sum += *(const uint8_t *)word;
if (isum != NULL)
*isum = sum;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return (uint16_t)~htons((uint16_t)sum);
return (uint16_t)~sum;
}
static struct bootp_pkt *
@ -1639,14 +1639,16 @@ dhcp_makeudppacket(size_t *sz, const uint8_t *data, size_t length,
udp->uh_dport = htons(BOOTPS);
udp->uh_ulen = htons((uint16_t)(sizeof(*udp) + length));
ip->ip_len = udp->uh_ulen;
udp->uh_sum = checksum(udpp, sizeof(*ip) + sizeof(*udp) + length);
udp->uh_sum = in_cksum(udpp, sizeof(*ip) + sizeof(*udp) + length, NULL);
ip->ip_v = IPVERSION;
ip->ip_hl = sizeof(*ip) >> 2;
ip->ip_id = (uint16_t)arc4random_uniform(UINT16_MAX);
ip->ip_ttl = IPDEFTTL;
ip->ip_len = htons((uint16_t)(sizeof(*ip) + sizeof(*udp) + length));
ip->ip_sum = checksum(ip, sizeof(*ip));
ip->ip_sum = in_cksum(ip, sizeof(*ip), NULL);
if (ip->ip_sum == 0)
ip->ip_sum = 0xffff; /* RFC 768 */
*sz = sizeof(*ip) + sizeof(*udp) + length;
return udpp;
@ -2363,7 +2365,10 @@ dhcp_arp_address(struct interface *ifp)
return 0;
}
#else
if (ifp->options->options & DHCPCD_ARP && ia == NULL) {
if (!(ifp->flags & IFF_NOARP) &&
ifp->options->options & DHCPCD_ARP &&
ia == NULL)
{
struct arp_state *astate;
struct dhcp_lease l;
@ -3236,10 +3241,15 @@ valid_udp_packet(void *packet, size_t plen, struct in_addr *from,
unsigned int flags)
{
struct ip *ip = packet;
char ip_hlv = *(char *)ip;
struct ip pseudo_ip = {
.ip_p = IPPROTO_UDP,
.ip_src = ip->ip_src,
.ip_dst = ip->ip_dst
};
size_t ip_hlen;
uint16_t ip_len, uh_sum;
struct udphdr *udp;
uint32_t csum;
if (plen < sizeof(*ip)) {
if (from != NULL)
@ -3252,13 +3262,13 @@ valid_udp_packet(void *packet, size_t plen, struct in_addr *from,
from->s_addr = ip->ip_src.s_addr;
ip_hlen = (size_t)ip->ip_hl * 4;
if (checksum(ip, ip_hlen) != 0) {
if (in_cksum(ip, ip_hlen, NULL) != 0) {
errno = EINVAL;
return -1;
}
ip_len = ntohs(ip->ip_len);
/* Check we have a payload */
ip_len = ntohs(ip->ip_len);
if (ip_len <= ip_hlen + sizeof(*udp)) {
errno = ERANGE;
return -1;
@ -3272,28 +3282,21 @@ valid_udp_packet(void *packet, size_t plen, struct in_addr *from,
if (flags & BPF_PARTIALCSUM)
return 0;
udp = (struct udphdr *)((char *)ip + ip_hlen);
/* UDP checksum is based on a pseudo IP header alongside
* the UDP header and payload. */
udp = (struct udphdr *)(void *)((char *)ip + ip_hlen);
if (udp->uh_sum == 0)
return 0;
uh_sum = udp->uh_sum;
/* This does scribble on the packet, but at this point
* we don't care to keep it. */
uh_sum = udp->uh_sum;
udp->uh_sum = 0;
ip->ip_hl = 0;
ip->ip_v = 0;
ip->ip_tos = 0;
ip->ip_len = udp->uh_ulen;
ip->ip_id = 0;
ip->ip_off = 0;
ip->ip_ttl = 0;
ip->ip_sum = 0;
if (checksum(packet, ip_len) != uh_sum) {
pseudo_ip.ip_len = udp->uh_ulen;
csum = 0;
in_cksum(&pseudo_ip, sizeof(pseudo_ip), &csum);
if (in_cksum(udp, ntohs(udp->uh_ulen), &csum) != uh_sum) {
errno = EINVAL;
return -1;
}
*(char *)ip = ip_hlv;
ip->ip_len = htons(ip_len);
return 0;
}
@ -3339,12 +3342,6 @@ dhcp_handlepacket(struct interface *ifp, uint8_t *data, size_t len)
ifp->name, inet_ntoa(from));
return;
}
if (ifp->flags & IFF_POINTOPOINT &&
(state->addr == NULL || state->addr->brd.s_addr != from.s_addr))
{
logwarnx("%s: server %s is not destination",
ifp->name, inet_ntoa(from));
}
/*
* DHCP has a variable option area rather than a fixed vendor area.
@ -3721,12 +3718,6 @@ dhcp_start1(void *arg)
return;
}
if (ifp->hwlen == 0 && ifo->clientid[0] == '\0') {
logwarnx("%s: needs a clientid to configure", ifp->name);
dhcp_drop(ifp, "FAIL");
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
return;
}
/* We don't want to read the old lease if we NAK an old test */
nolease = state->offer && ifp->ctx->options & DHCPCD_TEST;
if (!nolease && ifo->options & DHCPCD_DHCP) {

View File

@ -458,11 +458,10 @@ configure_interface1(struct interface *ifp)
ifo->options &= ~DHCPCD_ARP;
if (!(ifp->flags & IFF_MULTICAST))
ifo->options &= ~DHCPCD_IPV6RS;
if (!(ifo->options & DHCPCD_INFORM))
if (!(ifo->options & (DHCPCD_INFORM | DHCPCD_WANTDHCP)))
ifo->options |= DHCPCD_STATIC;
}
if (ifp->flags & IFF_NOARP ||
!(ifo->options & DHCPCD_ARP) ||
if (!(ifo->options & DHCPCD_ARP) ||
ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))
ifo->options &= ~DHCPCD_IPV4LL;
@ -1440,10 +1439,10 @@ dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd,
* write callback on the fd */
if (strcmp(*argv, "--version") == 0) {
return control_queue(fd, UNCONST(VERSION),
strlen(VERSION) + 1, 0);
strlen(VERSION) + 1, false);
} else if (strcmp(*argv, "--getconfigfile") == 0) {
return control_queue(fd, UNCONST(fd->ctx->cffile),
strlen(fd->ctx->cffile) + 1, 0);
strlen(fd->ctx->cffile) + 1, false);
} else if (strcmp(*argv, "--getinterfaces") == 0) {
eloop_event_add_w(fd->ctx->eloop, fd->fd,
dhcpcd_getinterfaces, fd);

View File

@ -52,10 +52,6 @@
#include <time.h>
#include <unistd.h>
#ifndef ARPHRD_NETROM
# define ARPHRD_NETROM 0
#endif
#include "common.h"
#include "dhcpcd.h"
#include "duid.h"
@ -189,10 +185,10 @@ duid_get(uint8_t **d, const struct interface *ifp)
return len;
/* No UUID? OK, lets make one based on our interface */
if (ifp->family == ARPHRD_NETROM) {
logwarnx("%s: is a NET/ROM pseudo interface", ifp->name);
if (ifp->hwlen == 0) {
logwarnx("%s: does not have hardware address", ifp->name);
TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
if (ifp2->family != ARPHRD_NETROM)
if (ifp2->hwlen != 0)
break;
}
if (ifp2) {

View File

@ -191,6 +191,8 @@ if_opensockets_os(struct dhcpcd_ctx *ctx)
if (setsockopt(ctx->link_fd, PF_ROUTE, ROUTE_MSGFILTER,
&msgfilter_mask, sizeof(msgfilter_mask)) == -1)
logerr(__func__);
#else
#warning kernel does not support route message filtering
#endif
return 0;
@ -660,11 +662,8 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, const struct rt_msghdr *rtm)
}
#endif
/* We have already checked that at least one address must be
* present after the rtm structure. */
/* coverity[ptr_arith] */
if (get_addrs(rtm->rtm_addrs, rtm + 1,
rtm->rtm_msglen - sizeof(*rtm), rti_info) == -1)
if (get_addrs(rtm->rtm_addrs, (const char *)rtm + sizeof(*rtm),
rtm->rtm_msglen - sizeof(*rtm), rti_info) == -1)
return -1;
memset(rt, 0, sizeof(*rt));
@ -1115,10 +1114,7 @@ if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam)
if ((ifp = if_findindex(ctx->ifaces, ifam->ifam_index)) == NULL)
return 0;
/* We have already checked that at least one address must be
* present after the ifam structure. */
/* coverity[ptr_arith] */
if (get_addrs(ifam->ifam_addrs, ifam + 1,
if (get_addrs(ifam->ifam_addrs, (const char *)ifam + sizeof(*ifam),
ifam->ifam_msglen - sizeof(*ifam), rti_info) == -1)
return -1;
@ -1314,32 +1310,41 @@ if_dispatch(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm)
#ifdef RTM_DESYNC
case RTM_DESYNC:
dhcpcd_linkoverflow(ctx);
#elif !defined(SO_RERROR)
#warning cannot detect route socket overflow within kernel
#endif
}
return 0;
}
__CTASSERT(offsetof(struct rt_msghdr, rtm_msglen) == 0);
int
if_handlelink(struct dhcpcd_ctx *ctx)
{
struct rtm rtm;
struct iovec iov = { .iov_base = &rtm, .iov_len = sizeof(rtm) };
struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 };
ssize_t len;
len = recvmsg(ctx->link_fd, &msg, 0);
len = read(ctx->link_fd, &rtm, sizeof(rtm));
if (len == -1)
return -1;
if (len == 0)
return 0;
if (len < rtm.hdr.rtm_msglen) {
if ((size_t)len < sizeof(rtm.hdr.rtm_msglen) ||
len != rtm.hdr.rtm_msglen)
{
errno = EINVAL;
return -1;
}
/* We generally treat rtm.hdr has an array so we can easily
* access the following data. */
/* coverity[callee_ptr_arith] */
/*
* Coverity thinks that the data could be tainted from here.
* I have no idea how because the length of the data we read
* is guarded by len and checked to match rtm_msglen.
* The issue seems to be related to extracting the addresses
* at the end of the header, but seems to have no issues with the
* equivalent call in if_initrt.
*/
/* coverity[tainted_data] */
return if_dispatch(ctx, &rtm.hdr);
}

View File

@ -2062,7 +2062,7 @@ err_sla:
ifo->auth.options &= ~DHCPCD_AUTH_REQUIRE;
break;
case O_DHCP:
ifo->options |= DHCPCD_DHCP | DHCPCD_IPV4;
ifo->options |= DHCPCD_DHCP | DHCPCD_WANTDHCP | DHCPCD_IPV4;
break;
case O_NODHCP:
ifo->options &= ~DHCPCD_DHCP;
@ -2281,7 +2281,7 @@ default_config(struct dhcpcd_ctx *ctx)
ifo->script = UNCONST(default_script);
ifo->metric = -1;
ifo->auth.options |= DHCPCD_AUTH_REQUIRE;
rb_tree_init(&ifo->routes, &rt_compare_proto_ops);
rb_tree_init(&ifo->routes, &rt_compare_list_ops);
#ifdef AUTH
TAILQ_INIT(&ifo->auth.tokens);
#endif

View File

@ -110,7 +110,7 @@
#define DHCPCD_DHCP6 (1ULL << 50)
#define DHCPCD_IF_UP (1ULL << 51)
#define DHCPCD_INFORM6 (1ULL << 52)
// unused (1ULL << 53)
#define DHCPCD_WANTDHCP (1ULL << 53)
#define DHCPCD_IPV6RA_AUTOCONF (1ULL << 54)
#define DHCPCD_ROUTER_HOST_ROUTE_WARNED (1ULL << 55)
#define DHCPCD_LASTLEASE_EXTEND (1ULL << 56)

View File

@ -307,17 +307,16 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
struct if_spec spec;
#ifdef AF_LINK
const struct sockaddr_dl *sdl;
#ifdef SIOCGIFPRIORITY
struct ifreq ifr;
#endif
#ifdef IFLR_ACTIVE
struct if_laddrreq iflr = { .flags = IFLR_PREFIX };
int link_fd;
#endif
#elif AF_PACKET
const struct sockaddr_ll *sll;
#endif
#if defined(SIOCGIFPRIORITY) || defined(SIOCGIFHWADDR)
struct ifreq ifr;
#endif
if ((ifs = malloc(sizeof(*ifs))) == NULL) {
logerr(__func__);
@ -512,10 +511,21 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen);
#endif
}
#ifdef __linux__
/* PPP addresses on Linux don't have hardware addresses */
else
ifp->index = if_nametoindex(ifp->name);
#ifdef SIOCGIFHWADDR
else {
/* This is a huge bug in getifaddrs(3) as there
* is no reason why this can't be returned in
* ifa_addr. */
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifa->ifa_name,
sizeof(ifr.ifr_name));
if (ioctl(ctx->pf_inet_fd, SIOCGIFHWADDR, &ifr) == -1)
logerr("%s: SIOCGIFHWADDR", ifa->ifa_name);
ifp->family = ifr.ifr_hwaddr.sa_family;
if (ioctl(ctx->pf_inet_fd, SIOCGIFINDEX, &ifr) == -1)
logerr("%s: SIOCGIFINDEX", ifa->ifa_name);
ifp->index = (unsigned int)ifr.ifr_ifindex;
}
#endif
/* Ensure hardware address is valid. */
@ -535,6 +545,9 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
#endif
#ifdef ARPHRD_PPP
case ARPHRD_PPP:
#endif
#ifdef ARPHRD_NONE
case ARPHRD_NONE:
#endif
/* We don't warn for supported families */
break;

View File

@ -268,13 +268,12 @@ inet_dhcproutes(rb_tree_t *routes, struct interface *ifp, bool *have_default)
rb_tree_init(&nroutes, &rt_compare_proto_ops);
/* First, add a subnet route. */
if (!(ifp->flags & IFF_POINTOPOINT) &&
if (state->addr->mask.s_addr != INADDR_ANY
#ifndef BSD
/* BSD adds a route in this instance */
state->addr->mask.s_addr != INADDR_BROADCAST &&
&& state->addr->mask.s_addr != INADDR_BROADCAST
#endif
state->addr->mask.s_addr != INADDR_ANY)
{
) {
if ((rt = rt_new(ifp)) == NULL)
return -1;
rt->rt_dflags |= RTDF_IFA_ROUTE;
@ -680,8 +679,10 @@ ipv4_addaddr(struct interface *ifp, const struct in_addr *addr,
logdebugx("%s: aliased %s", ia->alias, ia->saddr);
#endif
logdebugx("%s: adding IP address %s broadcast %s",
ifp->name, ia->saddr, inet_ntoa(*bcast));
logdebugx("%s: adding IP address %s %s %s",
ifp->name, ia->saddr,
ifp->flags & IFF_POINTOPOINT ? "destination" : "broadcast",
inet_ntoa(*bcast));
if (if_address(RTM_NEWADDR, ia) == -1) {
if (errno != EEXIST)
logerr("%s: if_addaddress",
@ -742,7 +743,8 @@ ipv4_applyaddr(void *arg)
#ifdef ARP
/* Announce the preferred address to
* kick ARP caches. */
arp_announceaddr(ifp->ctx, &lease->addr);
if (!(ifp->flags & IFF_NOARP))
arp_announceaddr(ifp->ctx,&lease->addr);
#endif
}
script_runreason(ifp, state->reason);
@ -804,7 +806,8 @@ ipv4_applyaddr(void *arg)
rt_build(ifp->ctx, AF_INET);
#ifdef ARP
arp_announceaddr(ifp->ctx, &state->addr->addr);
if (!(ifp->flags & IFF_NOARP))
arp_announceaddr(ifp->ctx, &state->addr->addr);
#endif
if (state->state == DHS_BOUND) {

View File

@ -100,7 +100,8 @@
#endif
/* This was fixed in NetBSD */
#if defined(__NetBSD_Version__) && __NetBSD_Version__ >= 699002000
#if (defined(__DragonFly_version) && __DragonFly_version >= 500704) || \
(defined(__NetBSD_Version__) && __NetBSD_Version__ >= 699002000)
# undef IPV6_POLLADDRFLAG
#endif
@ -153,9 +154,12 @@
* ND6 Advertising is only used for IP address sharing to prefer
* the address on a specific interface.
* This just fails to work on OpenBSD and causes erroneous duplicate
* address messages on BSD's other then NetBSD.
* address messages on BSD's other then DragonFly and NetBSD.
*/
#if !defined(SMALL) && (defined(__NetBSD__) || defined(__linux__))
#if !defined(SMALL) && \
((defined(__DragonFly_version) && __DragonFly_version >= 500703) || \
(defined(__NetBSD_Version__) && __NetBSD_Version__ >= 899002800) || \
defined(__linux__))
# define ND6_ADVERTISE
#endif

View File

@ -139,7 +139,19 @@ rt_compare_os(__unused void *context, const void *node1, const void *node2)
}
static int
rt_compare_proto(__unused void *context, const void *node1, const void *node2)
rt_compare_list(__unused void *context, const void *node1, const void *node2)
{
const struct rt *rt1 = node1, *rt2 = node2;
if (rt1->rt_order > rt2->rt_order)
return 1;
if (rt1->rt_order < rt2->rt_order)
return -1;
return 0;
}
static int
rt_compare_proto(void *context, const void *node1, const void *node2)
{
const struct rt *rt1 = node1, *rt2 = node2;
int c;
@ -161,11 +173,7 @@ rt_compare_proto(__unused void *context, const void *node1, const void *node2)
return c;
/* Finally the order in which the route was given to us. */
if (rt1->rt_order > rt2->rt_order)
return 1;
if (rt1->rt_order < rt2->rt_order)
return -1;
return 0;
return rt_compare_list(context, rt1, rt2);
}
static const rb_tree_ops_t rt_compare_os_ops = {
@ -175,6 +183,13 @@ static const rb_tree_ops_t rt_compare_os_ops = {
.rbto_context = NULL
};
const rb_tree_ops_t rt_compare_list_ops = {
.rbto_compare_nodes = rt_compare_list,
.rbto_compare_key = rt_compare_list,
.rbto_node_offset = offsetof(struct rt, rt_tree),
.rbto_context = NULL
};
const rb_tree_ops_t rt_compare_proto_ops = {
.rbto_compare_nodes = rt_compare_proto,
.rbto_compare_key = rt_compare_proto,

View File

@ -96,6 +96,7 @@ struct rt {
rb_node_t rt_tree;
};
extern const rb_tree_ops_t rt_compare_list_ops;
extern const rb_tree_ops_t rt_compare_proto_ops;
void rt_init(struct dhcpcd_ctx *);

View File

@ -288,11 +288,9 @@ sa_toprefix(const struct sockaddr *sa)
#ifndef NDEBUG
/* Ensure the calculation is correct */
if (!sa_inprefix) {
union sa_ss ss;
union sa_ss ss = { .sa.sa_family = sa->sa_family };
sa_inprefix = true;
memset(&ss, 0, sizeof(ss));
ss.sa.sa_family = sa->sa_family;
sa_fromprefix(&ss.sa, prefix);
assert(sa_cmp(sa, &ss.sa) == 0);
sa_inprefix = false;

View File

@ -33,6 +33,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>
@ -172,12 +173,12 @@ efprintf(FILE *fp, const char *fmt, ...)
return r;
}
static ssize_t
static long
make_env(const struct interface *ifp, const char *reason)
{
struct dhcpcd_ctx *ctx = ifp->ctx;
FILE *fp;
char **env, **envp, *buf, *bufp, *endp, *path;
char **env, **envp, *bufp, *endp, *path;
size_t nenv;
long buf_pos, i;
int protocol = PROTO_LINK;
@ -458,31 +459,38 @@ dumplease:
logerr(__func__);
goto eexit;
}
#ifdef HAVE_OPEN_MEMSTREAM
buf = ctx->script_buf;
#else
#ifndef HAVE_OPEN_MEMSTREAM
size_t buf_len = (size_t)buf_pos;
if (ctx->script_buflen < buf_len) {
buf = realloc(ctx->script_buf, buf_len);
char *buf = realloc(ctx->script_buf, buf_len);
if (buf == NULL)
goto eexit;
ctx->script_buf = buf;
ctx->script_buflen = buf_len;
}
buf = ctx->script_buf;
rewind(fp);
if (fread(buf, sizeof(char), buf_len, fp) != buf_len)
if (fread(ctx->script_buf, sizeof(char), buf_len, fp) != buf_len)
goto eexit;
fclose(fp);
fp = NULL;
#endif
/* Count the terminated env strings.
* Assert that the terminations are correct. */
nenv = 0;
endp = buf + buf_pos;
for (bufp = buf; bufp < endp; bufp++) {
if (*bufp == '\0')
endp = ctx->script_buf + buf_pos;
for (bufp = ctx->script_buf; bufp < endp; bufp++) {
if (*bufp == '\0') {
#ifndef NDEBUG
if (bufp + 1 < endp)
assert(*(bufp + 1) != '\0');
#endif
nenv++;
}
}
assert(*(bufp - 1) == '\0');
if (ctx->script_envlen < nenv) {
env = reallocarray(ctx->script_env, nenv + 1, sizeof(*env));
if (env == NULL)
@ -490,7 +498,8 @@ dumplease:
ctx->script_env = env;
ctx->script_envlen = nenv;
}
bufp = buf;
bufp = ctx->script_buf;
envp = ctx->script_env;
*envp++ = bufp++;
endp--; /* Avoid setting the last \0 to an invalid pointer */
@ -500,7 +509,7 @@ dumplease:
}
*envp = NULL;
return (ssize_t)nenv;
return buf_pos - 1;
eexit:
logerr(__func__);
@ -516,10 +525,12 @@ send_interface1(struct fd_list *fd, const struct interface *ifp,
const char *reason)
{
struct dhcpcd_ctx *ctx = ifp->ctx;
long len;
if (make_env(ifp, reason) == -1)
len = make_env(ifp, reason);
if (len == -1)
return -1;
return control_queue(fd, ctx->script_buf, ctx->script_buflen, 1);
return control_queue(fd, ctx->script_buf, (size_t)len, 1);
}
int
@ -636,8 +647,8 @@ send_listeners:
TAILQ_FOREACH(fd, &ctx->control_fds, next) {
if (!(fd->flags & FD_LISTEN))
continue;
if (control_queue(fd, ctx->script_buf, ctx->script_buflen, 1)
== -1)
if (control_queue(fd, ctx->script_buf, ctx->script_buflen,
true) == -1)
logerr("%s: control_queue", __func__);
else
status = 1;