From 6586e8352a56104b850c2ce55912cc630dd8c195 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Thu, 7 Nov 2013 14:20:13 +0000 Subject: [PATCH] Use random address allocation for DHCPv6 temporary addresses. --- src/dhcp6.c | 14 +++++++++----- src/dnsmasq.h | 3 ++- src/rfc3315.c | 3 ++- src/util.c | 37 +++++++++++++++++++++++++++++++------ 4 files changed, 44 insertions(+), 13 deletions(-) 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 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct 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 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c 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 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c 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 @@ int in_zone(struct auth_zone *zone, char *name, char **cut); /* 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 @@ int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr, #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 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ } /* 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 @@ unsigned short rand16(void) 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 @@ unsigned short rand16(void) static u32 seed[32]; static u32 in[12]; static u32 out[8]; +static int outleft = 0; void rand_init() { @@ -82,16 +92,31 @@ static void surf(void) } 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 -- 2.47.2