]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
dhcp6: deny unicast in non master mode
authorRoy Marples <roy@marples.name>
Sat, 10 Mar 2018 11:50:08 +0000 (11:50 +0000)
committerRoy Marples <roy@marples.name>
Sat, 10 Mar 2018 11:50:08 +0000 (11:50 +0000)
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.

src/dhcp6.c

index 7c35add9440ce894c8a6268bd1dbf6bd31825f08..08b9f283119a64b8764029938895348ab5cf9db0 100644 (file)
@@ -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,