diff options
| author | Roy Marples <roy@marples.name> | 2019-02-17 09:36:11 +0000 |
|---|---|---|
| committer | Roy Marples <roy@marples.name> | 2019-02-17 09:36:11 +0000 |
| commit | 590fc45d1c373b99d4fae7f8397d63194806b33a (patch) | |
| tree | 0889093e4169a97c9018befe96c3e802879190f8 /src/ipv6nd.c | |
| parent | 30433665d5cdd7bc4bf34bd7d1b8bb933e33c427 (diff) | |
| download | dhcpcd-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.c | 154 |
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 |
