diff options
Diffstat (limited to 'src/dhcpv6-ia.c')
-rw-r--r-- | src/dhcpv6-ia.c | 47 |
1 files changed, 23 insertions, 24 deletions
diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c index e8255b5..bd4b6e1 100644 --- a/src/dhcpv6-ia.c +++ b/src/dhcpv6-ia.c @@ -16,6 +16,7 @@ #include "odhcpd.h" #include "dhcpv6.h" #include "dhcpv4.h" +#include "prng.h" #include <time.h> #include <errno.h> @@ -51,12 +52,15 @@ static struct netevent_handler dhcpv6_netevent_handler = { .cb = dhcpv6_netevent static struct uloop_timeout valid_until_timeout = {.cb = valid_until_cb}; static uint32_t serial = 0; static uint8_t statemd5[16]; +static prng_context_t *prng; int dhcpv6_ia_init(void) { uloop_timeout_set(&valid_until_timeout, 1000); netlink_add_netevent_handler(&dhcpv6_netevent_handler); + prng = prng_alloc(); + prng_setup(prng); return 0; } @@ -700,7 +704,6 @@ static bool is_reserved_ipv6_iid(uint64_t iid) static bool assign_na(struct interface *iface, struct dhcp_assignment *a) { struct dhcp_assignment *c; - uint32_t seed = 0; /* Preconfigured assignment by static lease */ if (a->assigned_host_id) { @@ -713,36 +716,32 @@ static bool assign_na(struct interface *iface, struct dhcp_assignment *a) } } - /* Seed RNG with checksum of DUID */ - for (size_t i = 0; i < a->clid_len; ++i) - seed += a->clid_data[i]; - srandom(seed); + uint8_t counter = 0; + uint64_t mask; + + if (iface->dhcpv6_hostid_len < 64) + mask = ((uint64_t)1 << (uint64_t)iface->dhcpv6_hostid_len) - 1; + else + mask = UINT64_MAX; /* Try to assign up to 100x */ for (size_t i = 0; i < 100; ++i) { - uint64_t try; + uint64_t try = 0; + uint32_t counter_be = htonl(counter); - if (iface->dhcpv6_hostid_len > 32) { - uint32_t mask_high; + prng_starts(prng); + prng_update(prng, a->clid_data, a->clid_len); + prng_update(prng, (const uint8_t*)&a->iaid, sizeof(a->iaid)); + prng_update(prng, (const uint8_t*)&counter_be, sizeof(counter_be)); + prng_update(prng, (const uint8_t*)&config.secret_key, sizeof(config.secret_key)); + prng_finish(prng, (uint8_t*)&try); - if (iface->dhcpv6_hostid_len >= 64) - mask_high = UINT32_MAX; - else - mask_high = (1 << (iface->dhcpv6_hostid_len - 32)) - 1; + try &= mask; - do { - try = (uint32_t)random(); - try |= (uint64_t)((uint32_t)random() & mask_high) << 32; - } while (try < 0x100); - } else { - uint32_t mask_low; + counter++; - if (iface->dhcpv6_hostid_len == 32) - mask_low = UINT32_MAX; - else - mask_low = (1 << iface->dhcpv6_hostid_len) - 1; - do try = ((uint32_t)random()) & mask_low; while (try < 0x100); - } + if (try < 0x100) + continue; if (is_reserved_ipv6_iid(try)) continue; |