ITS#7027 actually implement RFC 2782 shuffle

This commit is contained in:
Howard Chu 2014-07-21 22:05:25 -07:00
parent 31995b535e
commit eef1ca007f

View File

@ -176,41 +176,77 @@ int ldap_domain2dn(
#ifdef HAVE_RES_QUERY #ifdef HAVE_RES_QUERY
#define DNSBUFSIZ (64*1024) #define DNSBUFSIZ (64*1024)
#define MAXHOST 254 /* RFC 1034, max length is 253 chars */
typedef struct srv_record { typedef struct srv_record {
u_short priority; u_short priority;
u_short weight; u_short weight;
u_short port; u_short port;
char hostname[DNSBUFSIZ]; char hostname[MAXHOST];
} srv_record; } srv_record;
/* Linear Congruential Generator - we don't need
* high quality randomness, and we don't want to
* interfere with anyone else's use of srand().
*
* The PRNG here cycles thru 941,955 numbers.
*/
static float srv_seed;
static void srv_srand(int seed) {
srv_seed = (float)seed / (float)RAND_MAX;
}
static float srv_rand() {
float val = 9821.0 * srv_seed + .211327;
srv_seed = val - (int)val;
return srv_seed;
}
static int srv_cmp(const void *aa, const void *bb){ static int srv_cmp(const void *aa, const void *bb){
srv_record *a=(srv_record *)aa; srv_record *a=(srv_record *)aa;
srv_record *b=(srv_record *)bb; srv_record *b=(srv_record *)bb;
u_long total; int i = a->priority - b->priority;
if (i) return i;
return b->weight - a->weight;
}
if(a->priority < b->priority) { static void srv_shuffle(srv_record *a, int n) {
return -1; int i, j, total = 0, r, p;
}
if(a->priority > b->priority) { for (i=0; i<n; i++)
return 1; total += a[i].weight;
}
if(a->priority == b->priority){ /* all weights are zero, do a straight Fisher-Yates shuffle */
/* targets with same priority are in psudeo random order */ if (!total) {
if (a->weight == 0 && b->weight == 0) { while (n) {
if (rand() % 2) { srv_record t;
return -1; i = srv_rand() * n--;
} else { t = a[n];
return 1; a[n] = a[i];
} a[i] = t;
}
return;
} }
total = a->weight + b->weight;
if (rand() % total < a->weight) { /* Do a shuffle per RFC2782 Page 4 */
return -1; p = n;
} else { for (i=0; i<n-1; i++) {
return 1; r = srv_rand() * total;
for (j=0; j<p; j++) {
r -= a[j].weight;
if (r <= 0) {
if (j) {
srv_record t = a[0];
a[0] = a[j];
a[j] = t;
}
total -= a[0].weight;
a++;
p--;
break;
}
}
} }
}
} }
#endif /* HAVE_RES_QUERY */ #endif /* HAVE_RES_QUERY */
@ -226,7 +262,7 @@ int ldap_domain2hostlist(
char *request; char *request;
char *hostlist = NULL; char *hostlist = NULL;
srv_record *hostent_head=NULL; srv_record *hostent_head=NULL;
int i; int i, j;
int rc, len, cur = 0; int rc, len, cur = 0;
unsigned char reply[DNSBUFSIZ]; unsigned char reply[DNSBUFSIZ];
int hostent_count=0; int hostent_count=0;
@ -325,15 +361,31 @@ int ldap_domain2hostlist(
hostent_head[hostent_count].priority=priority; hostent_head[hostent_count].priority=priority;
hostent_head[hostent_count].weight=weight; hostent_head[hostent_count].weight=weight;
hostent_head[hostent_count].port=port; hostent_head[hostent_count].port=port;
strncpy(hostent_head[hostent_count].hostname, host,255); strncpy(hostent_head[hostent_count].hostname, host, MAXHOST);
hostent_count=hostent_count+1; hostent_count++;
} }
add_size:; add_size:;
p += size; p += size;
} }
}
qsort(hostent_head, hostent_count, sizeof(srv_record), srv_cmp); qsort(hostent_head, hostent_count, sizeof(srv_record), srv_cmp);
if (!srv_seed)
srv_srand(time(0L));
/* shuffle records of same priority */
j = 0;
priority = hostent_head[0].priority;
for (i=1; i<hostent_count; i++) {
if (hostent_head[i].priority != priority) {
priority = hostent_head[i].priority;
if (i-j > 1)
srv_shuffle(hostent_head+j, i-j);
j = i;
}
}
if (i-j > 1)
srv_shuffle(hostent_head+j, i-j);
for(i=0; i<hostent_count; i++){ for(i=0; i<hostent_count; i++){
int buflen; int buflen;
buflen = strlen(hostent_head[i].hostname) + STRLENOF(":65535 "); buflen = strlen(hostent_head[i].hostname) + STRLENOF(":65535 ");
@ -347,6 +399,7 @@ add_size:;
} }
cur += sprintf(&hostlist[cur], "%s:%hd", hostent_head[i].hostname, hostent_head[i].port); cur += sprintf(&hostlist[cur], "%s:%hd", hostent_head[i].hostname, hostent_head[i].port);
} }
}
if (hostlist == NULL) { if (hostlist == NULL) {
/* No LDAP servers found in DNS. */ /* No LDAP servers found in DNS. */