]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Hardware Address validation
authorRoy Marples <roy@marples.name>
Sat, 20 May 2017 12:51:41 +0000 (13:51 +0100)
committerRoy Marples <roy@marples.name>
Mon, 22 May 2017 08:50:21 +0000 (09:50 +0100)
Summary:
The all zero's and all one's hardware address are reserved.
As such, they should not be used in dhcpcd.
Likewise, Router Solicitation messages should not contain an
all zero source address option.

Fixes T119.

Test Plan:
Request IPv6RA over a PPP interface on a suitable OS which assigns
an all zero's or all one's hardware address.

Maniphest Tasks: T119

Differential Revision: https://dev.marples.name/D114

src/dhcpcd.c
src/if.c
src/if.h
src/ipv6nd.c

index 91c339483b6c2402845e4940a2d20b22817104d6..9c99cb76a0d91fd605ec29a47decedfd43ee61c3 100644 (file)
@@ -1074,6 +1074,9 @@ dhcpcd_handlehwaddr(struct dhcpcd_ctx *ctx, const char *ifname,
        if (ifp == NULL)
                return;
 
+       if (!if_valid_hwaddr(hwaddr, hwlen))
+               hwlen = 0;
+
        if (hwlen > sizeof(ifp->hwaddr)) {
                errno = ENOBUFS;
                logerr("%s: %s", __func__, ifp->name);
index bcf14f2dee55e6ece2af47ef5d228887c735a2f8..2ae5079359c06b07c5a423de1cc70a4e7e0ce10c 100644 (file)
--- a/src/if.c
+++ b/src/if.c
@@ -264,6 +264,24 @@ static void if_learnaddrs(struct dhcpcd_ctx *ctx, struct if_head *ifs,
        }
 }
 
+bool
+if_valid_hwaddr(const uint8_t *hwaddr, size_t hwlen)
+{
+       size_t i;
+       bool all_zeros, all_ones;
+
+       all_zeros = all_ones = true;
+       for (i = 0; i < hwlen; i++) {
+               if (hwaddr[i] != 0x00)
+                       all_zeros = false;
+               if (hwaddr[i] != 0xff)
+                       all_ones = false;
+               if (!all_zeros && !all_ones)
+                       return true;
+       }
+       return false;
+}
+
 struct if_head *
 if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
 {
@@ -469,6 +487,10 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
                        ifp->index = if_nametoindex(ifp->name);
 #endif
 
+               /* Ensure hardware address is valid. */
+               if (!if_valid_hwaddr(ifp->hwaddr, ifp->hwlen))
+                       ifp->hwlen = 0;
+
                /* We only work on ethernet by default */
                if (ifp->family != ARPHRD_ETHER) {
                        if ((argc == 0 || argc == -1) &&
index fd5f3101c297078799fde83ddb941966ce7d1840..b3544f5bda29f3b416ab0e0fbb9ea3dbb8b13cf0 100644 (file)
--- a/src/if.h
+++ b/src/if.h
@@ -111,6 +111,7 @@ int if_getifaddrs(struct ifaddrs **);
 
 int if_setflag(struct interface *ifp, short flag);
 #define if_up(ifp) if_setflag((ifp), (IFF_UP | IFF_RUNNING))
+bool if_valid_hwaddr(const uint8_t *, size_t);
 struct if_head *if_discover(struct dhcpcd_ctx *, int, char * const *);
 struct interface *if_find(struct if_head *, const char *);
 struct interface *if_findindex(struct if_head *, unsigned int);
index dbae9b79c266aa4ea2d10a6466904391a4015d0f..5c9384fe0c4dfc893561d46b3811a91834811d3a 100644 (file)
@@ -237,11 +237,12 @@ ipv6nd_makersprobe(struct interface *ifp)
 {
        struct rs_state *state;
        struct nd_router_solicit *rs;
-       struct nd_opt_hdr *nd;
 
        state = RS_STATE(ifp);
        free(state->rs);
-       state->rslen = sizeof(*rs) + (size_t)ROUNDUP8(ifp->hwlen + 2);
+       state->rslen = sizeof(*rs);
+       if (ifp->hwlen != 0)
+               state->rslen += (size_t)ROUNDUP8(ifp->hwlen + 2);
        state->rs = calloc(1, state->rslen);
        if (state->rs == NULL)
                return -1;
@@ -250,10 +251,15 @@ ipv6nd_makersprobe(struct interface *ifp)
        rs->nd_rs_code = 0;
        rs->nd_rs_cksum = 0;
        rs->nd_rs_reserved = 0;
-       nd = (struct nd_opt_hdr *)(state->rs + sizeof(*rs));
-       nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
-       nd->nd_opt_len = (uint8_t)((ROUNDUP8(ifp->hwlen + 2)) >> 3);
-       memcpy(nd + 1, ifp->hwaddr, ifp->hwlen);
+
+       if (ifp->hwlen != 0) {
+               struct nd_opt_hdr *nd;
+
+               nd = (struct nd_opt_hdr *)(state->rs + sizeof(*rs));
+               nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
+               nd->nd_opt_len = (uint8_t)((ROUNDUP8(ifp->hwlen + 2)) >> 3);
+               memcpy(nd + 1, ifp->hwaddr, ifp->hwlen);
+       }
        return 0;
 }