From: Wouter Wijngaards Date: Thu, 18 Mar 2010 14:42:22 +0000 (+0000) Subject: Fixed random numbers for port, interface and server selection. X-Git-Tag: release-1.4.4rc1~34 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=75565262f75bc50038f91038199899c95e3ae669;p=thirdparty%2Funbound.git Fixed random numbers for port, interface and server selection. Removed very small bias. Also some lint fixes. git-svn-id: file:///svn/unbound/trunk@2049 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/daemon/daemon.c b/daemon/daemon.c index fb293b506..5657a8b2e 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -292,7 +292,7 @@ int daemon_get_shufport(struct daemon* daemon, int* shufport) /* Knuth shuffle */ n = avail; while(--n > 0) { - k = ub_random(daemon->rand) % (n+1); /* 0<= k<= n */ + k = ub_random_max(daemon->rand, n+1); /* 0<= k<= n */ temp = shufport[k]; shufport[k] = shufport[n]; shufport[n] = temp; diff --git a/doc/Changelog b/doc/Changelog index 64033a698..6ada462d7 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,7 @@ +18 March 2010: Wouter + - Fixed random numbers for port, interface and server selection. + Removed very small bias. + 16 March 2010: Wouter - Fix interface-automatic for OpenBSD: msg.controllen was too small, also assertions on ancillary data buffer. diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index cd000da37..a706e6b64 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -350,9 +350,9 @@ iter_server_selection(struct iter_env* iter_env, /* randomly select a target from the list */ log_assert(num > 1); - /* we do not need secure random numbers here, but - * we do need it to be threadsafe, so we use this */ - sel = ub_random(env->rnd) % num; + /* grab secure random number, to pick unexpected server. + * also we need it to be threadsafe. */ + sel = ub_random_max(env->rnd, num); a = dp->result_list; prev = NULL; while(sel > 0 && a) { @@ -418,7 +418,7 @@ iter_ns_probability(struct ub_randstate* rnd, int n, int m) return 1; /* we do not need secure random numbers here, but * we do need it to be threadsafe, so we use this */ - sel = ub_random(rnd) % m; + sel = ub_random_max(rnd, m); return (sel < n); } diff --git a/pythonmod/pythonmod.c b/pythonmod/pythonmod.c index 579b82ab3..1753869e5 100644 --- a/pythonmod/pythonmod.c +++ b/pythonmod/pythonmod.c @@ -57,6 +57,8 @@ #ifdef S_SPLINT_S typedef struct PyObject PyObject; +typedef struct PyThreadState PyThreadState; +typedef void* PyGILState_STATE; #endif /** diff --git a/services/outside_network.c b/services/outside_network.c index 02eead896..e1c5265d7 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -809,9 +809,9 @@ select_ifport(struct outside_network* outnet, struct pending* pend, log_assert(outnet->unused_fds); tries = 0; while(1) { - my_if = ub_random(outnet->rnd) % num_if; + my_if = ub_random_max(outnet->rnd, num_if); pif = &ifs[my_if]; - my_port = ub_random(outnet->rnd) % pif->avail_total; + my_port = ub_random_max(outnet->rnd, pif->avail_total); if(my_port < pif->inuse) { /* port already open */ pend->pc = pif->out[my_port]; diff --git a/testcode/unitmain.c b/testcode/unitmain.c index 4f7e8125a..9105afb88 100644 --- a/testcode/unitmain.c +++ b/testcode/unitmain.c @@ -447,10 +447,12 @@ static void rnd_test() { struct ub_randstate* r; - int num = 100, i; - long int a[100]; + int num = 1000, i; + long int a[1000]; + unsigned int seed = (unsigned)time(NULL); unit_show_feature("ub_random"); - unit_assert( (r = ub_initstate((unsigned)time(NULL), NULL)) ); + printf("ub_random seed is %u\n", seed); + unit_assert( (r = ub_initstate(seed, NULL)) ); for(i=0; i= 0); @@ -460,6 +462,14 @@ rnd_test() a[i] != a[i-3] || a[i] != a[i-4] || a[i] != a[i-5] || a[i] != a[i-6]); } + a[0] = ub_random_max(r, 1); + unit_assert(a[0] >= 0 && a[0] < 1); + a[0] = ub_random_max(r, 10000); + unit_assert(a[0] >= 0 && a[0] < 10000); + for(i=0; i= 0 && a[i] < 10); + } ub_randfree(r); } diff --git a/util/random.c b/util/random.c index 4b387fe49..1458104fe 100644 --- a/util/random.c +++ b/util/random.c @@ -177,6 +177,18 @@ ub_random(struct ub_randstate* s) return (long int)((r) % (((unsigned)MAX_VALUE + 1))); } +long int +ub_random_max(struct ub_randstate* state, long int x) +{ + /* make sure we fetch in a range that is divisible by x. ignore + * values from d .. MAX_VALUE, instead draw a new number */ + long int d = MAX_VALUE - (MAX_VALUE % x); /* d is divisible by x */ + long int v = ub_random(state); + while(d <= v) + v = ub_random(state); + return (v % x); +} + void ub_randfree(struct ub_randstate* s) { diff --git a/util/random.h b/util/random.h index 62e3033a7..400141a18 100644 --- a/util/random.h +++ b/util/random.h @@ -75,6 +75,15 @@ struct ub_randstate* ub_initstate(unsigned int seed, */ long int ub_random(struct ub_randstate* state); +/** + * Generate random number between 0 and x-1. No modulo bias. + * @param state: must have been initialised with ub_initstate. + * @param x: an upper limit. not negative or zero. must be smaller than 2**31. + * @return: random value between 0..x-1. Possibly more than one + * random number is picked from the random stream to satisfy this. + */ +long int ub_random_max(struct ub_randstate* state, long int x); + /** * Delete the random state. * @param state: to delete. diff --git a/validator/autotrust.c b/validator/autotrust.c index 4e90862ce..578a63f46 100644 --- a/validator/autotrust.c +++ b/validator/autotrust.c @@ -1685,7 +1685,7 @@ calc_next_probe(struct module_env* env, uint32_t wait) wait = 3600; rnd = wait/10; rest = wait-rnd; - rnd = (uint32_t)ub_random(env->rnd) % rnd; + rnd = (uint32_t)ub_random_max(env->rnd, (long int)rnd); return (time_t)(*env->now + rest + rnd); }