]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Implement Anonymity Profiles for DHCP Clients, RFC 7844
authorRoy Marples <roy@marples.name>
Wed, 15 Jan 2020 14:28:24 +0000 (14:28 +0000)
committerRoy Marples <roy@marples.name>
Wed, 15 Jan 2020 14:28:24 +0000 (14:28 +0000)
This works by randomising the hardware address when carrier is down
and using this to construct a DUID LL which is used over any saved
DUID. IAID is defaulted to zero and hostname + FQDN are disabled.
Then every possible option is masked out except for essential ones.

It's possible to request options *after* anonymous option which
will enable it. This is RFC compliant and allows 100% flexability
in letting the user decide what, if any, details leek out.

This is disabled by default.
Only works on NetBSD, other OS coming shortly.

18 files changed:
src/dhcp-common.h
src/dhcp.c
src/dhcp6.c
src/dhcpcd-definitions-small.conf
src/dhcpcd-definitions.conf
src/dhcpcd.8.in
src/dhcpcd.c
src/dhcpcd.conf.5.in
src/duid.c
src/duid.h
src/if-bsd.c
src/if-options.c
src/if-options.h
src/if.c
src/if.h
src/privsep-bsd.c
src/privsep-root.h
src/privsep.h

index 558a5705c3bdfc54156a06c7b262f3465a0f9bcc..ed020b139535fa2ae396112dd3b4a88dae98ea1c 100644 (file)
@@ -81,6 +81,9 @@
 #define        OT_BITFLAG              (1 << 27)
 #define        OT_RESERVED             (1 << 28)
 
+#define        DHC_REQ(r, n, o) \
+       (has_option_mask((r), (o)) && !has_option_mask((n), (o)))
+
 #define DHC_REQOPT(o, r, n)                                              \
        (!((o)->type & OT_NOREQ) &&                                       \
         ((o)->type & OT_REQUEST || has_option_mask((r), (o)->option)) && \
index 2a1fbc2759e644c2b94cc61267b72d0ce966315b..54de9f7291d881ba61c9447cb3001bed557fb5f2 100644 (file)
@@ -782,12 +782,9 @@ make_message(struct bootp **bootpm, const struct interface *ifp, uint8_t type)
 
        bootp->op = BOOTREQUEST;
        bootp->htype = (uint8_t)ifp->family;
-       switch (ifp->family) {
-       case ARPHRD_ETHER:
-       case ARPHRD_IEEE802:
+       if (ifp->hwlen != 0 && ifp->hwlen < sizeof(bootp->chaddr)) {
                bootp->hlen = (uint8_t)ifp->hwlen;
                memcpy(&bootp->chaddr, &ifp->hwaddr, ifp->hwlen);
-               break;
        }
 
        if (ifo->options & DHCPCD_BROADCAST &&
@@ -820,10 +817,6 @@ make_message(struct bootp **bootpm, const struct interface *ifp, uint8_t type)
        memcpy(p, &ul, sizeof(ul));
        p += sizeof(ul);
 
-       *p++ = DHO_MESSAGETYPE;
-       *p++ = 1;
-       *p++ = type;
-
 #define AREA_LEFT      (size_t)(e - p)
 #define AREA_FIT(s)    if ((s) > AREA_LEFT) goto toobig
 #define AREA_CHECK(s)  if ((s) + 2UL > AREA_LEFT) goto toobig
@@ -835,13 +828,10 @@ make_message(struct bootp **bootpm, const struct interface *ifp, uint8_t type)
        p += 4;                         \
 } while (0 /* CONSTCOND */)
 
-       if (state->clientid) {
-               AREA_CHECK(state->clientid[0]);
-               *p++ = DHO_CLIENTID;
-               memcpy(p, state->clientid, (size_t)state->clientid[0] + 1);
-               p += state->clientid[0] + 1;
-       }
+       /* Options are listed in numerical order as per RFC 7844 Section 3.1
+        * XXX: They should be randomised. */
 
+       bool putip = false;
        if (lease->addr.s_addr && lease->cookie == htonl(MAGIC_COOKIE)) {
                if (type == DHCP_DECLINE ||
                    (type == DHCP_REQUEST &&
@@ -849,12 +839,18 @@ make_message(struct bootp **bootpm, const struct interface *ifp, uint8_t type)
                    state->added & STATE_FAKE ||
                    lease->addr.s_addr != state->addr->addr.s_addr)))
                {
+                       putip = true;
                        PUT_ADDR(DHO_IPADDRESS, &lease->addr);
-                       if (lease->server.s_addr)
-                               PUT_ADDR(DHO_SERVERID, &lease->server);
                }
+       }
+
+       AREA_CHECK(3);
+       *p++ = DHO_MESSAGETYPE;
+       *p++ = 1;
+       *p++ = type;
 
-               if (type == DHCP_RELEASE) {
+       if (lease->addr.s_addr && lease->cookie == htonl(MAGIC_COOKIE)) {
+               if (type == DHCP_RELEASE || putip) {
                        if (lease->server.s_addr)
                                PUT_ADDR(DHO_SERVERID, &lease->server);
                }
@@ -870,32 +866,75 @@ make_message(struct bootp **bootpm, const struct interface *ifp, uint8_t type)
                }
        }
 
-       if (type == DHCP_DISCOVER &&
-           !(ifp->ctx->options & DHCPCD_TEST) &&
-           has_option_mask(ifo->requestmask, DHO_RAPIDCOMMIT))
-       {
-               /* RFC 4039 Section 3 */
-               AREA_CHECK(0);
-               *p++ = DHO_RAPIDCOMMIT;
-               *p++ = 0;
+#define        DHCP_DIR(type) ((type) == DHCP_DISCOVER || (type) == DHCP_INFORM || \
+    (type) == DHCP_REQUEST)
+
+       if (DHCP_DIR(type)) {
+               /* vendor is already encoded correctly, so just add it */
+               if (ifo->vendor[0]) {
+                       AREA_CHECK(ifo->vendor[0]);
+                       *p++ = DHO_VENDOR;
+                       memcpy(p, ifo->vendor, (size_t)ifo->vendor[0] + 1);
+                       p += ifo->vendor[0] + 1;
+               }
        }
 
        if (type == DHCP_DISCOVER && ifo->options & DHCPCD_REQUEST)
                PUT_ADDR(DHO_IPADDRESS, &ifo->req_addr);
 
-       /* RFC 2563 Auto Configure */
-       if (type == DHCP_DISCOVER && ifo->options & DHCPCD_IPV4LL) {
-               AREA_CHECK(1);
-               *p++ = DHO_AUTOCONFIGURE;
-               *p++ = 1;
-               *p++ = 1;
-       }
+       if (DHCP_DIR(type)) {
+               if (type != DHCP_INFORM) {
+                       if (ifo->leasetime != 0) {
+                               AREA_CHECK(4);
+                               *p++ = DHO_LEASETIME;
+                               *p++ = 4;
+                               ul = htonl(ifo->leasetime);
+                               memcpy(p, &ul, 4);
+                               p += 4;
+                       }
+               }
 
-       if (type == DHCP_DISCOVER ||
-           type == DHCP_INFORM ||
-           type == DHCP_REQUEST)
-       {
-               if (mtu != -1) {
+               AREA_CHECK(0);
+               *p++ = DHO_PARAMETERREQUESTLIST;
+               n_params = p;
+               *p++ = 0;
+               for (i = 0, opt = ifp->ctx->dhcp_opts;
+                   i < ifp->ctx->dhcp_opts_len;
+                   i++, opt++)
+               {
+                       if (!DHC_REQOPT(opt, ifo->requestmask, ifo->nomask))
+                               continue;
+                       if (type == DHCP_INFORM &&
+                           (opt->option == DHO_RENEWALTIME ||
+                               opt->option == DHO_REBINDTIME))
+                               continue;
+                       AREA_FIT(1);
+                       *p++ = (uint8_t)opt->option;
+               }
+               for (i = 0, opt = ifo->dhcp_override;
+                   i < ifo->dhcp_override_len;
+                   i++, opt++)
+               {
+                       /* Check if added above */
+                       for (lp = n_params + 1; lp < p; lp++)
+                               if (*lp == (uint8_t)opt->option)
+                                       break;
+                       if (lp < p)
+                               continue;
+                       if (!DHC_REQOPT(opt, ifo->requestmask, ifo->nomask))
+                               continue;
+                       if (type == DHCP_INFORM &&
+                           (opt->option == DHO_RENEWALTIME ||
+                               opt->option == DHO_REBINDTIME))
+                               continue;
+                       AREA_FIT(1);
+                       *p++ = (uint8_t)opt->option;
+               }
+               *n_params = (uint8_t)(p - n_params - 1);
+
+               if (mtu != -1 &&
+                   !(has_option_mask(ifo->nomask, DHO_MAXMESSAGESIZE)))
+               {
                        AREA_CHECK(2);
                        *p++ = DHO_MAXMESSAGESIZE;
                        *p++ = 2;
@@ -904,40 +943,45 @@ make_message(struct bootp **bootpm, const struct interface *ifp, uint8_t type)
                        p += 2;
                }
 
-               if (ifo->userclass[0]) {
+               if (ifo->userclass[0] &&
+                   !has_option_mask(ifo->nomask, DHO_USERCLASS))
+               {
                        AREA_CHECK(ifo->userclass[0]);
                        *p++ = DHO_USERCLASS;
                        memcpy(p, ifo->userclass,
                            (size_t)ifo->userclass[0] + 1);
                        p += ifo->userclass[0] + 1;
                }
+       }
 
-               if (ifo->vendorclassid[0]) {
-                       AREA_CHECK(ifo->vendorclassid[0]);
-                       *p++ = DHO_VENDORCLASSID;
-                       memcpy(p, ifo->vendorclassid,
-                           (size_t)ifo->vendorclassid[0] + 1);
-                       p += ifo->vendorclassid[0] + 1;
-               }
+       if (state->clientid) {
+               AREA_CHECK(state->clientid[0]);
+               *p++ = DHO_CLIENTID;
+               memcpy(p, state->clientid, (size_t)state->clientid[0] + 1);
+               p += state->clientid[0] + 1;
+       }
 
-               if (ifo->mudurl[0]) {
-                      AREA_CHECK(ifo->mudurl[0]);
-                      *p++ = DHO_MUDURL;
-                      memcpy(p, ifo->mudurl, (size_t)ifo->mudurl[0] + 1);
-                      p += ifo->mudurl[0] + 1;
-               }
+       if (DHCP_DIR(type) &&
+           !has_option_mask(ifo->nomask, DHO_VENDORCLASSID) &&
+           ifo->vendorclassid[0])
+       {
+               AREA_CHECK(ifo->vendorclassid[0]);
+               *p++ = DHO_VENDORCLASSID;
+               memcpy(p, ifo->vendorclassid, (size_t)ifo->vendorclassid[0]+1);
+               p += ifo->vendorclassid[0] + 1;
+       }
 
-               if (type != DHCP_INFORM) {
-                       if (ifo->leasetime != 0) {
-                               AREA_CHECK(4);
-                               *p++ = DHO_LEASETIME;
-                               *p++ = 4;
-                               ul = htonl(ifo->leasetime);
-                               memcpy(p, &ul, 4);
-                               p += 4;
-                       }
-               }
+       if (type == DHCP_DISCOVER &&
+           !(ifp->ctx->options & DHCPCD_TEST) &&
+           DHC_REQ(ifo->requestmask, ifo->nomask, DHO_RAPIDCOMMIT))
+       {
+               /* RFC 4039 Section 3 */
+               AREA_CHECK(0);
+               *p++ = DHO_RAPIDCOMMIT;
+               *p++ = 0;
+       }
 
+       if (DHCP_DIR(type)) {
                hostname = dhcp_get_hostname(hbuf, sizeof(hbuf), ifo);
 
                /*
@@ -984,29 +1028,53 @@ make_message(struct bootp **bootpm, const struct interface *ifp, uint8_t type)
                        memcpy(p, hostname, len);
                        p += len;
                }
-
-               /* vendor is already encoded correctly, so just add it */
-               if (ifo->vendor[0]) {
-                       AREA_CHECK(ifo->vendor[0]);
-                       *p++ = DHO_VENDOR;
-                       memcpy(p, ifo->vendor, (size_t)ifo->vendor[0] + 1);
-                       p += ifo->vendor[0] + 1;
-               }
+       }
 
 #ifdef AUTH
-               if ((ifo->auth.options & DHCPCD_AUTH_SENDREQUIRE) !=
-                   DHCPCD_AUTH_SENDREQUIRE &&
-                   !has_option_mask(ifo->nomask, DHO_FORCERENEW_NONCE))
-               {
-                       /* We support HMAC-MD5 */
-                       AREA_CHECK(1);
-                       *p++ = DHO_FORCERENEW_NONCE;
-                       *p++ = 1;
-                       *p++ = AUTH_ALG_HMAC_MD5;
+       auth = NULL;    /* appease GCC */
+       auth_len = 0;
+       if (ifo->auth.options & DHCPCD_AUTH_SEND) {
+               ssize_t alen = dhcp_auth_encode(&ifo->auth,
+                   state->auth.token,
+                   NULL, 0, 4, type, NULL, 0);
+               if (alen != -1 && alen > UINT8_MAX) {
+                       errno = ERANGE;
+                       alen = -1;
+               }
+               if (alen == -1)
+                       logerr("%s: dhcp_auth_encode", ifp->name);
+               else if (alen != 0) {
+                       auth_len = (uint8_t)alen;
+                       AREA_CHECK(auth_len);
+                       *p++ = DHO_AUTHENTICATION;
+                       *p++ = auth_len;
+                       auth = p;
+                       p += auth_len;
                }
+       }
 #endif
 
-               if (ifo->vivco_len) {
+       /* RFC 2563 Auto Configure */
+       if (type == DHCP_DISCOVER && ifo->options & DHCPCD_IPV4LL &&
+           !(has_option_mask(ifo->nomask, DHO_AUTOCONFIGURE)))
+       {
+               AREA_CHECK(1);
+               *p++ = DHO_AUTOCONFIGURE;
+               *p++ = 1;
+               *p++ = 1;
+       }
+
+       if (DHCP_DIR(type)) {
+               if (ifo->mudurl[0]) {
+                      AREA_CHECK(ifo->mudurl[0]);
+                      *p++ = DHO_MUDURL;
+                      memcpy(p, ifo->mudurl, (size_t)ifo->mudurl[0] + 1);
+                      p += ifo->mudurl[0] + 1;
+               }
+
+               if (ifo->vivco_len &&
+                   !has_option_mask(ifo->nomask, DHO_VIVCO))
+               {
                        AREA_CHECK(sizeof(ul));
                        *p++ = DHO_VIVCO;
                        lp = p++;
@@ -1032,68 +1100,19 @@ make_message(struct bootp **bootpm, const struct interface *ifp, uint8_t type)
                        }
                }
 
-               AREA_CHECK(0);
-               *p++ = DHO_PARAMETERREQUESTLIST;
-               n_params = p;
-               *p++ = 0;
-               for (i = 0, opt = ifp->ctx->dhcp_opts;
-                   i < ifp->ctx->dhcp_opts_len;
-                   i++, opt++)
-               {
-                       if (!DHC_REQOPT(opt, ifo->requestmask, ifo->nomask))
-                               continue;
-                       if (type == DHCP_INFORM &&
-                           (opt->option == DHO_RENEWALTIME ||
-                               opt->option == DHO_REBINDTIME))
-                               continue;
-                       AREA_FIT(1);
-                       *p++ = (uint8_t)opt->option;
-               }
-               for (i = 0, opt = ifo->dhcp_override;
-                   i < ifo->dhcp_override_len;
-                   i++, opt++)
-               {
-                       /* Check if added above */
-                       for (lp = n_params + 1; lp < p; lp++)
-                               if (*lp == (uint8_t)opt->option)
-                                       break;
-                       if (lp < p)
-                               continue;
-                       if (!DHC_REQOPT(opt, ifo->requestmask, ifo->nomask))
-                               continue;
-                       if (type == DHCP_INFORM &&
-                           (opt->option == DHO_RENEWALTIME ||
-                               opt->option == DHO_REBINDTIME))
-                               continue;
-                       AREA_FIT(1);
-                       *p++ = (uint8_t)opt->option;
-               }
-               *n_params = (uint8_t)(p - n_params - 1);
-       }
-
 #ifdef AUTH
-       auth = NULL;    /* appease GCC */
-       auth_len = 0;
-       if (ifo->auth.options & DHCPCD_AUTH_SEND) {
-               ssize_t alen = dhcp_auth_encode(&ifo->auth,
-                   state->auth.token,
-                   NULL, 0, 4, type, NULL, 0);
-               if (alen != -1 && alen > UINT8_MAX) {
-                       errno = ERANGE;
-                       alen = -1;
-               }
-               if (alen == -1)
-                       logerr("%s: dhcp_auth_encode", ifp->name);
-               else if (alen != 0) {
-                       auth_len = (uint8_t)alen;
-                       AREA_CHECK(auth_len);
-                       *p++ = DHO_AUTHENTICATION;
-                       *p++ = auth_len;
-                       auth = p;
-                       p += auth_len;
+               if ((ifo->auth.options & DHCPCD_AUTH_SENDREQUIRE) !=
+                   DHCPCD_AUTH_SENDREQUIRE &&
+                   !has_option_mask(ifo->nomask, DHO_FORCERENEW_NONCE))
+               {
+                       /* We support HMAC-MD5 */
+                       AREA_CHECK(1);
+                       *p++ = DHO_FORCERENEW_NONCE;
+                       *p++ = 1;
+                       *p++ = AUTH_ALG_HMAC_MD5;
                }
-       }
 #endif
+       }
 
        *p++ = DHO_END;
        len = (size_t)(p - (uint8_t *)bootp);
@@ -3762,7 +3781,22 @@ dhcp_init(struct interface *ifp)
        free(state->clientid);
        state->clientid = NULL;
 
-       if (*ifo->clientid) {
+       if (ifo->options & DHCPCD_ANONYMOUS) {
+               uint8_t duid[DUID_LEN];
+               uint8_t duid_len;
+
+               duid_len = (uint8_t)duid_make(duid, ifp, DUID_LL);
+               if (duid_len != 0) {
+                       state->clientid = malloc((size_t)duid_len + 6);
+                       if (state->clientid == NULL)
+                               goto eexit;
+                       state->clientid[0] =(uint8_t)(duid_len + 5);
+                       state->clientid[1] = 255; /* RFC 4361 */
+                       memcpy(state->clientid + 2, ifo->iaid, 4);
+                       memset(state->clientid + 2, 0, 4); /* IAID */
+                       memcpy(state->clientid + 6, duid, duid_len);
+               }
+       } else if (*ifo->clientid) {
                state->clientid = malloc((size_t)(ifo->clientid[0] + 1));
                if (state->clientid == NULL)
                        goto eexit;
@@ -3976,7 +4010,9 @@ dhcp_start1(void *arg)
        }
 #endif
 
-       if (state->offer == NULL || !IS_DHCP(state->offer))
+       if (state->offer == NULL ||
+           !IS_DHCP(state->offer) ||
+           ifo->options & DHCPCD_ANONYMOUS)
                dhcp_discover(ifp);
        else
                dhcp_reboot(ifp);
index c1667303e3a3ee60a2a8b29345682f2337d5f300..901bda610f68b0f8998e5e7e965c699e97780115 100644 (file)
@@ -637,6 +637,8 @@ dhcp6_makemessage(struct interface *ifp)
 #ifdef AUTH
        uint16_t auth_len;
 #endif
+       uint8_t duid[DUID_LEN];
+       size_t duid_len = 0;
 
        state = D6_STATE(ifp);
        if (state->send) {
@@ -705,19 +707,29 @@ dhcp6_makemessage(struct interface *ifp)
                        len += sizeof(o) + 1 + hl;
                }
 
-               if (ifo->mudurl[0])
+               if (!has_option_mask(ifo->nomask6, D6_OPTION_MUDURL) &&
+                   ifo->mudurl[0])
                        len += sizeof(o) + ifo->mudurl[0];
 
 #ifdef AUTH
                if ((ifo->auth.options & DHCPCD_AUTH_SENDREQUIRE) !=
-                   DHCPCD_AUTH_SENDREQUIRE)
+                   DHCPCD_AUTH_SENDREQUIRE &&
+                   DHC_REQ(ifo->requestmask6, ifo->nomask6,
+                   D6_OPTION_RECONF_ACCEPT))
                        len += sizeof(o); /* Reconfigure Accept */
 #endif
        }
 
        len += sizeof(*state->send);
-       len += sizeof(o) + ifp->ctx->duid_len;
        len += sizeof(o) + sizeof(uint16_t); /* elapsed */
+
+       if (ifo->options & DHCPCD_ANONYMOUS) {
+               duid_len = duid_make(duid, ifp, DUID_LL);
+               len += sizeof(o) + duid_len;
+       } else {
+               len += sizeof(o) + ifp->ctx->duid_len;
+       }
+
        if (!has_option_mask(ifo->nomask6, D6_OPTION_USER_CLASS))
                len += dhcp6_makeuser(NULL, ifp);
        if (!has_option_mask(ifo->nomask6, D6_OPTION_VENDOR_CLASS))
@@ -755,8 +767,9 @@ dhcp6_makemessage(struct interface *ifp)
                TAILQ_FOREACH(ap, &state->addrs, next) {
                        if (ap->flags & IPV6_AF_STALE)
                                continue;
-                       if (ap->prefix_vltime == 0 &&
-                           !(ap->flags & IPV6_AF_REQUEST))
+                       if (!(ap->flags & IPV6_AF_REQUEST) &&
+                           (ap->prefix_vltime == 0 ||
+                           state->state == DH6S_DISCOVER))
                                continue;
                        if (ap->ia_type == D6_OPTION_IA_PD) {
 #ifndef SMALL
@@ -785,7 +798,7 @@ dhcp6_makemessage(struct interface *ifp)
 
        if (state->state == DH6S_DISCOVER &&
            !(ifp->ctx->options & DHCPCD_TEST) &&
-           has_option_mask(ifo->requestmask6, D6_OPTION_RAPID_COMMIT))
+           DHC_REQ(ifo->requestmask6, ifo->nomask6, D6_OPTION_RAPID_COMMIT))
                len += sizeof(o);
 
        if (m == NULL) {
@@ -884,35 +897,29 @@ dhcp6_makemessage(struct interface *ifp)
        memcpy(p, &o, sizeof(o));               \
        p += sizeof(o);                         \
 }
-#define COPYIN(_code, _data, _len)     {       \
+#define COPYIN(_code, _data, _len)     do {    \
        COPYIN1((_code), (_len));               \
        if ((_len) != 0) {                      \
                memcpy(p, (_data), (_len));     \
                p += (_len);                    \
        }                                       \
-}
+} while (0 /* CONSTCOND */)
 #define NEXTLEN (p + offsetof(struct dhcp6_option, len))
 
+       /* Options are listed in numerical order as per RFC 7844 Section 4.1
+        * XXX: They should be randomised. */
+
        p = (uint8_t *)state->send + sizeof(*state->send);
-       COPYIN(D6_OPTION_CLIENTID, ifp->ctx->duid,
-           (uint16_t)ifp->ctx->duid_len);
+       if (ifo->options & DHCPCD_ANONYMOUS)
+               COPYIN(D6_OPTION_CLIENTID, duid,
+                   (uint16_t)duid_len);
+       else
+               COPYIN(D6_OPTION_CLIENTID, ifp->ctx->duid,
+                   (uint16_t)ifp->ctx->duid_len);
 
        if (si != NULL)
                COPYIN(D6_OPTION_SERVERID, si, si_len);
 
-       si_len = 0;
-       COPYIN(D6_OPTION_ELAPSED, &si_len, sizeof(si_len));
-
-       if (!has_option_mask(ifo->nomask6, D6_OPTION_USER_CLASS))
-               p += dhcp6_makeuser(p, ifp);
-       if (!has_option_mask(ifo->nomask6, D6_OPTION_VENDOR_CLASS))
-               p += dhcp6_makevendor(p, ifp);
-
-       if (state->state == DH6S_DISCOVER &&
-           !(ifp->ctx->options & DHCPCD_TEST) &&
-           has_option_mask(ifo->requestmask6, D6_OPTION_RAPID_COMMIT))
-               COPYIN1(D6_OPTION_RAPID_COMMIT, 0);
-
        for (l = 0; IA && l < ifo->ia_len; l++) {
                ifia = &ifo->ia[l];
                o_lenp = NEXTLEN;
@@ -931,8 +938,9 @@ dhcp6_makemessage(struct interface *ifp)
                TAILQ_FOREACH(ap, &state->addrs, next) {
                        if (ap->flags & IPV6_AF_STALE)
                                continue;
-                       if (ap->prefix_vltime == 0 &&
-                           !(ap->flags & IPV6_AF_REQUEST))
+                       if (!(ap->flags & IPV6_AF_REQUEST) &&
+                           (ap->prefix_vltime == 0 ||
+                           state->state == DH6S_DISCOVER))
                                continue;
                        if (ap->ia_type != ifia->ia_type)
                                continue;
@@ -995,6 +1003,68 @@ dhcp6_makemessage(struct interface *ifp)
                memcpy(o_lenp, &ia_na_len, sizeof(ia_na_len));
        }
 
+       if (state->send->type != DHCP6_RELEASE && n_options) {
+               o_lenp = NEXTLEN;
+               o.len = 0;
+               COPYIN1(D6_OPTION_ORO, 0);
+               for (l = 0, opt = ifp->ctx->dhcp6_opts;
+                   l < ifp->ctx->dhcp6_opts_len;
+                   l++, opt++)
+               {
+#ifndef SMALL
+                       for (n = 0, opt2 = ifo->dhcp6_override;
+                           n < ifo->dhcp6_override_len;
+                           n++, opt2++)
+                       {
+                               if (opt->option == opt2->option)
+                                       break;
+                       }
+                       if (n < ifo->dhcp6_override_len)
+                           continue;
+#endif
+                       if (!DHC_REQOPT(opt, ifo->requestmask6, ifo->nomask6))
+                               continue;
+                       o.code = htons((uint16_t)opt->option);
+                       memcpy(p, &o.code, sizeof(o.code));
+                       p += sizeof(o.code);
+                       o.len = (uint16_t)(o.len + sizeof(o.code));
+               }
+#ifndef SMALL
+               for (l = 0, opt = ifo->dhcp6_override;
+                   l < ifo->dhcp6_override_len;
+                   l++, opt++)
+               {
+                       if (!DHC_REQOPT(opt, ifo->requestmask6, ifo->nomask6))
+                               continue;
+                       o.code = htons((uint16_t)opt->option);
+                       memcpy(p, &o.code, sizeof(o.code));
+                       p += sizeof(o.code);
+                       o.len = (uint16_t)(o.len + sizeof(o.code));
+               }
+               if (dhcp6_findselfsla(ifp)) {
+                       o.code = htons(D6_OPTION_PD_EXCLUDE);
+                       memcpy(p, &o.code, sizeof(o.code));
+                       p += sizeof(o.code);
+                       o.len = (uint16_t)(o.len + sizeof(o.code));
+               }
+#endif
+               o.len = htons(o.len);
+               memcpy(o_lenp, &o.len, sizeof(o.len));
+       }
+
+       si_len = 0;
+       COPYIN(D6_OPTION_ELAPSED, &si_len, sizeof(si_len));
+
+       if (state->state == DH6S_DISCOVER &&
+           !(ifp->ctx->options & DHCPCD_TEST) &&
+           DHC_REQ(ifo->requestmask6, ifo->nomask6, D6_OPTION_RAPID_COMMIT))
+               COPYIN1(D6_OPTION_RAPID_COMMIT, 0);
+
+       if (!has_option_mask(ifo->nomask6, D6_OPTION_USER_CLASS))
+               p += dhcp6_makeuser(p, ifp);
+       if (!has_option_mask(ifo->nomask6, D6_OPTION_VENDOR_CLASS))
+               p += dhcp6_makevendor(p, ifp);
+
        if (state->send->type != DHCP6_RELEASE) {
                if (fqdn != FQDN_DISABLE) {
                        o_lenp = NEXTLEN;
@@ -1021,67 +1091,19 @@ dhcp6_makemessage(struct interface *ifp)
                        memcpy(o_lenp, &o.len, sizeof(o.len));
                }
 
-               if (ifo->mudurl[0])
+               if (!has_option_mask(ifo->nomask6, D6_OPTION_MUDURL &&
+                   ifo->mudurl[0]))
                        COPYIN(D6_OPTION_MUDURL,
                            ifo->mudurl + 1, ifo->mudurl[0]);
 
 #ifdef AUTH
                if ((ifo->auth.options & DHCPCD_AUTH_SENDREQUIRE) !=
                    DHCPCD_AUTH_SENDREQUIRE &&
-                   !has_option_mask(ifo->nomask6, D6_OPTION_RECONF_ACCEPT))
+                   DHC_REQ(ifo->requestmask6, ifo->nomask6,
+                   D6_OPTION_RECONF_ACCEPT))
                        COPYIN1(D6_OPTION_RECONF_ACCEPT, 0);
 #endif
 
-               if (n_options) {
-                       o_lenp = NEXTLEN;
-                       o.len = 0;
-                       COPYIN1(D6_OPTION_ORO, 0);
-                       for (l = 0, opt = ifp->ctx->dhcp6_opts;
-                           l < ifp->ctx->dhcp6_opts_len;
-                           l++, opt++)
-                       {
-#ifndef SMALL
-                               for (n = 0, opt2 = ifo->dhcp6_override;
-                                   n < ifo->dhcp6_override_len;
-                                   n++, opt2++)
-                               {
-                                       if (opt->option == opt2->option)
-                                               break;
-                               }
-                               if (n < ifo->dhcp6_override_len)
-                                   continue;
-#endif
-                               if (!DHC_REQOPT(opt, ifo->requestmask6,
-                                   ifo->nomask6))
-                                       continue;
-                               o.code = htons((uint16_t)opt->option);
-                               memcpy(p, &o.code, sizeof(o.code));
-                               p += sizeof(o.code);
-                               o.len = (uint16_t)(o.len + sizeof(o.code));
-                       }
-#ifndef SMALL
-                       for (l = 0, opt = ifo->dhcp6_override;
-                           l < ifo->dhcp6_override_len;
-                           l++, opt++)
-                       {
-                               if (!DHC_REQOPT(opt, ifo->requestmask6,
-                                   ifo->nomask6))
-                                       continue;
-                               o.code = htons((uint16_t)opt->option);
-                               memcpy(p, &o.code, sizeof(o.code));
-                               p += sizeof(o.code);
-                               o.len = (uint16_t)(o.len + sizeof(o.code));
-                       }
-                       if (dhcp6_findselfsla(ifp)) {
-                               o.code = htons(D6_OPTION_PD_EXCLUDE);
-                               memcpy(p, &o.code, sizeof(o.code));
-                               p += sizeof(o.code);
-                               o.len = (uint16_t)(o.len + sizeof(o.code));
-                       }
-#endif
-                       o.len = htons(o.len);
-                       memcpy(o_lenp, &o.len, sizeof(o.len));
-               }
        }
 
 #ifdef AUTH
@@ -2631,7 +2653,9 @@ dhcp6_startinit(struct interface *ifp)
                if (r == -1) {
                        if (errno != ENOENT)
                                logerr("%s: %s", __func__, state->leasefile);
-               } else if (r != 0) {
+               } else if (r != 0 &&
+                   !(ifp->options->options & DHCPCD_ANONYMOUS))
+               {
                        /* RFC 3633 section 12.1 */
 #ifndef SMALL
                        if (dhcp6_hasprefixdelegation(ifp))
@@ -3520,10 +3544,18 @@ dhcp6_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg, struct ipv6_addr *ia)
        }
 
        r = (struct dhcp6_message *)msg->msg_iov[0].iov_base;
+
+       uint8_t duid[DUID_LEN], *dp;
+       size_t duid_len;
        o = dhcp6_findmoption(r, len, D6_OPTION_CLIENTID, &ol);
-       if (o == NULL || ol != ctx->duid_len ||
-           memcmp(o, ctx->duid, ol) != 0)
-       {
+       if (ifp->options->options & DHCPCD_ANONYMOUS) {
+               duid_len = duid_make(duid, ifp, DUID_LL);
+               dp = duid;
+       } else {
+               duid_len = ctx->duid_len;
+               dp = ctx->duid;
+       }
+       if (o == NULL || ol != duid_len || memcmp(o, dp, ol) != 0) {
                logdebugx("%s: incorrect client ID from %s",
                    ifp->name, sfrom);
                return;
@@ -3774,12 +3806,11 @@ dhcp6_start1(void *arg)
        }
        if (i == sizeof(ifo->requestmask6)) {
                for (dhc = dhcp_compats; dhc->dhcp_opt; dhc++) {
-                       if (has_option_mask(ifo->requestmask, dhc->dhcp_opt))
+                       if (DHC_REQ(ifo->requestmask, ifo->nomask, dhc->dhcp_opt))
                                add_option_mask(ifo->requestmask6,
                                    dhc->dhcp6_opt);
                }
-               if (ifo->fqdn != FQDN_DISABLE ||
-                   ifo->options & DHCPCD_HOSTNAME)
+               if (ifo->fqdn != FQDN_DISABLE || ifo->options & DHCPCD_HOSTNAME)
                        add_option_mask(ifo->requestmask6, D6_OPTION_FQDN);
        }
 
index 17873d7eb1d130055bb8139c9b3a7fd81d2f6e37..b58ab021c7b450528f9d5255a75d71472c2aa0d7 100644 (file)
@@ -9,16 +9,13 @@ define 1      request ipaddress       subnet_mask
 # RFC3442 states that the CSR has to come before all other routes
 # For completeness we also specify static routes then routers
 define 121     rfc3442                 classless_static_routes
-# Option 249 is an IANA assigned private number used by Windows DHCP servers
-# to provide the exact same information as option 121, classless static routes
-define 249     rfc3442                 ms_classless_static_routes
-define 33      request array ipaddress static_routes
 define 3       request array ipaddress routers
 define 6       array ipaddress         domain_name_servers
 define 12      dname                   host_name
 define 15      array dname             domain_name
 define 26      uint16                  interface_mtu
 define 28      request ipaddress       broadcast_address
+define 33      request array ipaddress static_routes
 define 50      ipaddress               dhcp_requested_address
 define 51      request uint32          dhcp_lease_time
 define 52      byte                    dhcp_option_overload
@@ -49,6 +46,10 @@ embed                optional domain         fqdn
 # DHCP Domain Search, RFC3397
 define 119     array domain            domain_search
 
+# Option 249 is an IANA assigned private number used by Windows DHCP servers
+# to provide the exact same information as option 121, classless static routes
+define 249     rfc3442                 ms_classless_static_routes
+
 ##############################################################################
 # ND6 options, RFC4861
 definend 1     binhex                  source_address
index df4075e8b2e732f15aa56f14416d01060e009624..7f96b5168b4ee301c90a04effb313ebc1e7004cf 100644 (file)
@@ -12,12 +12,8 @@ define 1     request ipaddress       subnet_mask
 # RFC3442 states that the CSR has to come before all other routes
 # For completeness we also specify static routes then routers
 define 121     rfc3442                 classless_static_routes
-# Option 249 is an IANA assigned private number used by Windows DHCP servers
-# to provide the exact same information as option 121, classless static routes
-define 249     rfc3442                 ms_classless_static_routes
-define 33      request array ipaddress static_routes
-define 3       request array ipaddress routers
 define 2       uint32                  time_offset
+define 3       request array ipaddress routers
 define 4       array ipaddress         time_servers
 define 5       array ipaddress         ien116_name_servers
 define 6       array ipaddress         domain_name_servers
@@ -49,6 +45,7 @@ define 29     byte                    perform_mask_discovery
 define 30      byte                    mask_supplier
 define 31      byte                    router_discovery
 define 32      ipaddress               router_solicitation_address
+define 33      request array ipaddress static_routes
 define 34      byte                    trailer_encapsulation
 define 35      uint32                  arp_cache_timeout
 define 36      uint16                  ieee802_3_encapsulation
@@ -311,7 +308,12 @@ encap 255  flag                    global
 # Options 222 and 223 are unused, RFC3942
 
 # Options 224-254 are reserved for Private Use
-# However, an expired RFC for Web Proxy Auto Discovery Protocol does define
+
+# Option 249 is an IANA assigned private number used by Windows DHCP servers
+# to provide the exact same information as option 121, classless static routes
+define 249     rfc3442                 ms_classless_static_routes
+
+# An expired RFC for Web Proxy Auto Discovery Protocol does define
 # Option 252 which is commonly used by major browsers.
 # Apparently the code was assigned by agreement of the DHC working group chair.
 define 252     string                  wpad_url
index 95696e86c577712347a2a479c2f434687b30e21b..9a9978edd1f940a0df7e3e9e4dce511a925e026e 100644 (file)
@@ -24,7 +24,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd January 3, 2020
+.Dd January 15, 2020
 .Dt DHCPCD 8
 .Os
 .Sh NAME
@@ -833,7 +833,7 @@ RFC\ 3004, RFC\ 3118, RFC\ 3203, RFC\ 3315, RFC\ 3361, RFC\ 3633, RFC\ 3396,
 RFC\ 3397, RFC\ 3442, RFC\ 3495, RFC\ 3925, RFC\ 3927, RFC\ 4039, RFC\ 4075,
 RFC\ 4242, RFC\ 4361, RFC\ 4390, RFC\ 4702, RFC\ 4074, RFC\ 4861, RFC\ 4833,
 RFC\ 4941, RFC\ 5227, RFC\ 5942, RFC\ 5969, RFC\ 6106, RFC\ 6334, RFC\ 6355,
-RFC\ 6603, RFC\ 6704, RFC\ 7217, RFC\ 7550.
+RFC\ 6603, RFC\ 6704, RFC\ 7217, RFC\ 7550, RFC\ 7844.
 .Sh AUTHORS
 .An Roy Marples Aq Mt roy@marples.name
 .Sh BUGS
index 85af5494cab17981d0a8eb429af41e89f98e72d2..d15db87e6461e52b9b91ecfbd7513998e7be5b99 100644 (file)
@@ -494,7 +494,9 @@ configure_interface1(struct interface *ifp)
                         * so we don't conflict with an interface index. */
                        vlanid = htonl(ifp->vlanid | 0xff000000);
                        memcpy(ifo->iaid, &vlanid, sizeof(vlanid));
-               } else if (ifp->hwlen >= sizeof(ifo->iaid)) {
+               } else if (ifo->options & DHCPCD_ANONYMOUS)
+                       memset(ifo->iaid, 0, sizeof(ifo->iaid));
+               else if (ifp->hwlen >= sizeof(ifo->iaid)) {
                        memcpy(ifo->iaid,
                            ifp->hwaddr + ifp->hwlen - sizeof(ifo->iaid),
                            sizeof(ifo->iaid));
@@ -700,14 +702,17 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx *ctx, int carrier, unsigned int flags,
                        if (ifp->carrier == LINK_UP)
                                loginfox("%s: carrier lost", ifp->name);
 #ifdef NOCARRIER_PRESERVE_IP
-                       if (ifp->flags & IFF_UP)
+                       if (ifp->flags & IFF_UP &&
+                           !(ifp->options->options & DHCPCD_ANONYMOUS))
                                ifp->carrier = LINK_DOWN_IFFUP;
                        else
 #endif
                                ifp->carrier = LINK_DOWN;
                        script_runreason(ifp, "NOCARRIER");
 #ifdef NOCARRIER_PRESERVE_IP
-                       if (ifp->flags & IFF_UP) {
+                       if (ifp->flags & IFF_UP &&
+                           !(ifp->options->options & DHCPCD_ANONYMOUS))
+                       {
 #ifdef ARP
                                arp_drop(ifp);
 #endif
@@ -720,6 +725,12 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx *ctx, int carrier, unsigned int flags,
                        } else
 #endif
                                dhcpcd_drop(ifp, 0);
+                       if (ifp->options->options & DHCPCD_ANONYMOUS) {
+                               if_down(ifp);
+                               if (if_randomisemac(ifp) == -1 && errno != ENXIO)
+                                       logerr(__func__);
+                               if_up(ifp);
+                       }
                }
        } else if (carrier == LINK_UP && ifp->flags & IFF_UP) {
                if (ifp->carrier != LINK_UP) {
@@ -924,8 +935,14 @@ dhcpcd_prestartinterface(void *arg)
 
        if ((!(ifp->ctx->options & DHCPCD_MASTER) ||
            ifp->options->options & DHCPCD_IF_UP) &&
-           if_up(ifp) == -1)
-               logerr("%s: %s", __func__, ifp->name);
+           ifp->carrier != LINK_UP)
+       {
+               if (ifp->options->options & DHCPCD_ANONYMOUS &&
+                   if_randomisemac(ifp) == -1)
+                       logerr(__func__);
+               if (if_up(ifp) == -1)
+                       logerr(__func__);
+       }
 
        dhcpcd_startinterface(ifp);
 }
@@ -1312,9 +1329,10 @@ dhcpcd_signal_cb(int sig, void *arg)
 
        if (ctx->options & DHCPCD_FORKED) {
                pid_t pid = pidfile_read(ctx->pidfile);
-               if (pid == -1)
-                       logerr("%s: pidfile_read",__func__);
-               else if (pid == 0)
+               if (pid == -1) {
+                       if (errno != ENOENT)
+                               logerr("%s: pidfile_read",__func__);
+               } else if (pid == 0)
                        logerr("%s: pid cannot be zero", __func__);
                else if (kill(pid, sig) == -1)
                        logerr("%s: kill", __func__);
index add12f41cf5b784ef63cbff781c1bd8de178b3c0..8bb71a57f9e71efb19bd98585a5b5b8d9b7128bc 100644 (file)
@@ -24,7 +24,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd January 3, 2020
+.Dd January 15, 2020
 .Dt DHCPCD.CONF 5
 .Os
 .Sh NAME
@@ -59,6 +59,26 @@ When discovering interfaces, the interface name must not match
 .Ar pattern
 which is a space or comma separated list of patterns passed to
 .Xr fnmatch 3 .
+.It Ic anonymous
+Enables Anonymity Profiles for DHCP, RFC 7844.
+This implementation forces a hardware address randomisaton when
+the interface link is down and that ClientID's are only LL.
+Any DUID is ignored.
+All non essential options are then masked at this point,
+but they could be unmasked by explicitly requesting the option
+.Sy after
+the
+.Ic anonymous
+option is processed.
+As such, the
+.Ic anonymous
+option
+.Sy should
+be the last option in the configuration unless you really want to
+send something which could identify you.
+.Nm dhcpcd
+will not try and reboot an old lease, it will go straight into
+DISCOVER/SOLICIT.
 .It Ic arping Ar address Op address
 .Nm dhcpcd
 will arping each address in order before attempting DHCP.
index 8922f62f34ba78b84125bda94a9d625ce8499f58..0d6c6f8f5f67b22017d331fc44075865d97fe939 100644 (file)
@@ -28,9 +28,6 @@
 
 #define        UUID_LEN        36
 #define        DUID_TIME_EPOCH 946684800
-#define        DUID_LLT        1
-#define        DUID_LL         3
-#define        DUID_UUID       4
 
 #include <sys/param.h>
 #include <sys/socket.h>
@@ -118,33 +115,36 @@ duid_make_uuid(uint8_t *d)
        return l;
 }
 
-static size_t
-duid_make(uint8_t *d, const struct interface *ifp, uint16_t type)
+size_t
+duid_make(void *d, const struct interface *ifp, uint16_t type)
 {
        uint8_t *p;
        uint16_t u16;
        time_t t;
        uint32_t u32;
 
+       if (ifp->hwlen == 0)
+               return 0;
+
        p = d;
        u16 = htons(type);
-       memcpy(p, &u16, 2);
-       p += 2;
+       memcpy(p, &u16, sizeof(u16));
+       p += sizeof(u16);
        u16 = htons(ifp->family);
-       memcpy(p, &u16, 2);
-       p += 2;
+       memcpy(p, &u16, sizeof(u16));
+       p += sizeof(u16);
        if (type == DUID_LLT) {
                /* time returns seconds from jan 1 1970, but DUID-LLT is
                 * seconds from jan 1 2000 modulo 2^32 */
                t = time(NULL) - DUID_TIME_EPOCH;
                u32 = htonl((uint32_t)t & 0xffffffff);
-               memcpy(p, &u32, 4);
-               p += 4;
+               memcpy(p, &u32, sizeof(u32));
+               p += sizeof(u32);
        }
        /* Finally, add the MAC address of the interface */
        memcpy(p, ifp->hwaddr, ifp->hwlen);
        p += ifp->hwlen;
-       return (size_t)(p - d);
+       return (size_t)(p - (uint8_t *)d);
 }
 
 #define DUID_STRLEN DUID_LEN * 3
index ad2600bf7472bf9361f1551eae5a1511f03eb3ee..d9d82a61394c916a25f1e57fd517a9c17b99e505 100644 (file)
 #define DUID_H
 
 #define DUID_LEN       128 + 2
+#define        DUID_LLT        1
+#define        DUID_LL         3
+#define        DUID_UUID       4
 
+size_t duid_make(void *, const struct interface *, uint16_t);
 size_t duid_init(const struct interface *);
 
 #endif
index 4d3dce4fc0c49c87dcf477283d471081f65c980c..f44988ac8ccb9624c5ed88d4dbabd949807dc1f2 100644 (file)
@@ -213,6 +213,55 @@ if_closesockets_os(struct dhcpcd_ctx *ctx)
        priv = (struct priv *)ctx->priv;
        if (priv->pf_inet6_fd != -1)
                close(priv->pf_inet6_fd);
+       free(priv);
+       ctx->priv = NULL;
+}
+
+static int
+if_ioctllink(struct dhcpcd_ctx *ctx, unsigned long req, void *data, size_t len)
+{
+       int s;
+       int retval;
+
+#ifdef PRIVSEP
+       if (ctx->options & DHCPCD_PRIVSEP)
+               return (int)ps_root_ioctllink(ctx, req, data, len);
+#else
+       UNUSED(ctx);
+#endif
+
+       s = socket(PF_LINK, SOCK_DGRAM, 0);
+       if (s == -1)
+               return -1;
+       retval = ioctl(s, req, data, len);
+       close(s);
+       return retval;
+}
+
+int
+if_setmac(struct interface *ifp, void *mac, uint8_t maclen)
+{
+       struct if_laddrreq iflr = { .flags = IFLR_ACTIVE };
+       struct sockaddr_dl *sdl = satosdl(&iflr.addr);
+       int retval;
+
+       if (ifp->hwlen != maclen) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       strlcpy(iflr.iflr_name, ifp->name, sizeof(iflr.iflr_name));
+       sdl->sdl_family = AF_LINK;
+       sdl->sdl_len = sizeof(*sdl);
+       sdl->sdl_alen = maclen;
+       memcpy(LLADDR(sdl), mac, maclen);
+       retval = if_ioctllink(ifp->ctx, SIOCALIFADDR, &iflr, sizeof(iflr));
+
+       /* Try and remove the old address */
+       memcpy(LLADDR(sdl), ifp->hwaddr, ifp->hwlen);
+       if_ioctllink(ifp->ctx, SIOCDLIFADDR, &iflr, sizeof(iflr));
+
+       return retval;
 }
 
 static bool
index 74355a85f4c27e602c399117226887c02f440759..628abf24214632ff63abef57f33b9b1f250c1f22 100644 (file)
@@ -66,7 +66,7 @@
 #define O_NOIPV6RS             O_BASE + 5
 #define O_IPV6RA_FORK          O_BASE + 6
 #define O_LINK_RCVBUF          O_BASE + 7
-// unused                      O_BASE + 8
+#define O_ANONYMOUS            O_BASE + 8
 #define O_NOALIAS              O_BASE + 9
 #define O_IA_NA                        O_BASE + 10
 #define O_IA_TA                        O_BASE + 11
@@ -161,6 +161,7 @@ const struct option cf_options[] = {
        {"oneshot",         no_argument,       NULL, '1'},
        {"ipv4only",        no_argument,       NULL, '4'},
        {"ipv6only",        no_argument,       NULL, '6'},
+       {"anonymous",       no_argument,       NULL, O_ANONYMOUS},
        {"arping",          required_argument, NULL, O_ARPING},
        {"destination",     required_argument, NULL, O_DESTINATION},
        {"fallback",        required_argument, NULL, O_FALLBACK},
@@ -1238,6 +1239,33 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
                break;
        case O_NOIPV6:
                ifo->options &= ~DHCPCD_IPV6;
+               break;
+       case O_ANONYMOUS:
+               ifo->options |= DHCPCD_ANONYMOUS;
+               ifo->options &= ~DHCPCD_HOSTNAME;
+               ifo->fqdn = FQDN_DISABLE;
+
+               /* Block everything */
+               memset(ifo->nomask, 0xff, sizeof(ifo->nomask));
+               memset(ifo->nomask6, 0xff, sizeof(ifo->nomask6));
+
+               /* Allow the bare minimum through */
+               del_option_mask(ifo->nomask, DHO_SUBNETMASK);
+               del_option_mask(ifo->nomask, DHO_CSR);
+               del_option_mask(ifo->nomask, DHO_ROUTER);
+               del_option_mask(ifo->nomask, DHO_DNSSERVER);
+               del_option_mask(ifo->nomask, DHO_BROADCAST);
+               del_option_mask(ifo->nomask, DHO_STATICROUTE);
+               del_option_mask(ifo->nomask, DHO_SERVERID);
+               del_option_mask(ifo->nomask, DHO_RENEWALTIME);
+               del_option_mask(ifo->nomask, DHO_REBINDTIME);
+               del_option_mask(ifo->nomask, DHO_DNSSEARCH);
+
+               del_option_mask(ifo->nomask6, D6_OPTION_DNS_SERVERS);
+               del_option_mask(ifo->nomask6, D6_OPTION_DOMAIN_LIST);
+               del_option_mask(ifo->nomask6, D6_OPTION_SOL_MAX_RT);
+               del_option_mask(ifo->nomask6, D6_OPTION_INF_MAX_RT);
+
                break;
 #ifdef INET
        case O_ARPING:
index bfe9aa6443043bfee1c684ea33a48359b70b4458..9c3c0f570ea169b5d832a8296b651899eed79c06 100644 (file)
@@ -78,7 +78,7 @@
 #define DHCPCD_HOSTNAME                        (1ULL << 18)
 #define DHCPCD_CLIENTID                        (1ULL << 19)
 #define DHCPCD_LINK                    (1ULL << 20)
-// unused                              (1ULL << 21)
+#define DHCPCD_ANONYMOUS               (1ULL << 21)
 #define DHCPCD_BACKGROUND              (1ULL << 22)
 #define DHCPCD_VENDORRAW               (1ULL << 23)
 #define DHCPCD_NOWAITIP                        (1ULL << 24) /* To force daemonise */
index a96ac5c192a947edf6f5d4d8dbe2aa9f2796657a..ff1a88bbcc47e649493e5cb7207b4e8954efb1dd 100644 (file)
--- a/src/if.c
+++ b/src/if.c
@@ -156,7 +156,7 @@ if_getflags(struct interface *ifp)
 }
 
 int
-if_setflag(struct interface *ifp, short flag)
+if_setflag(struct interface *ifp, short setflag, short unsetflag)
 {
        struct ifreq ifr = { .ifr_flags = 0 };
        short f;
@@ -165,11 +165,12 @@ if_setflag(struct interface *ifp, short flag)
                return -1;
 
        f = (short)ifp->flags;
-       if ((f & flag) == flag)
+       if ((f & setflag) == setflag && (f & unsetflag) == 0)
                return 0;
 
        strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
-       ifr.ifr_flags = f | flag;
+       ifr.ifr_flags |= setflag;
+       ifr.ifr_flags &= (short)~unsetflag;
        if (if_ioctl(ifp->ctx, SIOCSIFFLAGS, &ifr, sizeof(ifr)) == -1)
                return -1;
 
@@ -177,6 +178,46 @@ if_setflag(struct interface *ifp, short flag)
        return 0;
 }
 
+int
+if_randomisemac(struct interface *ifp)
+{
+       uint32_t randnum;
+       size_t hwlen = ifp->hwlen, rlen = 0;
+       uint8_t buf[hwlen], *bp = buf, *rp = (uint8_t *)&randnum;
+       char sbuf[hwlen * 3];
+       int retval;
+
+       if (hwlen == 0) {
+               errno = ENOTSUP;
+               return -1;
+       }
+
+       for (; hwlen != 0; hwlen--) {
+               if (rlen == 0) {
+                       randnum = arc4random();
+                       rp = (uint8_t *)&randnum;
+                       rlen = sizeof(randnum);
+               }
+               if (bp == buf) {
+                       /* First octet is special. We need to preserve
+                        * bit 8 (unicast/multicast) and set
+                        * bit 7 (locally administered address) */
+                       *bp = *rp++ & 0xFC;
+                       *bp++ |= 2;
+               } else
+                       *bp++ = *rp++;
+               rlen--;
+       }
+
+       logdebugx("%s: hardware address randomised to %s",
+           ifp->name,
+           hwaddr_ntoa(buf, sizeof(buf), sbuf, sizeof(sbuf)));
+       retval = if_setmac(ifp, buf, ifp->hwlen);
+       if (retval == 0)
+               memcpy(ifp->hwaddr, buf, sizeof(ifp->hwaddr));
+       return retval;
+}
+
 static int
 if_hasconf(struct dhcpcd_ctx *ctx, const char *ifname)
 {
index e371e970e48321905a406c0cb81a6c280ba87ebc..2f147f1da8b2a80d53353e596e2acfbf15745a3a 100644 (file)
--- a/src/if.h
+++ b/src/if.h
@@ -121,9 +121,10 @@ int if_getsubnet(struct dhcpcd_ctx *, const char *, int, void *, size_t);
 #endif
 
 int if_ioctl(struct dhcpcd_ctx *, ioctl_request_t, void *, size_t);
-int if_getflags(struct interface *ifp);
-int if_setflag(struct interface *ifp, short flag);
-#define if_up(ifp) if_setflag((ifp), (IFF_UP | IFF_RUNNING))
+int if_getflags(struct interface *);
+int if_setflag(struct interface *, short, short);
+#define if_up(ifp) if_setflag((ifp), (IFF_UP | IFF_RUNNING), 0)
+#define if_down(ifp) if_setflag((ifp), 0, IFF_UP);
 bool if_valid_hwaddr(const uint8_t *, size_t);
 struct if_head *if_discover(struct dhcpcd_ctx *, struct ifaddrs **,
     int, char * const *);
@@ -171,6 +172,8 @@ int if_opensockets_os(struct dhcpcd_ctx *);
 void if_closesockets(struct dhcpcd_ctx *);
 void if_closesockets_os(struct dhcpcd_ctx *);
 int if_handlelink(struct dhcpcd_ctx *);
+int if_randomisemac(struct interface *);
+int if_setmac(struct interface *ifp, void *, uint8_t);
 
 /* dhcpcd uses the same routing flags as BSD.
  * If the platform doesn't use these flags,
index d07d0e0733b7e954fd2f1e671b5ed4461bd90021..08093f97178703d2dac7f30a156a3954bb5b0462 100644 (file)
 #include "privsep.h"
 
 static ssize_t
-ps_root_doioctl6(unsigned long req, void *data, size_t len)
+ps_root_doioctldom(int domain, unsigned long req, void *data, size_t len)
 {
        int s, err;
 
-       s = socket(PF_INET6, SOCK_DGRAM, 0);
+       s = socket(domain, SOCK_DGRAM, 0);
        if (s != -1)
                err = ioctl(s, req, data, len);
        else
@@ -74,8 +74,10 @@ ps_root_os(struct ps_msghdr *psm, struct msghdr *msg)
        size_t len = iov->iov_len;
 
        switch (psm->ps_cmd) {
+       case PS_IOCTLLINK:
+               return ps_root_doioctldom(PF_LINK, psm->ps_flags, data, len);
        case PS_IOCTL6:
-               return ps_root_doioctl6(psm->ps_flags, data, len);
+               return ps_root_doioctldom(PF_INET6, psm->ps_flags, data, len);
        case PS_ROUTE:
                return ps_root_doroute(data, len);
        default:
@@ -84,16 +86,31 @@ ps_root_os(struct ps_msghdr *psm, struct msghdr *msg)
        }
 }
 
-ssize_t
-ps_root_ioctl6(struct dhcpcd_ctx *ctx, unsigned long request, void *data, size_t len)
+static ssize_t
+ps_root_ioctldom(struct dhcpcd_ctx *ctx, uint8_t domain, unsigned long request,
+    void *data, size_t len)
 {
 
-       if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IOCTL6,
+       if (ps_sendcmd(ctx, ctx->ps_root_fd, domain,
            request, data, len) == -1)
                return -1;
        return ps_root_readerror(ctx);
 }
 
+ssize_t
+ps_root_ioctllink(struct dhcpcd_ctx *ctx, unsigned long request, void *data, size_t len)
+{
+
+       return ps_root_ioctldom(ctx, PS_IOCTLLINK, request, data, len);
+}
+
+ssize_t
+ps_root_ioctl6(struct dhcpcd_ctx *ctx, unsigned long request, void *data, size_t len)
+{
+
+       return ps_root_ioctldom(ctx, PS_IOCTL6, request, data, len);
+}
+
 ssize_t
 ps_root_route(struct dhcpcd_ctx *ctx, void *data, size_t len)
 {
index 57862626ff9286bc82fd3484c4dd01ce9d3b3545..5ad19c96ed6de6d84a0910433500638b5e5f93b9 100644 (file)
@@ -39,6 +39,7 @@ ssize_t ps_root_ioctl(struct dhcpcd_ctx *, ioctl_request_t, void *, size_t);
 ssize_t ps_root_os(struct ps_msghdr *, struct msghdr *);
 #if defined(BSD) || defined(__sun)
 ssize_t ps_root_route(struct dhcpcd_ctx *, void *, size_t);
+ssize_t ps_root_ioctllink(struct dhcpcd_ctx *, unsigned long, void *, size_t);
 ssize_t ps_root_ioctl6(struct dhcpcd_ctx *, unsigned long, void *, size_t);
 #endif
 #ifdef __linux__
index 2f63038a818bfb96ed4609bfbdd10abd13b85469..d277b22ff33a86529c8d9e95ae590fb8e9d6239c 100644 (file)
 
 #define        PS_IOCTL                0x10
 #define        PS_SCRIPT               0x11
-#define        PS_IOCTL6               0x12
-#define        PS_ROUTE                0x13    /* Also used for NETLINK */
-#define        PS_WRITEPATHUINT        0x14
+#define        PS_IOCTLLINK            0x12
+#define        PS_IOCTL6               0x13
+#define        PS_ROUTE                0x14    /* Also used for NETLINK */
+#define        PS_WRITEPATHUINT        0x15
 
 #define        PS_DELETE               0x20
 #define        PS_START                0x40