From: Roy Marples Date: Wed, 15 Jan 2020 14:28:24 +0000 (+0000) Subject: Implement Anonymity Profiles for DHCP Clients, RFC 7844 X-Git-Tag: v9.0.0~121 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=68f04fa827830e894559ba42461d86e0d8bd7b47;p=thirdparty%2Fdhcpcd.git Implement Anonymity Profiles for DHCP Clients, RFC 7844 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. --- diff --git a/src/dhcp-common.h b/src/dhcp-common.h index 558a5705..ed020b13 100644 --- a/src/dhcp-common.h +++ b/src/dhcp-common.h @@ -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)) && \ diff --git a/src/dhcp.c b/src/dhcp.c index 2a1fbc27..54de9f72 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -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); diff --git a/src/dhcp6.c b/src/dhcp6.c index c1667303..901bda61 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -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); } diff --git a/src/dhcpcd-definitions-small.conf b/src/dhcpcd-definitions-small.conf index 17873d7e..b58ab021 100644 --- a/src/dhcpcd-definitions-small.conf +++ b/src/dhcpcd-definitions-small.conf @@ -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 diff --git a/src/dhcpcd-definitions.conf b/src/dhcpcd-definitions.conf index df4075e8..7f96b516 100644 --- a/src/dhcpcd-definitions.conf +++ b/src/dhcpcd-definitions.conf @@ -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 diff --git a/src/dhcpcd.8.in b/src/dhcpcd.8.in index 95696e86..9a9978ed 100644 --- a/src/dhcpcd.8.in +++ b/src/dhcpcd.8.in @@ -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 diff --git a/src/dhcpcd.c b/src/dhcpcd.c index 85af5494..d15db87e 100644 --- a/src/dhcpcd.c +++ b/src/dhcpcd.c @@ -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__); diff --git a/src/dhcpcd.conf.5.in b/src/dhcpcd.conf.5.in index add12f41..8bb71a57 100644 --- a/src/dhcpcd.conf.5.in +++ b/src/dhcpcd.conf.5.in @@ -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. diff --git a/src/duid.c b/src/duid.c index 8922f62f..0d6c6f8f 100644 --- a/src/duid.c +++ b/src/duid.c @@ -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 #include @@ -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 diff --git a/src/duid.h b/src/duid.h index ad2600bf..d9d82a61 100644 --- a/src/duid.h +++ b/src/duid.h @@ -30,7 +30,11 @@ #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 diff --git a/src/if-bsd.c b/src/if-bsd.c index 4d3dce4f..f44988ac 100644 --- a/src/if-bsd.c +++ b/src/if-bsd.c @@ -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 diff --git a/src/if-options.c b/src/if-options.c index 74355a85..628abf24 100644 --- a/src/if-options.c +++ b/src/if-options.c @@ -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: diff --git a/src/if-options.h b/src/if-options.h index bfe9aa64..9c3c0f57 100644 --- a/src/if-options.h +++ b/src/if-options.h @@ -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 */ diff --git a/src/if.c b/src/if.c index a96ac5c1..ff1a88bb 100644 --- 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) { diff --git a/src/if.h b/src/if.h index e371e970..2f147f1d 100644 --- 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, diff --git a/src/privsep-bsd.c b/src/privsep-bsd.c index d07d0e07..08093f97 100644 --- a/src/privsep-bsd.c +++ b/src/privsep-bsd.c @@ -36,11 +36,11 @@ #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) { diff --git a/src/privsep-root.h b/src/privsep-root.h index 57862626..5ad19c96 100644 --- a/src/privsep-root.h +++ b/src/privsep-root.h @@ -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__ diff --git a/src/privsep.h b/src/privsep.h index 2f63038a..d277b22f 100644 --- a/src/privsep.h +++ b/src/privsep.h @@ -44,9 +44,10 @@ #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