From: Roy Marples Date: Sat, 10 Mar 2018 11:50:08 +0000 (+0000) Subject: dhcp6: deny unicast in non master mode X-Git-Tag: v7.0.2~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=efd76398c8cae817370d0bc8f839b2e2d65ac432;p=thirdparty%2Fdhcpcd.git dhcp6: deny unicast in non master mode It seems that some DHCP6 servers or firewalls really insist on the client sending from the correct source port. This is the safest thing for the time being. --- diff --git a/src/dhcp6.c b/src/dhcp6.c index 7c35add9..08b9f283 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -777,6 +777,15 @@ dhcp6_makemessage(struct interface *ifp) return -1; } + /* In non master mode we listen and send from fixed addresses. + * We should try and match an address we have to unicast to, + * but for now this is the safest policy. */ + if (unicast != NULL && !(ifp->ctx->options & DHCPCD_MASTER)) { + logdebugx("%s: ignoring unicast option as not master", + ifp->name); + unicast = NULL; + } + #ifdef AUTH auth_len = 0; if (ifo->auth.options & DHCPCD_AUTH_SEND) { @@ -1092,6 +1101,8 @@ dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *)) uint8_t neg; const char *broad_uni; const struct in6_addr alldhcp = IN6ADDR_LINKLOCAL_ALLDHCP_INIT; + struct ipv6_addr *lla; + int s; if (!callback && ifp->carrier == LINK_DOWN) return 0; @@ -1104,12 +1115,13 @@ dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *)) #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 * a Router Advertisement */ if (IN6_IS_ADDR_UNSPECIFIED(&state->unicast) || (state->state == DH6S_REQUEST && - (!IN6_IS_ADDR_LINKLOCAL(&state->unicast) || !ipv6_linklocal(ifp)))) + (!IN6_IS_ADDR_LINKLOCAL(&state->unicast) || lla == NULL))) { dst.sin6_addr = alldhcp; broad_uni = "broadcasting"; @@ -1251,7 +1263,16 @@ logsend: ctx->sndhdr.msg_controllen = 0; } - if (sendmsg(ctx->dhcp6_fd, &ctx->sndhdr, 0) == -1) { + if (ctx->dhcp6_fd != -1) + s = ctx->dhcp6_fd; + else if (lla != NULL && lla->dhcp6_fd != -1) + s = lla->dhcp6_fd; + else { + logerrx("%s: no socket to send from", ifp->name); + return -1; + } + + if (sendmsg(s, &ctx->sndhdr, 0) == -1) { logerr("%s: %s: sendmsg", __func__, ifp->name); /* Allow DHCPv6 to continue .... the errors * would be rate limited by the protocol. @@ -3551,19 +3572,16 @@ dhcp6_listen(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia) if (ia != NULL) { memcpy(&sa.sin6_addr, &ia->addr, sizeof(sa.sin6_addr)); sa.sin6_scope_id = ia->iface->index; - } else if (!(ctx->options & DHCPCD_MASTER)) - /* This socket is only used for sending. */ - return s; + } if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) == -1) goto errexit; - if (ia == NULL) { - n = 1; - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, - &n, sizeof(n)) == -1) - goto errexit; - } else { + n = 1; + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &n, sizeof(n)) == -1) + goto errexit; + + if (ia != NULL) { ia->dhcp6_fd = s; eloop_event_add(ctx->eloop, s, dhcp6_recvaddr, ia); } @@ -3577,18 +3595,6 @@ errexit: return -1; } -static int -dhcp6_open(struct dhcpcd_ctx *ctx) -{ - - /* Open an unbound socket to send from. */ - ctx->dhcp6_fd = dhcp6_listen(ctx, NULL); - if (ctx->dhcp6_fd != -1 && (ctx->options & DHCPCD_MASTER)) - eloop_event_add(ctx->eloop, ctx->dhcp6_fd, dhcp6_recvctx, ctx); - - return ctx->dhcp6_fd; -} - #ifndef SMALL static void dhcp6_activateinterfaces(struct interface *ifp) @@ -3623,13 +3629,18 @@ static void dhcp6_start1(void *arg) { struct interface *ifp = arg; + struct dhcpcd_ctx *ctx = ifp->ctx; struct if_options *ifo = ifp->options; struct dhcp6_state *state; size_t i; const struct dhcp_compat *dhc; - if (ifp->ctx->dhcp6_fd == -1 && dhcp6_open(ifp->ctx) == -1) - return; + if (ctx->dhcp6_fd == -1 && ctx->options & DHCPCD_MASTER) { + ctx->dhcp6_fd = dhcp6_listen(ctx, NULL); + if (ctx->dhcp6_fd == -1) + return; + eloop_event_add(ctx->eloop, ctx->dhcp6_fd, dhcp6_recvctx, ctx); + } state = D6_STATE(ifp); /* If no DHCPv6 options are configured,