summaryrefslogtreecommitdiffstats
path: root/src/ipv6nd.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2019-02-17 09:36:11 +0000
committerRoy Marples <roy@marples.name>2019-02-17 09:36:11 +0000
commit590fc45d1c373b99d4fae7f8397d63194806b33a (patch)
tree0889093e4169a97c9018befe96c3e802879190f8 /src/ipv6nd.c
parent30433665d5cdd7bc4bf34bd7d1b8bb933e33c427 (diff)
downloaddhcpcd-590fc45d1c373b99d4fae7f8397d63194806b33a.tar.xz
Remove the send/recv structures from dhcpcd context and allocate
on stack as and when required. Rather than peaking and checking for truncation for receiving, just allocate a large enough buffer upfront.
Diffstat (limited to 'src/ipv6nd.c')
-rw-r--r--src/ipv6nd.c154
1 files changed, 79 insertions, 75 deletions
diff --git a/src/ipv6nd.c b/src/ipv6nd.c
index 5a248486..7f67287c 100644
--- a/src/ipv6nd.c
+++ b/src/ipv6nd.c
@@ -274,10 +274,17 @@ ipv6nd_sendrsprobe(void *arg)
{
struct interface *ifp = arg;
struct dhcpcd_ctx *ctx;
- struct rs_state *state;
- struct sockaddr_in6 dst;
+ struct rs_state *state = RS_STATE(ifp);
+ struct sockaddr_in6 dst = { .sin6_family = AF_INET6 };
+ struct iovec iov = { .iov_base = state->rs, .iov_len = state->rslen };
+ unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
+ struct msghdr msg = {
+ .msg_name = &dst, .msg_namelen = sizeof(dst),
+ .msg_iov = &iov, .msg_iovlen = 1,
+ .msg_control = ctl, .msg_controllen = sizeof(ctl),
+ };
struct cmsghdr *cm;
- struct in6_pktinfo pi;
+ struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
if (ipv6_linklocal(ifp) == NULL) {
logdebugx("%s: delaying Router Solicitation for LL address",
@@ -286,8 +293,6 @@ ipv6nd_sendrsprobe(void *arg)
return;
}
- memset(&dst, 0, sizeof(dst));
- dst.sin6_family = AF_INET6;
#ifdef HAVE_SA_LEN
dst.sin6_len = sizeof(dst);
#endif
@@ -297,25 +302,19 @@ ipv6nd_sendrsprobe(void *arg)
return;
}
- state = RS_STATE(ifp);
ctx = ifp->ctx;
- ctx->sndhdr.msg_name = (void *)&dst;
- ctx->sndhdr.msg_iov[0].iov_base = state->rs;
- ctx->sndhdr.msg_iov[0].iov_len = state->rslen;
/* Set the outbound interface */
- cm = CMSG_FIRSTHDR(&ctx->sndhdr);
+ cm = CMSG_FIRSTHDR(&msg);
if (cm == NULL) /* unlikely */
return;
cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(pi));
- memset(&pi, 0, sizeof(pi));
- pi.ipi6_ifindex = ifp->index;
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
logdebugx("%s: sending Router Solicitation", ifp->name);
- if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) {
+ if (sendmsg(ctx->nd_fd, &msg, 0) == -1) {
logerr(__func__);
/* Allow IPv6ND to continue .... at most a few errors
* would be logged.
@@ -341,41 +340,42 @@ ipv6nd_sendadvertisement(void *arg)
struct ipv6_addr *ia = arg;
struct interface *ifp = ia->iface;
struct dhcpcd_ctx *ctx = ifp->ctx;
- struct sockaddr_in6 dst;
+ struct sockaddr_in6 dst = {
+ .sin6_family = AF_INET6,
+ .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 };
+ struct msghdr msg = {
+ .msg_name = &dst, .msg_namelen = sizeof(dst),
+ .msg_iov = &iov, .msg_iovlen = 1,
+ .msg_control = ctl, .msg_controllen = sizeof(ctl),
+ };
struct cmsghdr *cm;
- struct in6_pktinfo pi;
+ struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
const struct rs_state *state = RS_CSTATE(ifp);
if (state == NULL || ifp->carrier <= LINK_DOWN)
goto freeit;
- memset(&dst, 0, sizeof(dst));
- dst.sin6_family = AF_INET6;
#ifdef SIN6_LEN
dst.sin6_len = sizeof(dst);
#endif
- dst.sin6_scope_id = ifp->index;
if (inet_pton(AF_INET6, ALLNODES, &dst.sin6_addr) != 1) {
logerr(__func__);
return;
}
- ctx->sndhdr.msg_name = (void *)&dst;
- ctx->sndhdr.msg_iov[0].iov_base = ia->na;
- ctx->sndhdr.msg_iov[0].iov_len = ia->na_len;
-
/* Set the outbound interface. */
- cm = CMSG_FIRSTHDR(&ctx->sndhdr);
+ cm = CMSG_FIRSTHDR(&msg);
assert(cm != NULL);
cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(pi));
- memset(&pi, 0, sizeof(pi));
- pi.ipi6_ifindex = ifp->index;
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
logdebugx("%s: sending NA for %s", ifp->name, ia->saddr);
- if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1)
+ if (sendmsg(ctx->nd_fd, &msg, 0) == -1)
logerr(__func__);
if (++ia->na_count < MAX_NEIGHBOR_ADVERTISEMENT) {
@@ -872,8 +872,9 @@ dhcp6_start(__unused struct interface *ifp, __unused enum DH6S init_state)
#endif
static void
-ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp,
- struct icmp6_hdr *icp, size_t len, int hoplimit)
+ipv6nd_handlera(struct dhcpcd_ctx *ctx,
+ const struct sockaddr_in6 *from, const char *sfrom,
+ struct interface *ifp, struct icmp6_hdr *icp, size_t len, int hoplimit)
{
size_t i, olen;
struct nd_router_advert *nd_ra;
@@ -895,33 +896,29 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp,
if (ifp == NULL) {
#ifdef DEBUG_RS
- logdebugx("RA for unexpected interface from %s",
- ctx->sfrom);
+ logdebugx("RA for unexpected interface from %s", sfrom);
#endif
return;
}
if (len < sizeof(struct nd_router_advert)) {
- logerrx("IPv6 RA packet too short from %s", ctx->sfrom);
+ logerrx("IPv6 RA packet too short from %s", sfrom);
return;
}
/* RFC 4861 7.1.2 */
if (hoplimit != 255) {
- logerrx("invalid hoplimit(%d) in RA from %s",
- hoplimit, ctx->sfrom);
+ logerrx("invalid hoplimit(%d) in RA from %s", hoplimit, sfrom);
return;
}
-
- if (!IN6_IS_ADDR_LINKLOCAL(&ctx->from.sin6_addr)) {
- logerrx("RA from non local address %s", ctx->sfrom);
+ if (!IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr)) {
+ logerrx("RA from non local address %s", sfrom);
return;
}
if (!(ifp->options->options & DHCPCD_IPV6RS)) {
#ifdef DEBUG_RS
- logerrx("%s: unexpected RA from %s",
- ifp->name, ctx->sfrom);
+ logerrx("%s: unexpected RA from %s", ifp->name, sfrom);
#endif
return;
}
@@ -930,20 +927,20 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp,
if (ipv6_linklocal(ifp) == NULL) {
#ifdef DEBUG_RS
logdebugx("%s: received RA from %s (no link-local)",
- ifp->name, ctx->sfrom);
+ ifp->name, sfrom);
#endif
return;
}
- if (ipv6_iffindaddr(ifp, &ctx->from.sin6_addr, IN6_IFF_TENTATIVE)) {
+ if (ipv6_iffindaddr(ifp, &from->sin6_addr, IN6_IFF_TENTATIVE)) {
logdebugx("%s: ignoring RA from ourself %s",
- ifp->name, ctx->sfrom);
+ ifp->name, sfrom);
return;
}
TAILQ_FOREACH(rap, ctx->ra_routers, next) {
if (ifp == rap->iface &&
- IN6_ARE_ADDR_EQUAL(&rap->from, &ctx->from.sin6_addr))
+ IN6_ARE_ADDR_EQUAL(&rap->from, &from->sin6_addr))
break;
}
@@ -968,8 +965,8 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp,
return;
}
rap->iface = ifp;
- rap->from = ctx->from.sin6_addr;
- strlcpy(rap->sfrom, ctx->sfrom, sizeof(rap->sfrom));
+ rap->from = from->sin6_addr;
+ strlcpy(rap->sfrom, sfrom, sizeof(rap->sfrom));
TAILQ_INIT(&rap->addrs);
new_rap = true;
} else
@@ -991,8 +988,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp,
* in accordance with the own prefix times which would result in too
* much needless log spam. */
logfunc = new_rap ? loginfox : logdebugx,
- logfunc("%s: Router Advertisement from %s",
- ifp->name, ctx->sfrom);
+ logfunc("%s: Router Advertisement from %s", ifp->name, rap->sfrom);
clock_gettime(CLOCK_MONOTONIC, &rap->acquired);
rap->flags = nd_ra->nd_ra_flags_reserved;
@@ -1053,10 +1049,10 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp,
}
if (dho != NULL)
logwarnx("%s: reject RA (option %s) from %s",
- ifp->name, dho->var, ctx->sfrom);
+ ifp->name, dho->var, rap->sfrom);
else
logwarnx("%s: reject RA (option %d) from %s",
- ifp->name, ndo.nd_opt_type, ctx->sfrom);
+ ifp->name, ndo.nd_opt_type, rap->sfrom);
if (new_rap)
ipv6nd_removefreedrop_ra(rap, 0, 0);
else
@@ -1196,7 +1192,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp,
dho->option))
{
logwarnx("%s: reject RA (no option %s) from %s",
- ifp->name, dho->var, ctx->sfrom);
+ ifp->name, dho->var, rap->sfrom);
if (new_rap)
ipv6nd_removefreedrop_ra(rap, 0, 0);
else
@@ -1584,8 +1580,8 @@ ipv6nd_drop(struct interface *ifp)
}
static void
-ipv6nd_handlena(struct dhcpcd_ctx *ctx, struct interface *ifp,
- struct icmp6_hdr *icp, size_t len, int hoplimit)
+ipv6nd_handlena(struct dhcpcd_ctx *ctx, const char *sfrom,
+ struct interface *ifp, struct icmp6_hdr *icp, size_t len, int hoplimit)
{
struct nd_neighbor_advert *nd_na;
struct in6_addr nd_na_target;
@@ -1596,22 +1592,20 @@ ipv6nd_handlena(struct dhcpcd_ctx *ctx, struct interface *ifp,
if (ifp == NULL) {
#ifdef DEBUG_NS
- logdebugx("NA for unexpected interface from %s",
- ctx->sfrom);
+ logdebugx("NA for unexpected interface from %s", sfrom);
#endif
return;
}
if ((size_t)len < sizeof(struct nd_neighbor_advert)) {
- logerrx("%s: IPv6 NA too short from %s",
- ifp->name, ctx->sfrom);
+ logerrx("%s: IPv6 NA too short from %s", ifp->name, sfrom);
return;
}
/* RFC 4861 7.1.2 */
if (hoplimit != 255) {
logerrx("invalid hoplimit(%d) in NA from %s",
- hoplimit, ctx->sfrom);
+ hoplimit, sfrom);
return;
}
@@ -1625,7 +1619,7 @@ ipv6nd_handlena(struct dhcpcd_ctx *ctx, struct interface *ifp,
memcpy(&nd_na_target, &nd_na->nd_na_target, sizeof(nd_na_target));
if (IN6_IS_ADDR_MULTICAST(&nd_na_target)) {
logerrx("%s: NA multicast address %s (%s)",
- ifp->name, taddr, ctx->sfrom);
+ ifp->name, taddr, sfrom);
return;
}
@@ -1637,20 +1631,20 @@ ipv6nd_handlena(struct dhcpcd_ctx *ctx, struct interface *ifp,
if (rap == NULL) {
#ifdef DEBUG_NS
logdebugx("%s: unexpected NA from %s for %s",
- ifp->name, ctx->sfrom, taddr);
+ ifp->name, sfrom, taddr);
#endif
return;
}
#ifdef DEBUG_NS
logdebugx("%s: %sNA for %s from %s",
- ifp->name, is_solicited ? "solicited " : "", taddr, ctx->sfrom);
+ ifp->name, is_solicited ? "solicited " : "", taddr, sfrom);
#endif
/* Node is no longer a router, so remove it from consideration */
if (!is_router && !rap->expired) {
loginfox("%s: %s not a router (%s)",
- ifp->name, taddr, ctx->sfrom);
+ ifp->name, taddr, sfrom);
rap->expired = 1;
rt_build(ifp->ctx, AF_INET6);
script_runreason(ifp, "ROUTERADVERT");
@@ -1665,33 +1659,43 @@ static void
ipv6nd_handledata(void *arg)
{
struct dhcpcd_ctx *ctx;
+ struct sockaddr_in6 from;
+ unsigned char buf[64 * 1024]; /* Maximum ICMPv6 size */
+ struct iovec iov = {
+ .iov_base = buf,
+ .iov_len = sizeof(buf),
+ };
+ unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int))] = { 0 };
+ struct msghdr msg = {
+ .msg_name = &from, .msg_namelen = sizeof(from),
+ .msg_iov = &iov, .msg_iovlen = 1,
+ .msg_control = ctl, .msg_controllen = sizeof(ctl),
+ };
ssize_t len;
struct cmsghdr *cm;
+ char sfrom[INET6_ADDRSTRLEN];
int hoplimit;
struct in6_pktinfo pkt;
struct icmp6_hdr *icp;
struct interface *ifp;
ctx = arg;
- ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
- CMSG_SPACE(sizeof(int));
- len = recvmsg_realloc(ctx->nd_fd, &ctx->rcvhdr, 0);
+ len = recvmsg(ctx->nd_fd, &msg, 0);
if (len == -1) {
logerr(__func__);
return;
}
- ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr,
- ctx->ntopbuf, INET6_ADDRSTRLEN);
+ inet_ntop(AF_INET6, &from.sin6_addr, sfrom, sizeof(sfrom));
if ((size_t)len < sizeof(struct icmp6_hdr)) {
- logerrx("IPv6 ICMP packet too short from %s", ctx->sfrom);
+ logerrx("IPv6 ICMP packet too short from %s", sfrom);
return;
}
pkt.ipi6_ifindex = 0;
hoplimit = 0;
- for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&ctx->rcvhdr);
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&msg);
cm;
- cm = (struct cmsghdr *)CMSG_NXTHDR(&ctx->rcvhdr, cm))
+ cm = (struct cmsghdr *)CMSG_NXTHDR(&msg, cm))
{
if (cm->cmsg_level != IPPROTO_IPV6)
continue;
@@ -1708,7 +1712,7 @@ ipv6nd_handledata(void *arg)
}
if (pkt.ipi6_ifindex == 0) {
- logerrx("IPv6 RA/NA did not contain index from %s", ctx->sfrom);
+ logerrx("IPv6 RA/NA did not contain index from %s", sfrom);
return;
}
@@ -1724,22 +1728,22 @@ ipv6nd_handledata(void *arg)
!(ifp->options->options & DHCPCD_IPV6)))
return;
- icp = (struct icmp6_hdr *)ctx->rcvhdr.msg_iov[0].iov_base;
+ icp = (struct icmp6_hdr *)buf;
if (icp->icmp6_code == 0) {
switch(icp->icmp6_type) {
case ND_NEIGHBOR_ADVERT:
- ipv6nd_handlena(ctx, ifp, icp, (size_t)len,
- hoplimit);
+ ipv6nd_handlena(ctx, sfrom,
+ ifp, icp, (size_t)len, hoplimit);
return;
case ND_ROUTER_ADVERT:
- ipv6nd_handlera(ctx, ifp, icp, (size_t)len,
- hoplimit);
+ ipv6nd_handlera(ctx, &from, sfrom,
+ ifp, icp, (size_t)len, hoplimit);
return;
}
}
logerrx("invalid IPv6 type %d or code %d from %s",
- icp->icmp6_type, icp->icmp6_code, ctx->sfrom);
+ icp->icmp6_type, icp->icmp6_code, sfrom);
}
static void