This commit is contained in:
roy 2019-04-26 14:34:10 +00:00
parent cdfaff8fa4
commit 5520e60803
4 changed files with 154 additions and 55 deletions

View File

@ -215,6 +215,12 @@ get_option(struct dhcpcd_ctx *ctx,
}
l = *p++;
/* Check we can read the option data, if present */
if (p + l > e) {
errno = EINVAL;
return NULL;
}
if (o == DHO_OPTSOVERLOADED) {
/* Ensure we only get this option once by setting
* the last bit as well as the value.
@ -249,10 +255,6 @@ get_option(struct dhcpcd_ctx *ctx,
bp += ol;
}
ol = l;
if (p + ol >= e) {
errno = EINVAL;
return NULL;
}
op = p;
bl += ol;
}
@ -2075,7 +2077,7 @@ dhcp_arp_probed(struct arp_state *astate)
ifp->name, inet_ntoa(astate->addr));
if (!(ifo->options & DHCPCD_INFORM))
dhcp_bind(ifp);
#ifndef IN_IFF_TENTATIVE
#ifndef IN_IFF_DUPLICATED
else {
struct bootp *bootp;
size_t len;
@ -2429,7 +2431,7 @@ dhcp_arp_address(struct interface *ifp)
if (astate == NULL)
return -1;
#ifdef IN_IFF_TENTATIVE
#ifdef IN_IFF_NOTUSEABLE
if (ia == NULL || ia->addr_flags & IN_IFF_NOTUSEABLE) {
state->state = DHS_PROBE;
if (ia == NULL) {

View File

@ -2029,12 +2029,12 @@ dhcp6_findna(struct interface *ifp, uint16_t ot, const uint8_t *iaid,
nd = o + ol;
l -= (size_t)(nd - d);
d = nd;
if (ol < 24) {
if (ol < sizeof(ia)) {
errno = EINVAL;
logerrx("%s: IA Address option truncated", ifp->name);
continue;
}
memcpy(&ia, o, ol);
memcpy(&ia, o, sizeof(ia));
ia.pltime = ntohl(ia.pltime);
ia.vltime = ntohl(ia.vltime);
/* RFC 3315 22.6 */
@ -3035,7 +3035,7 @@ dhcp6_bind(struct interface *ifp, const char *op, const char *sfrom)
* unless those values in those fields are 0.
*/
logwarnx("%s: ignoring T1 %"PRIu32
" to due address expiry",
" due to address expiry",
ifp->name, state->renew);
state->renew = state->rebind = 0;
}

View File

@ -943,10 +943,15 @@ if_getlifetime6(struct ipv6_addr *ia)
priv = (struct priv *)ia->iface->ctx->priv;
if (ioctl(priv->pf_inet6_fd, SIOCGIFALIFETIME_IN6, &ifr6) == -1)
return -1;
clock_gettime(CLOCK_MONOTONIC, &ia->created);
#if defined(__FreeBSD__) || defined(__DragonFly__)
t = ia->created.tv_sec;
#else
t = time(NULL);
lifetime = &ifr6.ifr_ifru.ifru_lifetime;
#endif
lifetime = &ifr6.ifr_ifru.ifru_lifetime;
if (lifetime->ia6t_preferred)
ia->prefix_pltime = (uint32_t)(lifetime->ia6t_preferred -
MIN(t, lifetime->ia6t_preferred));
@ -956,7 +961,6 @@ if_getlifetime6(struct ipv6_addr *ia)
ia->prefix_vltime = (uint32_t)(lifetime->ia6t_expire -
MIN(t, lifetime->ia6t_expire));
/* Calculate the created time */
clock_gettime(CLOCK_MONOTONIC, &ia->created);
ia->created.tv_sec -= lifetime->ia6t_vltime - ia->prefix_vltime;
} else
ia->prefix_vltime = ND6_INFINITE_LIFETIME;

View File

@ -190,54 +190,106 @@ ipv6nd_printoptions(const struct dhcpcd_ctx *ctx,
}
static int
ipv6nd_open(struct dhcpcd_ctx *ctx)
ipv6nd_open0(void)
{
int on;
int s, on;
struct icmp6_filter filt;
if (ctx->nd_fd != -1)
return ctx->nd_fd;
#define SOCK_FLAGS SOCK_CLOEXEC | SOCK_NONBLOCK
ctx->nd_fd = xsocket(PF_INET6, SOCK_RAW | SOCK_FLAGS, IPPROTO_ICMPV6);
s = xsocket(PF_INET6, SOCK_RAW | SOCK_FLAGS, IPPROTO_ICMPV6);
#undef SOCK_FLAGS
if (ctx->nd_fd == -1)
if (s == -1)
return -1;
/* RFC4861 4.1 */
on = 255;
if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
&on, sizeof(on)) == -1)
goto eexit;
on = 1;
if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
&on, sizeof(on)) == -1)
goto eexit;
on = 1;
if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
&on, sizeof(on)) == -1)
goto eexit;
ICMP6_FILTER_SETBLOCKALL(&filt);
ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt);
ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
if (setsockopt(ctx->nd_fd, IPPROTO_ICMPV6, ICMP6_FILTER,
if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
&filt, sizeof(filt)) == -1)
goto eexit;
eloop_event_add(ctx->eloop, ctx->nd_fd, ipv6nd_handledata, ctx);
return ctx->nd_fd;
return s;
eexit:
if (ctx->nd_fd != -1) {
eloop_event_delete(ctx->eloop, ctx->nd_fd);
close(ctx->nd_fd);
ctx->nd_fd = -1;
}
close(s);
return -1;
}
#ifdef __sun
static int
ipv6nd_open(struct interface *ifp)
{
int s;
struct ipv6_mreq mreq = {
.ipv6mr_multiaddr = IN6ADDR_LINKLOCAL_ALLNODES_INIT,
.ipv6mr_interface = ifp->index
};
struct rs_state *state = RS_STATE(ifp);
uint_t ifindex = ifp->index;
if (state->nd_fd != -1)
return state->nd_fd;
s = ipv6nd_open0();
if (s == -1)
return -1;
if (setsockopt(s, IPPROTO_IPV6, IPV6_BOUND_IF,
&ifindex, sizeof(ifindex)) == -1)
{
close(s);
return -1;
}
if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP,
&mreq, sizeof(mreq)) == -1)
{
close(s);
return -1;
}
state->nd_fd = s;
eloop_event_add(ifp->ctx->eloop, s, ipv6nd_handledata, ifp);
return s;
}
#else
static int
ipv6nd_open(struct dhcpcd_ctx *ctx)
{
int s, on;
if (ctx->nd_fd != -1)
return ctx->nd_fd;
s = ipv6nd_open0();
if (s == -1)
return -1;
on = 1;
if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO,
&on, sizeof(on)) == -1)
{
close(s);
return -1;
}
ctx->nd_fd = s;
eloop_event_add(ctx->eloop, s, ipv6nd_handledata, ctx);
return s;
}
#endif
static int
ipv6nd_makersprobe(struct interface *ifp)
{
@ -273,9 +325,12 @@ static void
ipv6nd_sendrsprobe(void *arg)
{
struct interface *ifp = arg;
struct dhcpcd_ctx *ctx;
struct rs_state *state = RS_STATE(ifp);
struct sockaddr_in6 dst = { .sin6_family = AF_INET6 };
struct sockaddr_in6 dst = {
.sin6_family = AF_INET6,
.sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT,
.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 };
struct msghdr msg = {
@ -285,6 +340,7 @@ ipv6nd_sendrsprobe(void *arg)
};
struct cmsghdr *cm;
struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
int s;
if (ipv6_linklocal(ifp) == NULL) {
logdebugx("%s: delaying Router Solicitation for LL address",
@ -296,13 +352,6 @@ ipv6nd_sendrsprobe(void *arg)
#ifdef HAVE_SA_LEN
dst.sin6_len = sizeof(dst);
#endif
dst.sin6_scope_id = ifp->index;
if (inet_pton(AF_INET6, ALLROUTERS, &dst.sin6_addr) != 1) {
logerr(__func__);
return;
}
ctx = ifp->ctx;
/* Set the outbound interface */
cm = CMSG_FIRSTHDR(&msg);
@ -314,7 +363,12 @@ ipv6nd_sendrsprobe(void *arg)
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
logdebugx("%s: sending Router Solicitation", ifp->name);
if (sendmsg(ctx->nd_fd, &msg, 0) == -1) {
#ifdef __sun
s = state->nd_fd;
#else
s = ifp->ctx->nd_fd;
#endif
if (sendmsg(s, &msg, 0) == -1) {
logerr(__func__);
/* Allow IPv6ND to continue .... at most a few errors
* would be logged.
@ -342,6 +396,7 @@ ipv6nd_sendadvertisement(void *arg)
struct dhcpcd_ctx *ctx = ifp->ctx;
struct sockaddr_in6 dst = {
.sin6_family = AF_INET6,
.sin6_addr = IN6ADDR_LINKLOCAL_ALLNODES_INIT,
.sin6_scope_id = ifp->index,
};
struct iovec iov = { .iov_base = ia->na, .iov_len = ia->na_len };
@ -354,6 +409,7 @@ ipv6nd_sendadvertisement(void *arg)
struct cmsghdr *cm;
struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
const struct rs_state *state = RS_CSTATE(ifp);
int s;
if (state == NULL || ifp->carrier <= LINK_DOWN)
goto freeit;
@ -361,10 +417,6 @@ ipv6nd_sendadvertisement(void *arg)
#ifdef SIN6_LEN
dst.sin6_len = sizeof(dst);
#endif
if (inet_pton(AF_INET6, ALLNODES, &dst.sin6_addr) != 1) {
logerr(__func__);
return;
}
/* Set the outbound interface. */
cm = CMSG_FIRSTHDR(&msg);
@ -373,10 +425,20 @@ ipv6nd_sendadvertisement(void *arg)
cm->cmsg_type = IPV6_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(pi));
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
logdebugx("%s: sending NA for %s", ifp->name, ia->saddr);
if (sendmsg(ctx->nd_fd, &msg, 0) == -1)
#ifdef __sun
s = state->nd_fd;
#else
s = ctx->nd_fd;
#endif
if (sendmsg(s, &msg, 0) == -1)
#ifdef __OpenBSD__
/* This isn't too critical as they don't support IPv6 address sharing */
#warning Cannot send NA messages on OpenBSD
logdebug(__func__);
#else
logerr(__func__);
#endif
if (++ia->na_count < MAX_NEIGHBOR_ADVERTISEMENT) {
eloop_timeout_add_sec(ctx->eloop,
@ -619,6 +681,11 @@ ipv6nd_free(struct interface *ifp)
if (state == NULL)
return 0;
ctx = ifp->ctx;
#ifdef __sun
eloop_event_delete(ctx->eloop, state->nd_fd);
close(state->nd_fd);
#endif
free(state->rs);
free(state);
ifp->if_data[IF_DATA_IPV6ND] = NULL;
@ -630,9 +697,9 @@ ipv6nd_free(struct interface *ifp)
}
}
#ifndef __sun
/* If we don't have any more IPv6 enabled interfaces,
* close the global socket and release resources */
ctx = ifp->ctx;
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
if (RS_STATE(ifp))
break;
@ -644,6 +711,7 @@ ipv6nd_free(struct interface *ifp)
ctx->nd_fd = -1;
}
}
#endif
return n;
}
@ -1659,6 +1727,7 @@ static void
ipv6nd_handledata(void *arg)
{
struct dhcpcd_ctx *ctx;
int s;
struct sockaddr_in6 from;
unsigned char buf[64 * 1024]; /* Maximum ICMPv6 size */
struct iovec iov = {
@ -1677,8 +1746,18 @@ ipv6nd_handledata(void *arg)
struct icmp6_hdr *icp;
struct interface *ifp;
#ifdef __sun
struct rs_state *state;
ifp = arg;
state = RS_STATE(ifp);
ctx = ifp->ctx;
s = state->nd_fd;
#else
ctx = arg;
len = recvmsg(ctx->nd_fd, &msg, 0);
s = ctx->nd_fd;
#endif
len = recvmsg(s, &msg, 0);
if (len == -1) {
logerr(__func__);
return;
@ -1689,11 +1768,15 @@ ipv6nd_handledata(void *arg)
return;
}
#ifdef __sun
if_findifpfromcmsg(ctx, &msg, &hoplimit);
#else
ifp = if_findifpfromcmsg(ctx, &msg, &hoplimit);
if (ifp == NULL) {
logerr(__func__);
return;
}
#endif
/* Don't do anything if the user hasn't configured it. */
if (ifp->active != IF_ACTIVE_USER ||
@ -1725,11 +1808,6 @@ ipv6nd_startrs1(void *arg)
struct rs_state *state;
loginfox("%s: soliciting an IPv6 router", ifp->name);
if (ipv6nd_open(ifp->ctx) == -1) {
logerr(__func__);
return;
}
state = RS_STATE(ifp);
if (state == NULL) {
ifp->if_data[IF_DATA_IPV6ND] = calloc(1, sizeof(*state));
@ -1738,8 +1816,23 @@ ipv6nd_startrs1(void *arg)
logerr(__func__);
return;
}
#ifdef __sun
state->nd_fd = -1;
#endif
}
#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);