Use random address allocation for DHCPv6 temporary addresses.
diff --git a/src/dhcp6.c b/src/dhcp6.c
index 7c72872..5da2d0f 100644
--- a/src/dhcp6.c
+++ b/src/dhcp6.c
@@ -394,7 +394,7 @@
return NULL;
}
-struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
+struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len, int temp_addr,
int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans)
{
/* Find a free address: exclude anything in use and anything allocated to
@@ -411,9 +411,13 @@
u64 j;
/* hash hwaddr: use the SDBM hashing algorithm. This works
- for MAC addresses, let's see how it manages with client-ids! */
- for (j = iaid, i = 0; i < clid_len; i++)
- j += clid[i] + (j << 6) + (j << 16) - j;
+ for MAC addresses, let's see how it manages with client-ids!
+ For temporary addresses, we generate a new random one each time. */
+ if (temp_addr)
+ j = rand64();
+ else
+ for (j = iaid, i = 0; i < clid_len; i++)
+ j += clid[i] + (j << 6) + (j << 16) - j;
for (pass = 0; pass <= plain_range ? 1 : 0; pass++)
for (c = context; c; c = c->current)
@@ -423,7 +427,7 @@
continue;
else
{
- if (option_bool(OPT_CONSEC_ADDR))
+ if (!temp_addr && option_bool(OPT_CONSEC_ADDR))
/* seed is largest extant lease addr in this context */
start = lease_find_max_addr6(c) + serial;
else
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 62b1d68..98266c6 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -1000,6 +1000,7 @@
/* util.c */
void rand_init(void);
unsigned short rand16(void);
+u64 rand64(void);
int legal_hostname(char *c);
char *canonicalise(char *s, int *nomem);
unsigned char *do_rfc1035_name(unsigned char *p, char *sval);
@@ -1221,7 +1222,7 @@
#ifdef HAVE_DHCP6
void dhcp6_init(void);
void dhcp6_packet(time_t now);
-struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
+struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len, int temp_addr,
int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans);
int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr);
struct dhcp_context *address6_available(struct dhcp_context *context,
diff --git a/src/rfc3315.c b/src/rfc3315.c
index bf3bacf..8a2660f 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -764,7 +764,8 @@
}
/* Return addresses for all valid contexts which don't yet have one */
- while ((c = address6_allocate(state->context, state->clid, state->clid_len, state->iaid, ia_counter, solicit_tags, plain_range, &addr)))
+ while ((c = address6_allocate(state->context, state->clid, state->clid_len, state->ia_type == OPTION6_IA_TA,
+ state->iaid, ia_counter, solicit_tags, plain_range, &addr)))
{
#ifdef OPTION6_PREFIX_CLASS
if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
diff --git a/src/util.c b/src/util.c
index 94cc570..b267558 100644
--- a/src/util.c
+++ b/src/util.c
@@ -39,6 +39,15 @@
return (unsigned short) (arc4random() >> 15);
}
+u64 rand64(void)
+{
+ u64 ret;
+
+ arc4random_buf(&ret, sizeof(ret));
+
+ return ret;
+}
+
#else
/* SURF random number generator */
@@ -46,6 +55,7 @@
static u32 seed[32];
static u32 in[12];
static u32 out[8];
+static int outleft = 0;
void rand_init()
{
@@ -83,15 +93,30 @@
unsigned short rand16(void)
{
+ if (!outleft)
+ {
+ if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
+ surf();
+ outleft = 8;
+ }
+
+ return (unsigned short) out[--outleft];
+}
+
+u64 rand64(void)
+{
static int outleft = 0;
- if (!outleft) {
- if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
- surf();
- outleft = 8;
- }
+ if (outleft < 2)
+ {
+ if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
+ surf();
+ outleft = 8;
+ }
+
+ outleft -= 2;
- return (unsigned short) out[--outleft];
+ return (u64)out[outleft+1] + (((u64)out[outleft]) << 32);
}
#endif