diff --git a/includes/site.h b/includes/site.h --- a/includes/site.h +++ b/includes/site.h @@ -329,7 +329,7 @@ * for IA_NA pools, if the parameter use-eui-64 is true for the * pool. Can be at all scopes down to the pool level. Not * supported by the configure script. */ -/* #define EUI_64 */ +#define EUI_64 /* Enable enforcement of the require option statement as documented * in man page. Instructs the dhclient, when in -6 mode, to discard diff --git a/server/mdb6.c b/server/mdb6.c --- a/server/mdb6.c +++ b/server/mdb6.c @@ -859,18 +859,32 @@ build_address6(struct in6_addr *addr, #ifdef EUI_64 int valid_eui_64_duid(const struct data_string* uid, int offset) { + /* actual EUI-64, which dhclient does not actually use, at least by default */ + const unsigned char* duid = uid->data + offset; if (uid->len == (offset + EUI_64_ID_LEN)) { - const unsigned char* duid = uid->data + offset; return (((duid[0] == 0x00 && duid[1] == 0x03) && (duid[2] == 0x00 && duid[3] == 0x1b))); } - + /* add a hack to handle LL and LLT like they are EUI-64 */ + if (uid->len == (offset + 4 + 6)) { + return (((duid[0] == 0x00 && duid[1] == 0x03) && + (duid[2] == 0x00 && duid[3] == 0x01))); + } + /* this is the LLT format, we discard the time part and consider only the mac address */ + if (uid->len == (offset + 4 + 4 + 6)) { + return (((duid[0] == 0x00 && duid[1] == 0x01) && + (duid[2] == 0x00 && duid[3] == 0x01))); + } return(0); } /* - * Create an EUI-64 address + * Create an IPv6 address from EUI-64 address, or MAC (like EUI-48) address + * also treat LL and LLT DUID like this + * 0x1b = EUI-64 whereas 01 = MAC address + * https://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml#arp-parameters-2 + * dhclient -6 -D LLT -d eth0 */ static isc_result_t build_address6_eui_64(struct in6_addr *addr, @@ -884,19 +898,38 @@ build_address6_eui_64(struct in6_addr *addr, if (valid_eui_64_duid(iaid_duid, duid_beg)) { const unsigned char *duid = iaid_duid->data + duid_beg; - /* copy network prefix to the high 64 bits */ memcpy(addr->s6_addr, net_start_addr->s6_addr, 8); - /* copy Link-layer address to low 64 bits */ - memcpy(addr->s6_addr + 8, duid + 4, 8); + if (duid[3] == 0x1b) { + /* copy Link-layer address to low 64 bits */ + memcpy(addr->s6_addr + 8, duid + 4, 8); + } + if (duid[3] == 0x01) { + if (duid[1] == 0x03) { + /* copy OUI part of mac address */ + memcpy(addr->s6_addr + 8, duid + 4, 3); + + /* copy vendor part of mac address */ + memcpy(addr->s6_addr + 8 + 3 + 2, duid + 7, 3); + } + if (duid[1] == 0x01) { + /* copy OUI part of mac address */ + memcpy(addr->s6_addr + 8, duid + 4 + 4, 3); + + /* copy vendor part of mac address */ + memcpy(addr->s6_addr + 8 + 3 + 2, duid + 4 + 7, 3); + } + addr->s6_addr[11] = 0xff; + addr->s6_addr[12] = 0xfe; + } /* RFC-3315 Any address assigned by a server that is based * on an EUI-64 identifier MUST include an interface identifier * with the "u" (universal/local) and "g" (individual/group) * bits of the interface identifier set appropriately, as * indicated in section 2.5.1 of RFC 2373 [5]. */ - addr->s6_addr[8] |= 0x02; + addr->s6_addr[8] ^= 0x02; return (ISC_R_SUCCESS); } -- 2.30.2