summaryrefslogtreecommitdiffhomepage
path: root/src/dhcpv6-ia.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dhcpv6-ia.c')
-rw-r--r--src/dhcpv6-ia.c47
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;