diff -rNu dhcp-4.3.1.orig/client/dhc6.c dhcp-4.3.1/client/dhc6.c --- dhcp-4.3.1.orig/client/dhc6.c 2014-08-07 00:35:01.000000000 +0200 +++ dhcp-4.3.1/client/dhc6.c 2014-11-20 14:55:01.953953895 +0100 @@ -4902,7 +4902,8 @@ */ if ((oc = lookup_option(&dhcpv6_universe, *op, D6O_CLIENTID)) == NULL) { - if (!option_cache(&oc, &default_duid, NULL, clientid_option, + if (default_duid.len == 0 || + !option_cache(&oc, &default_duid, NULL, clientid_option, MDL)) log_fatal("Failure assembling a DUID."); diff -rNu dhcp-4.3.1.orig/client/dhclient.c dhcp-4.3.1/client/dhclient.c --- dhcp-4.3.1.orig/client/dhclient.c 2014-08-07 00:35:01.000000000 +0200 +++ dhcp-4.3.1/client/dhclient.c 2014-11-20 14:53:15.843412985 +0100 @@ -602,8 +602,8 @@ if (default_duid.buffer != NULL) data_string_forget(&default_duid, MDL); - form_duid(&default_duid, MDL); - write_duid(&default_duid); + if (form_duid(&default_duid, MDL) == ISC_R_SUCCESS) + write_duid(&default_duid); } } @@ -2901,19 +2901,55 @@ * is not how it is intended. Upcoming rearchitecting the client should * address this "one daemon model." */ -void +isc_result_t form_duid(struct data_string *duid, const char *file, int line) { struct interface_info *ip; int len; char *str; + int fd; + int flag; /* For now, just use the first interface on the list. */ ip = interfaces; + flag = 0; if (ip == NULL) log_fatal("Impossible condition at %s:%d.", MDL); + while (ip && ip->hw_address.hbuf[0] == HTYPE_RESERVED) { + fd = open("/dev/urandom", O_RDONLY); + if (fd != -1) { + if(read(fd, ip->hw_address.hbuf + 1, 6) == 6) { + ip->hw_address.hbuf[0] = HTYPE_ETHER; + ip->hw_address.hlen = 7; + close(fd); + flag = 1; + break; + } + close(fd); + } + if (!ip->hw_address.hlen && ip->v6address_count) { + ip->hw_address.hbuf[0] = HTYPE_ETHER; + ip->hw_address.hlen = 7; + memcpy(ip->hw_address.hbuf + 1, + ip->v6addresses[0].s6_addr, 6); + for(len = 0 ; len < 10 ; len ++) { + fd = len % 6; + ip->hw_address.hbuf[fd + 1] ^= + ip->v6addresses[0].s6_addr[len + 6]; + } + flag = 1; + break; + } + /* Try the other interfaces */ + log_debug("Cannot form default DUID from interface %s.", ip->name); + ip = ip->next; + } + if (ip == NULL) { + return ISC_R_UNEXPECTED; + } + if ((ip->hw_address.hlen == 0) || (ip->hw_address.hlen > sizeof(ip->hw_address.hbuf))) log_fatal("Impossible hardware address length at %s:%d.", MDL); @@ -2950,6 +2986,9 @@ ip->hw_address.hlen - 1); } + if (flag) + memset(ip->hw_address.hbuf, 0, 7); + str = quotify_buf(duid->data, duid->len, MDL); if (str == NULL) log_info("Created duid."); @@ -2957,6 +2996,8 @@ log_info("Created duid %s.", str); dfree(str, MDL); } + + return ISC_R_SUCCESS; } /* Write the default DUID to the lease store. */ diff -rNu dhcp-4.3.1.orig/common/bpf.c dhcp-4.3.1/common/bpf.c --- dhcp-4.3.1.orig/common/bpf.c 2014-08-07 00:35:02.000000000 +0200 +++ dhcp-4.3.1/common/bpf.c 2014-11-20 14:58:27.560875234 +0100 @@ -600,6 +600,22 @@ memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen); break; #endif /* IFT_FDDI */ +#if defined(IFT_PPP) + case IFT_PPP: + if (local_family != AF_INET6) + log_fatal("Unsupported device type %d for \"%s\"", + sa->sdl_type, name); + hw->hlen = 0; + hw->hbuf[0] = HTYPE_RESERVED; + /* 0xdeadbeef should never occur on the wire, and is a signature that + * something went wrong. + */ + hw->hbuf[1] = 0xde; + hw->hbuf[2] = 0xad; + hw->hbuf[3] = 0xbe; + hw->hbuf[4] = 0xef; + break; +#endif default: log_fatal("Unsupported device type %d for \"%s\"", sa->sdl_type, name); diff -rNu dhcp-4.3.1.orig/common/lpf.c dhcp-4.3.1/common/lpf.c --- dhcp-4.3.1.orig/common/lpf.c 2014-08-07 00:35:02.000000000 +0200 +++ dhcp-4.3.1/common/lpf.c 2014-11-20 15:01:04.969723942 +0100 @@ -468,6 +468,22 @@ hw->hbuf[0] = HTYPE_FDDI; memcpy(&hw->hbuf[1], sa->sa_data, 6); break; +#if defined(ARPHRD_PPP) + case ARPHRD_PPP: + if (local_family != AF_INET6) + log_fatal("Unsupported device type %d for \"%s\"", + sa->sa_family, name); + hw->hlen = 0; + hw->hbuf[0] = HTYPE_RESERVED; + /* 0xdeadbeef should never occur on the wire, and is a signature that + * something went wrong. + */ + hw->hbuf[1] = 0xde; + hw->hbuf[2] = 0xad; + hw->hbuf[3] = 0xbe; + hw->hbuf[4] = 0xef; + break; +#endif default: log_fatal("Unsupported device type %ld for \"%s\"", (long int)sa->sa_family, name); diff -rNu dhcp-4.3.1.orig/includes/dhcp.h dhcp-4.3.1/includes/dhcp.h --- dhcp-4.3.1.orig/includes/dhcp.h 2014-06-20 22:10:34.000000000 +0200 +++ dhcp-4.3.1/includes/dhcp.h 2014-11-20 15:02:03.208001594 +0100 @@ -81,6 +81,8 @@ * is no standard for this so we * just steal a type */ +#define HTYPE_RESERVED 0 /* RFC 5494 */ + /* Magic cookie validating dhcp options field (and bootp vendor extensions field). */ #define DHCP_OPTIONS_COOKIE "\143\202\123\143" diff -rNu dhcp-4.3.1.orig/includes/dhcpd.h dhcp-4.3.1/includes/dhcpd.h --- dhcp-4.3.1.orig/includes/dhcpd.h 2014-08-07 00:35:02.000000000 +0200 +++ dhcp-4.3.1/includes/dhcpd.h 2014-11-20 14:55:27.642075489 +0100 @@ -2834,7 +2834,7 @@ void dhcpv4_client_assignments(void); void dhcpv6_client_assignments(void); -void form_duid(struct data_string *duid, const char *file, int line); +isc_result_t form_duid(struct data_string *duid, const char *file, int line); /* dhc6.c */ void dhc6_lease_destroy(struct dhc6_lease **src, const char *file, int line); diff -rNu dhcp-4.3.1.orig/server/dhcpv6.c dhcp-4.3.1/server/dhcpv6.c --- dhcp-4.3.1.orig/server/dhcpv6.c 2014-08-07 00:35:03.000000000 +0200 +++ dhcp-4.3.1/server/dhcpv6.c 2014-11-20 15:03:26.369380673 +0100 @@ -330,6 +330,9 @@ if (p->hw_address.hlen > 0) { break; } + if (p->next == NULL && p->hw_address.hbuf[0] == HTYPE_RESERVED) { + log_error("Can not generate DUID from interfaces which do not have hardware addresses, please configure server-duid!"); + } } if (p == NULL) { return ISC_R_UNEXPECTED;