From: Roy Marples Date: Sun, 17 Feb 2019 09:36:11 +0000 (+0000) Subject: Remove the send/recv structures from dhcpcd context and allocate X-Git-Tag: v7.2.0~34 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5fed9d4382316708ce6042e5707b6bb9be05c214;p=thirdparty%2Fdhcpcd.git 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. --- diff --git a/src/common.c b/src/common.c index 6d06604d..0214af2c 100644 --- a/src/common.c +++ b/src/common.c @@ -200,51 +200,3 @@ read_hwaddr_aton(uint8_t **data, const char *path) fclose(fp); return len; } - -ssize_t -recvmsg_realloc(int fd, struct msghdr *msg, int flags) -{ - struct iovec *iov; - ssize_t slen; - size_t len; - void *n; - - assert(msg != NULL); - assert(msg->msg_iov != NULL && msg->msg_iovlen > 0); - assert((flags & (MSG_PEEK | MSG_TRUNC)) == 0); - - /* Assume we are reallocing the last iovec. */ - iov = &msg->msg_iov[msg->msg_iovlen - 1]; - - for (;;) { - /* Passing MSG_TRUNC should return the actual size needed. */ - slen = recvmsg(fd, msg, flags | MSG_PEEK | MSG_TRUNC); - if (slen == -1) - return -1; - if (!(msg->msg_flags & MSG_TRUNC)) - break; - - len = (size_t)slen; - - /* Some kernels return the size of the receive buffer - * on truncation, not the actual size needed. - * So grow the buffer and try again. */ - if (iov->iov_len == len) - len++; - else if (iov->iov_len > len) - break; - len = roundup(len, IOVEC_BUFSIZ); - if ((n = realloc(iov->iov_base, len)) == NULL) - return -1; - iov->iov_base = n; - iov->iov_len = len; - } - - slen = recvmsg(fd, msg, flags); - if (slen != -1 && msg->msg_flags & MSG_TRUNC) { - /* This should not be possible ... */ - errno = ENOBUFS; - return -1; - } - return slen; -} diff --git a/src/common.h b/src/common.h index 713dd1d3..8dfd251c 100644 --- a/src/common.h +++ b/src/common.h @@ -181,6 +181,4 @@ ssize_t addvard(char ***, const char *, const char *, size_t); const char *hwaddr_ntoa(const void *, size_t, char *, size_t); size_t hwaddr_aton(uint8_t *, const char *); size_t read_hwaddr_aton(uint8_t **, const char *); - -ssize_t recvmsg_realloc(int, struct msghdr *, int); #endif diff --git a/src/dhcp6.c b/src/dhcp6.c index b5b035f2..c50efb66 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -168,7 +168,7 @@ static const char * const dhcp6_statuses[] = { "No Prefix Available" }; -static void dhcp6_bind(struct interface *, const char *); +static void dhcp6_bind(struct interface *, const char *, const char *); static void dhcp6_failinform(void *); static int dhcp6_listen(struct dhcpcd_ctx *, struct ipv6_addr *); static void dhcp6_recvaddr(void *); @@ -1157,9 +1157,12 @@ dhcp6_update_auth(struct interface *ifp, struct dhcp6_message *m, size_t len) static int dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *)) { - struct dhcp6_state *state; - struct dhcpcd_ctx *ctx; - struct sockaddr_in6 dst; + struct dhcp6_state *state = D6_STATE(ifp); + struct dhcpcd_ctx *ctx = ifp->ctx; + struct sockaddr_in6 dst = { + .sin6_family = AF_INET6, + .sin6_port = htons(DHCP6_SERVER_PORT), + }; struct timespec RTprev; double rnd; time_t ms; @@ -1168,18 +1171,22 @@ dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *)) 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, + }; + 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, + }; if (!callback && ifp->carrier <= LINK_DOWN) return 0; - memset(&dst, 0, sizeof(dst)); - dst.sin6_family = AF_INET6; - dst.sin6_port = htons(DHCP6_SERVER_PORT); #ifdef HAVE_SA_LEN dst.sin6_len = sizeof(dst); #endif - state = D6_STATE(ifp); 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 @@ -1280,7 +1287,7 @@ logsend: /* Wait the initial delay */ if (state->IMD != 0) { state->IMD = 0; - eloop_timeout_add_tv(ifp->ctx->eloop, + eloop_timeout_add_tv(ctx->eloop, &state->RT, callback, ifp); return 0; } @@ -1301,31 +1308,21 @@ logsend: } #endif - ctx = ifp->ctx; - ctx->sndhdr.msg_name = (void *)&dst; - ctx->sndhdr.msg_iov[0].iov_base = state->send; - ctx->sndhdr.msg_iov[0].iov_len = state->send_len; - /* Set the outbound interface */ if (IN6_ARE_ADDR_EQUAL(&dst.sin6_addr, &alldhcp)) { struct cmsghdr *cm; - struct in6_pktinfo pi; + struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index }; dst.sin6_scope_id = ifp->index; - cm = CMSG_FIRSTHDR(&ctx->sndhdr); + msg.msg_control = ctl; + msg.msg_controllen = sizeof(ctl); + cm = CMSG_FIRSTHDR(&msg); if (cm == NULL) /* unlikely */ return -1; 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)); - } else { - /* Remove the control buffer as we're not dictating - * which interface to use for outgoing messages. */ - ctx->sndhdr.msg_control = NULL; - ctx->sndhdr.msg_controllen = 0; } if (ctx->dhcp6_fd != -1) @@ -1337,7 +1334,7 @@ logsend: return -1; } - if (sendmsg(s, &ctx->sndhdr, 0) == -1) { + if (sendmsg(s, &msg, 0) == -1) { logerr("%s: %s: sendmsg", __func__, ifp->name); /* Allow DHCPv6 to continue .... the errors * would be rate limited by the protocol. @@ -1345,19 +1342,13 @@ logsend: * associate with an access point. */ } - /* Restore the control buffer assignment. */ - if (!IN6_ARE_ADDR_EQUAL(&dst.sin6_addr, &alldhcp)) { - ctx->sndhdr.msg_control = ctx->sndbuf; - ctx->sndhdr.msg_controllen = sizeof(ctx->sndbuf); - } - state->RTC++; if (callback) { if (state->MRC == 0 || state->RTC < state->MRC) - eloop_timeout_add_tv(ifp->ctx->eloop, + eloop_timeout_add_tv(ctx->eloop, &state->RT, callback, ifp); else if (state->MRC != 0 && state->MRCcallback) - eloop_timeout_add_tv(ifp->ctx->eloop, + eloop_timeout_add_tv(ctx->eloop, &state->RT, state->MRCcallback, ifp); else logwarnx("%s: sent %d times with no reply", @@ -1650,7 +1641,7 @@ dhcp6_fail(struct interface *ifp) break; } - dhcp6_bind(ifp, NULL); + dhcp6_bind(ifp, NULL, NULL); switch (state->state) { case DH6S_BOUND: @@ -2927,7 +2918,7 @@ dhcp6_find_delegates(struct interface *ifp) #endif static void -dhcp6_bind(struct interface *ifp, const char *op) +dhcp6_bind(struct interface *ifp, const char *op, const char *sfrom) { struct dhcp6_state *state = D6_STATE(ifp); bool has_new = false; @@ -2943,8 +2934,7 @@ dhcp6_bind(struct interface *ifp, const char *op) } lognewinfo = has_new ? loginfox : logdebugx; if (op != NULL) - lognewinfo("%s: %s received from %s", - ifp->name, op, ifp->ctx->sfrom); + lognewinfo("%s: %s received from %s", ifp->name, op, sfrom); state->reason = NULL; if (state->state != DH6S_ITIMEDOUT) @@ -3176,7 +3166,8 @@ dhcp6_bind(struct interface *ifp, const char *op) } static void -dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len) +dhcp6_recvif(struct interface *ifp, const char *sfrom, + struct dhcp6_message *r, size_t len) { struct dhcpcd_ctx *ctx; size_t i; @@ -3211,8 +3202,7 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len) } if (dhcp6_findmoption(r, len, D6_OPTION_SERVERID, NULL) == NULL) { - logdebugx("%s: no DHCPv6 server ID from %s", - ifp->name, ctx->sfrom); + logdebugx("%s: no DHCPv6 server ID from %s", ifp->name, sfrom); return; } @@ -3225,14 +3215,14 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len) !dhcp6_findmoption(r, len, (uint16_t)opt->option, NULL)) { logwarnx("%s: reject DHCPv6 (no option %s) from %s", - ifp->name, opt->var, ctx->sfrom); + ifp->name, opt->var, sfrom); return; } if (has_option_mask(ifo->rejectmask6, opt->option) && dhcp6_findmoption(r, len, (uint16_t)opt->option, NULL)) { logwarnx("%s: reject DHCPv6 (option %s) from %s", - ifp->name, opt->var, ctx->sfrom); + ifp->name, opt->var, sfrom); return; } } @@ -3245,7 +3235,7 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len) (uint8_t *)r, len, 6, r->type, auth, auth_len) == NULL) { logerr("%s: authentication failed from %s", - ifp->name, ctx->sfrom); + ifp->name, sfrom); return; } if (state->auth.token) @@ -3256,11 +3246,10 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len) } else if (ifo->auth.options & DHCPCD_AUTH_SEND) { if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) { logerr("%s: no authentication from %s", - ifp->name, ctx->sfrom); + ifp->name, sfrom); return; } - logwarnx("%s: no authentication from %s", - ifp->name, ctx->sfrom); + logwarnx("%s: no authentication from %s", ifp->name, sfrom); } #endif @@ -3274,8 +3263,7 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len) return; break; case DH6S_CONFIRM: - if (dhcp6_validatelease(ifp, r, len, - ctx->sfrom, NULL) == -1) + if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1) { dhcp6_startdiscover(ifp); return; @@ -3297,8 +3285,7 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len) case DH6S_REQUEST: /* FALLTHROUGH */ case DH6S_RENEW: /* FALLTHROUGH */ case DH6S_REBIND: - if (dhcp6_validatelease(ifp, r, len, - ctx->sfrom, NULL) == -1) + if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1) { /* * If we can't use the lease, fallback to @@ -3366,7 +3353,7 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len) logerrx("%s: invalid INF_MAX_RT %u", ifp->name, max_rt); } - if (dhcp6_validatelease(ifp, r, len, ctx->sfrom, NULL) == -1) + if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1) return; break; case DHCP6_RECONFIGURE: @@ -3374,12 +3361,12 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len) if (auth == NULL) { #endif logerrx("%s: unauthenticated %s from %s", - ifp->name, op, ctx->sfrom); + ifp->name, op, sfrom); if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) return; #ifdef AUTH } - loginfox("%s: %s from %s", ifp->name, op, ctx->sfrom); + loginfox("%s: %s from %s", ifp->name, op, sfrom); o = dhcp6_findmoption(r, len, D6_OPTION_RECONF_MSG, &ol); if (o == NULL) { logerrx("%s: missing Reconfigure Message option", @@ -3456,10 +3443,10 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len) ia = TAILQ_FIRST(&state->addrs); if (ia == NULL) loginfox("%s: ADV (no address) from %s", - ifp->name, ctx->sfrom); + ifp->name, sfrom); else loginfox("%s: ADV %s from %s", - ifp->name, ia->saddr, ctx->sfrom); + ifp->name, ia->saddr, sfrom); if (ifp->ctx->options & DHCPCD_TEST) break; dhcp6_startrequest(ifp); @@ -3467,33 +3454,44 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len) } } - dhcp6_bind(ifp, op); + dhcp6_bind(ifp, op, sfrom); } 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 */ + struct iovec iov = { + .iov_base = buf, + .iov_len = sizeof(buf), + }; + unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 }; + struct msghdr msg = { + .msg_name = &from, .msg_namelen = sizeof(from), + .msg_iov = &iov, .msg_iovlen = 1, + .msg_control = ctl, .msg_controllen = sizeof(ctl), + }; int s; size_t len; ssize_t bytes; + char sfrom[INET6_ADDRSTRLEN]; struct interface *ifp; struct dhcp6_message *r; const struct dhcp6_state *state; uint8_t *o; uint16_t ol; - ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); s = ia != NULL ? ia->dhcp6_fd : ctx->dhcp6_fd; - bytes = recvmsg_realloc(s, &ctx->rcvhdr, 0); + bytes = recvmsg(s, &msg, 0); if (bytes == -1) { - logerr("%s: recvmsg_realloc", __func__); + logerr(__func__); return; } len = (size_t)bytes; - ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr, - ctx->ntopbuf, sizeof(ctx->ntopbuf)); + inet_ntop(AF_INET6, &from.sin6_addr, sfrom, sizeof(sfrom)); if (len < sizeof(struct dhcp6_message)) { - logerrx("DHCPv6 packet too short from %s", ctx->sfrom); + logerrx("DHCPv6 packet too short from %s", sfrom); return; } @@ -3504,9 +3502,9 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia) struct in6_pktinfo pi; pi.ipi6_ifindex = 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; @@ -3519,7 +3517,7 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia) } if (pi.ipi6_ifindex == 0) { logerrx("DHCPv6 reply did not contain index from %s", - ctx->sfrom); + sfrom); return; } @@ -3529,35 +3527,35 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia) } if (ifp == NULL) { logerrx("DHCPv6 reply for unexpected interface from %s", - ctx->sfrom); + sfrom); return; } } - r = (struct dhcp6_message *)ctx->rcvhdr.msg_iov[0].iov_base; + r = (struct dhcp6_message *)buf; o = dhcp6_findmoption(r, len, D6_OPTION_CLIENTID, &ol); if (o == NULL || ol != ctx->duid_len || memcmp(o, ctx->duid, ol) != 0) { logdebugx("%s: incorrect client ID from %s", - ifp->name, ctx->sfrom); + ifp->name, sfrom); return; } if (dhcp6_findmoption(r, len, D6_OPTION_SERVERID, NULL) == NULL) { logdebugx("%s: no DHCPv6 server ID from %s", - ifp->name, ctx->sfrom); + ifp->name, sfrom); return; } if (r->type == DHCP6_RECONFIGURE) { logdebugx("%s: RECONFIGURE6 recv from %s," " sending to all interfaces", - ifp->name, ctx->sfrom); + ifp->name, sfrom); TAILQ_FOREACH(ifp, ctx->ifaces, next) { state = D6_CSTATE(ifp); if (state != NULL && state->send != NULL) - dhcp6_recvif(ifp, r, len); + dhcp6_recvif(ifp, sfrom, r, len); } return; } @@ -3591,7 +3589,7 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia) state->send->xid[0], state->send->xid[1], state->send->xid[2], - ctx->sfrom); + sfrom); return; } logdebugx("%s: redirecting DHCP6 message to %s", @@ -3599,7 +3597,7 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia) ifp = ifp1; } - dhcp6_recvif(ifp, r, len); + dhcp6_recvif(ifp, sfrom, r, len); } static void diff --git a/src/dhcpcd.c b/src/dhcpcd.c index 6fe60ea1..6d86baa4 100644 --- a/src/dhcpcd.c +++ b/src/dhcpcd.c @@ -2143,7 +2143,6 @@ exit1: #endif dev_stop(&ctx); eloop_free(ctx.eloop); - free(ctx.iov[0].iov_base); if (ctx.options & DHCPCD_STARTED && !(ctx.options & DHCPCD_FORKED)) loginfox(PACKAGE " exited"); diff --git a/src/dhcpcd.h b/src/dhcpcd.h index 39577006..b135f1b7 100644 --- a/src/dhcpcd.h +++ b/src/dhcpcd.h @@ -149,7 +149,6 @@ struct dhcpcd_ctx { int link_fd; int seq; /* route message sequence no */ int sseq; /* successful seq no sent */ - struct iovec iov[1]; /* generic iovec buffer */ #ifdef USE_SIGNALS sigset_t sigset; @@ -184,15 +183,6 @@ struct dhcpcd_ctx { uint8_t *secret; size_t secret_len; - unsigned char ctlbuf[IP6BUFLEN]; - struct sockaddr_in6 from; - struct msghdr sndhdr; - struct iovec sndiov[1]; - unsigned char sndbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; - struct msghdr rcvhdr; - char ntopbuf[INET6_ADDRSTRLEN]; - const char *sfrom; - int nd_fd; struct ra_head *ra_routers; diff --git a/src/if-bsd.c b/src/if-bsd.c index 0fe6d200..f638c641 100644 --- a/src/if-bsd.c +++ b/src/if-bsd.c @@ -1229,18 +1229,19 @@ if_dispatch(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm) int if_handlelink(struct dhcpcd_ctx *ctx) { - struct msghdr msg; + union { + struct rt_msghdr rtmsg; + unsigned char buf[2048]; + } u; + struct iovec iov = { .iov_base = u.buf, .iov_len = sizeof(u) }; + struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 }; ssize_t len; - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = ctx->iov; - msg.msg_iovlen = 1; - - len = recvmsg_realloc(ctx->link_fd, &msg, 0); + len = recvmsg(ctx->link_fd, &msg, 0); if (len == -1) return -1; if (len != 0) - if_dispatch(ctx, ctx->iov[0].iov_base); + if_dispatch(ctx, &u.rtmsg); return 0; } diff --git a/src/if-linux.c b/src/if-linux.c index 99d3ed6a..1e55d672 100644 --- a/src/if-linux.c +++ b/src/if-linux.c @@ -105,7 +105,6 @@ int if_getssid_wext(const char *ifname, uint8_t *ssid); struct priv { int route_fd; uint32_t route_pid; - struct iovec sndrcv_iov[1]; }; /* We need this to send a broadcast for InfiniBand. @@ -346,7 +345,6 @@ if_closesockets_os(struct dhcpcd_ctx *ctx) if (ctx->priv != NULL) { priv = (struct priv *)ctx->priv; - free(priv->sndrcv_iov[0].iov_base); close(priv->route_fd); } } @@ -356,21 +354,18 @@ get_netlink(struct dhcpcd_ctx *ctx, struct iovec *iov, struct interface *ifp, int fd, int flags, int (*callback)(struct dhcpcd_ctx *, struct interface *, struct nlmsghdr *)) { - struct msghdr msg; - struct sockaddr_nl nladdr; + struct sockaddr_nl nladdr = { .nl_pid = 0 }; + struct msghdr msg = { + .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), + .msg_iov = iov, .msg_iovlen = 1, + }; ssize_t len; struct nlmsghdr *nlm; int r; unsigned int again; - memset(&msg, 0, sizeof(msg)); - msg.msg_name = &nladdr; - msg.msg_namelen = sizeof(nladdr); - memset(&nladdr, 0, sizeof(nladdr)); - msg.msg_iov = iov; - msg.msg_iovlen = 1; recv_again: - if ((len = recvmsg_realloc(fd, &msg, flags)) == -1) + if ((len = recvmsg(fd, &msg, flags)) == -1) return -1; if (len == 0) return 0; @@ -816,8 +811,13 @@ link_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp, int if_handlelink(struct dhcpcd_ctx *ctx) { + unsigned char buf[16 * 1024]; + struct iovec iov = { + .iov_base = buf, + .iov_len = sizeof(buf), + }; - return get_netlink(ctx, ctx->iov, NULL, + return get_netlink(ctx, &iov, NULL, ctx->link_fd, MSG_DONTWAIT, &link_netlink); } @@ -827,12 +827,12 @@ send_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp, int (*callback)(struct dhcpcd_ctx *, struct interface *, struct nlmsghdr *)) { int s, r; - struct sockaddr_nl snl; - struct iovec iov[1]; - struct msghdr msg; - - memset(&snl, 0, sizeof(snl)); - snl.nl_family = AF_NETLINK; + struct sockaddr_nl snl = { .nl_family = AF_NETLINK }; + struct iovec iov = { .iov_base = hdr, .iov_len = hdr->nlmsg_len }; + struct msghdr msg = { + .msg_name = &snl, .msg_namelen = sizeof(snl), + .msg_iov = &iov, .msg_iovlen = 1 + }; if (protocol == NETLINK_ROUTE) { struct priv *priv; @@ -844,22 +844,17 @@ send_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp, return -1; } - memset(&msg, 0, sizeof(msg)); - msg.msg_name = &snl; - msg.msg_namelen = sizeof(snl); - memset(&iov, 0, sizeof(iov)); - iov[0].iov_base = hdr; - iov[0].iov_len = hdr->nlmsg_len; - msg.msg_iov = iov; - msg.msg_iovlen = 1; /* Request a reply */ hdr->nlmsg_flags |= NLM_F_ACK; hdr->nlmsg_seq = (uint32_t)++ctx->seq; if (sendmsg(s, &msg, 0) != -1) { - struct priv *priv; + unsigned char buf[16 * 1024]; + struct iovec riov = { + .iov_base = buf, + .iov_len = sizeof(buf), + }; - priv = (struct priv *)ctx->priv; - r = get_netlink(ctx, priv->sndrcv_iov, ifp, s, 0, callback); + r = get_netlink(ctx, &riov, ifp, s, 0, callback); } else r = -1; if (protocol != NETLINK_ROUTE) @@ -1304,17 +1299,15 @@ _if_initrt(struct dhcpcd_ctx *ctx, __unused struct interface *ifp, int if_initrt(struct dhcpcd_ctx *ctx, int af) { - struct nlmr nlm; + struct nlmr nlm = { + .hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)), + .hdr.nlmsg_type = RTM_GETROUTE, + .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH, + .rt.rtm_table = RT_TABLE_MAIN, + .rt.rtm_family = (unsigned char)af, + }; rt_headclear(&ctx->kroutes, af); - - memset(&nlm, 0, sizeof(nlm)); - nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - nlm.hdr.nlmsg_type = RTM_GETROUTE; - nlm.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH; - nlm.rt.rtm_table = RT_TABLE_MAIN; - nlm.rt.rtm_family = (unsigned char)af; - return send_netlink(ctx, NULL, NETLINK_ROUTE, &nlm.hdr, &_if_initrt); } @@ -1401,7 +1394,7 @@ bpf_read(struct interface *ifp, int s, void *data, size_t len, }; struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 }; #ifdef PACKET_AUXDATA - unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))]; + unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))] = { 0 }; struct cmsghdr *cmsg; struct tpacket_auxdata *aux; #endif diff --git a/src/if-sun.c b/src/if-sun.c index d7c2e9c6..76111f4e 100644 --- a/src/if-sun.c +++ b/src/if-sun.c @@ -752,17 +752,18 @@ if_dispatch(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm) int if_handlelink(struct dhcpcd_ctx *ctx) { - struct msghdr msg; + union { + struct rt_msghdr rtmsg; + unsigned char buf[2048]; + } u; + struct iovec iov = { .iov_base = u.buf, .iov_len = sizeof(u) }; + struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 }; ssize_t len; - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = ctx->iov; - msg.msg_iovlen = 1; - - if ((len = recvmsg_realloc(ctx->link_fd, &msg, 0)) == -1) + if ((len = recvmsg(ctx->link_fd, &msg, 0)) == -1) return -1; if (len != 0) - if_dispatch(ctx, ctx->iov[0].iov_base); + if_dispatch(ctx, &u.rtmsg); return 0; } diff --git a/src/ipv6.c b/src/ipv6.c index 62ce9cc6..d7c73c22 100644 --- a/src/ipv6.c +++ b/src/ipv6.c @@ -129,29 +129,14 @@ int ipv6_init(struct dhcpcd_ctx *ctx) { - if (ctx->sndhdr.msg_iovlen == 1) + if (ctx->ra_routers != NULL) return 0; - if (ctx->ra_routers == NULL) { - ctx->ra_routers = malloc(sizeof(*ctx->ra_routers)); - if (ctx->ra_routers == NULL) - return -1; - } + ctx->ra_routers = malloc(sizeof(*ctx->ra_routers)); + if (ctx->ra_routers == NULL) + return -1; TAILQ_INIT(ctx->ra_routers); - ctx->sndhdr.msg_namelen = sizeof(struct sockaddr_in6); - ctx->sndhdr.msg_iov = ctx->sndiov; - ctx->sndhdr.msg_iovlen = 1; - ctx->sndhdr.msg_control = ctx->sndbuf; - ctx->sndhdr.msg_controllen = sizeof(ctx->sndbuf); - ctx->rcvhdr.msg_name = &ctx->from; - ctx->rcvhdr.msg_namelen = sizeof(ctx->from); - ctx->rcvhdr.msg_iov = ctx->iov; - ctx->rcvhdr.msg_iovlen = 1; - ctx->rcvhdr.msg_control = ctx->ctlbuf; - // controllen is set at recieve - //ctx->rcvhdr.msg_controllen = sizeof(ctx->rcvbuf); - ctx->nd_fd = -1; ctx->dhcp6_fd = -1; return 0; 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