interface-ip: harden eui64 IPv6 prefix address generation
authorHans Dedecker <dedeckeh@gmail.com>
Thu, 14 Dec 2017 13:13:35 +0000 (14:13 +0100)
committerHans Dedecker <dedeckeh@gmail.com>
Fri, 15 Dec 2017 16:21:12 +0000 (17:21 +0100)
Check if a mac address is actually present when generating an eui64 based
IPv6 address; in case of failure bail out.
At the same time make sure the active mac address is used as input for the
eui64 based IPv6 address and guarantee IPv6 prefix address generation is
based on the actual config by resetting the IPv6 prefix address in the
assignment structure when it gets deleted.

Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
device.c
device.h
interface-ip.c

index 0424658a21bfdd1c63dab33b674684078883f55f..a851037f16415442cf4853d2f18914abf91e52ca 100644 (file)
--- a/device.c
+++ b/device.c
@@ -193,7 +193,7 @@ struct device_type simple_device_type = {
        .free = simple_device_free,
 };
 
        .free = simple_device_free,
 };
 
-static void
+void
 device_merge_settings(struct device *dev, struct device_settings *n)
 {
        struct device_settings *os = &dev->orig_settings;
 device_merge_settings(struct device *dev, struct device_settings *n)
 {
        struct device_settings *os = &dev->orig_settings;
index f398dbc5c5ad2251b9328357611fae725171bf44..07f1dbd71a0e2c15935046b30ee0982efb303238 100644 (file)
--- a/device.h
+++ b/device.h
@@ -244,6 +244,7 @@ int device_type_add(struct device_type *devtype);
 struct device_type *device_type_get(const char *tname);
 struct device *device_create(const char *name, struct device_type *type,
                             struct blob_attr *config);
 struct device_type *device_type_get(const char *tname);
 struct device *device_create(const char *name, struct device_type *type,
                             struct blob_attr *config);
+void device_merge_settings(struct device *dev, struct device_settings *n);
 void device_init_settings(struct device *dev, struct blob_attr **tb);
 void device_init_pending(void);
 
 void device_init_settings(struct device *dev, struct blob_attr **tb);
 void device_init_pending(void);
 
index 716a093e80a58afd753e80ed429b8ac3931d0d0e..dcf3390ec153127687078f86130dcf8f4187a2a6 100644 (file)
@@ -712,9 +712,16 @@ random_ifaceid(struct in6_addr *addr)
        addr->s6_addr32[3] = (uint32_t)mrand48();
 }
 
        addr->s6_addr32[3] = (uint32_t)mrand48();
 }
 
-static void
+static bool
 eui64_ifaceid(struct interface *iface, struct in6_addr *addr)
 {
 eui64_ifaceid(struct interface *iface, struct in6_addr *addr)
 {
+       struct device_settings st;
+
+       device_merge_settings(iface->l3_dev.dev, &st);
+
+       if (!(st.flags & DEV_OPT_MACADDR))
+               return false;
+
        /* get mac address */
        uint8_t *macaddr = iface->l3_dev.dev->settings.macaddr;
        uint8_t *ifaceid = addr->s6_addr + 8;
        /* get mac address */
        uint8_t *macaddr = iface->l3_dev.dev->settings.macaddr;
        uint8_t *ifaceid = addr->s6_addr + 8;
@@ -723,11 +730,15 @@ eui64_ifaceid(struct interface *iface, struct in6_addr *addr)
        ifaceid[3] = 0xff;
        ifaceid[4] = 0xfe;
        ifaceid[0] ^= 0x02;
        ifaceid[3] = 0xff;
        ifaceid[4] = 0xfe;
        ifaceid[0] ^= 0x02;
+
+       return true;
 }
 
 }
 
-static void
+static bool
 generate_ifaceid(struct interface *iface, struct in6_addr *addr)
 {
 generate_ifaceid(struct interface *iface, struct in6_addr *addr)
 {
+       bool ret = true;
+
        /* generate new iface id */
        switch (iface->assignment_iface_id_selection) {
        case IFID_FIXED:
        /* generate new iface id */
        switch (iface->assignment_iface_id_selection) {
        case IFID_FIXED:
@@ -741,9 +752,13 @@ generate_ifaceid(struct interface *iface, struct in6_addr *addr)
                break;
        case IFID_EUI64:
                /* eui64 */
                break;
        case IFID_EUI64:
                /* eui64 */
-               eui64_ifaceid(iface, addr);
+               ret = eui64_ifaceid(iface, addr);
+               break;
+       default:
+               ret = false;
                break;
        }
                break;
        }
+       return ret;
 }
 
 static void
 }
 
 static void
@@ -797,12 +812,15 @@ interface_set_prefix_address(struct device_prefix_assignment *assignment,
                system_del_route(l3_downlink, &route);
                system_add_address(l3_downlink, &addr);
 
                system_del_route(l3_downlink, &route);
                system_add_address(l3_downlink, &addr);
 
+               assignment->addr = in6addr_any;
                assignment->enabled = false;
        } else if (add && (iface->state == IFS_UP || iface->state == IFS_SETUP)) {
                if (IN6_IS_ADDR_UNSPECIFIED(&addr.addr.in6)) {
                        addr.addr.in6 = prefix->addr;
                        addr.addr.in6.s6_addr32[1] |= htonl(assignment->assigned);
                assignment->enabled = false;
        } else if (add && (iface->state == IFS_UP || iface->state == IFS_SETUP)) {
                if (IN6_IS_ADDR_UNSPECIFIED(&addr.addr.in6)) {
                        addr.addr.in6 = prefix->addr;
                        addr.addr.in6.s6_addr32[1] |= htonl(assignment->assigned);
-                       generate_ifaceid(iface, &addr.addr.in6);
+                       if (!generate_ifaceid(iface, &addr.addr.in6))
+                               return;
+
                        assignment->addr = addr.addr.in6;
                        route.addr = addr.addr;
                }
                        assignment->addr = addr.addr.in6;
                        route.addr = addr.addr;
                }