123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- Implement priority/weight for DNS SRV records
- From RFC 2782:
- A client MUST attempt to contact the target host with the
- lowest-numbered priority it can reach.
- This patch sorts the DNS SRV records by their priority, and
- additionally gives records with a larger weight a higher probability
- of appearing earlier. This way, the DNS SRV records are tried in the
- order of their priority.
- Author: James M Leddy <james.leddy@redhat.com>
- Upstream ITS: #7027
- Resolves: #733078
- ---
- libraries/libldap/dnssrv.c | 106 ++++++++++++++++++++++++++++++++++----------
- 1 files changed, 83 insertions(+), 23 deletions(-)
- diff --git a/libraries/libldap/dnssrv.c b/libraries/libldap/dnssrv.c
- index 16b1544..40f93b4 100644
- --- a/libraries/libldap/dnssrv.c
- +++ b/libraries/libldap/dnssrv.c
- @@ -174,6 +174,46 @@ int ldap_domain2dn(
- return LDAP_SUCCESS;
- }
-
- +#ifdef HAVE_RES_QUERY
- +#define DNSBUFSIZ (64*1024)
- +typedef struct srv_record {
- + u_short priority;
- + u_short weight;
- + u_short port;
- + char hostname[DNSBUFSIZ];
- +} srv_record;
- +
- +
- +static int srv_cmp(const void *aa, const void *bb){
- + srv_record *a=(srv_record *)aa;
- + srv_record *b=(srv_record *)bb;
- + u_long total;
- +
- + if(a->priority < b->priority) {
- + return -1;
- + }
- + if(a->priority > b->priority) {
- + return 1;
- + }
- + if(a->priority == b->priority){
- + /* targets with same priority are in psudeo random order */
- + if (a->weight == 0 && b->weight == 0) {
- + if (rand() % 2) {
- + return -1;
- + } else {
- + return 1;
- + }
- + }
- + total = a->weight + b->weight;
- + if (rand() % total < a->weight) {
- + return -1;
- + } else {
- + return 1;
- + }
- + }
- +}
- +#endif /* HAVE_RES_QUERY */
- +
- /*
- * Lookup and return LDAP servers for domain (using the DNS
- * SRV record _ldap._tcp.domain).
- @@ -183,15 +223,16 @@ int ldap_domain2hostlist(
- char **list )
- {
- #ifdef HAVE_RES_QUERY
- -#define DNSBUFSIZ (64*1024)
- - char *request;
- - char *hostlist = NULL;
- + char *request;
- + char *hostlist = NULL;
- + srv_record *hostent_head=NULL;
- + int i;
- int rc, len, cur = 0;
- unsigned char reply[DNSBUFSIZ];
- + int hostent_count=0;
-
- assert( domain != NULL );
- assert( list != NULL );
- -
- if( *domain == '\0' ) {
- return LDAP_PARAM_ERROR;
- }
- @@ -223,8 +264,7 @@ int ldap_domain2hostlist(
- unsigned char *p;
- char host[DNSBUFSIZ];
- int status;
- - u_short port;
- - /* int priority, weight; */
- + u_short port, priority, weight;
-
- /* Parse out query */
- p = reply;
- @@ -263,40 +303,56 @@ int ldap_domain2hostlist(
- size = (p[0] << 8) | p[1];
- p += 2;
- if (type == T_SRV) {
- - int buflen;
- status = dn_expand(reply, reply + len, p + 6, host, sizeof(host));
- if (status < 0) {
- goto out;
- }
- - /* ignore priority and weight for now */
- - /* priority = (p[0] << 8) | p[1]; */
- - /* weight = (p[2] << 8) | p[3]; */
- +
- + /* Get priority weight and port */
- + priority = (p[0] << 8) | p[1];
- + weight = (p[2] << 8) | p[3];
- port = (p[4] << 8) | p[5];
-
- if ( port == 0 || host[ 0 ] == '\0' ) {
- goto add_size;
- }
-
- - buflen = strlen(host) + STRLENOF(":65355 ");
- - hostlist = (char *) LDAP_REALLOC(hostlist, cur + buflen + 1);
- - if (hostlist == NULL) {
- - rc = LDAP_NO_MEMORY;
- - goto out;
- + hostent_head = (srv_record *) LDAP_REALLOC(hostent_head, (hostent_count+1)*(sizeof(srv_record)));
- + if(hostent_head==NULL){
- + rc=LDAP_NO_MEMORY;
- + goto out;
- +
- }
- - if (cur > 0) {
- - /* not first time around */
- - hostlist[cur++] = ' ';
- - }
- - cur += sprintf(&hostlist[cur], "%s:%hu", host, port);
- + hostent_head[hostent_count].priority=priority;
- + hostent_head[hostent_count].weight=weight;
- + hostent_head[hostent_count].port=port;
- + strncpy(hostent_head[hostent_count].hostname, host,255);
- + hostent_count=hostent_count+1;
- }
- add_size:;
- p += size;
- }
- }
- + qsort(hostent_head, hostent_count, sizeof(srv_record), srv_cmp);
- +
- + for(i=0; i<hostent_count; i++){
- + int buflen;
- + buflen = strlen(hostent_head[i].hostname) + STRLENOF(":65355" );
- + hostlist = (char *) LDAP_REALLOC(hostlist, cur+buflen+1);
- + if (hostlist == NULL) {
- + rc = LDAP_NO_MEMORY;
- + goto out;
- + }
- + if(cur>0){
- + hostlist[cur++]=' ';
- + }
- + cur += sprintf(&hostlist[cur], "%s:%hd", hostent_head[i].hostname, hostent_head[i].port);
- + }
- +
- if (hostlist == NULL) {
- - /* No LDAP servers found in DNS. */
- - rc = LDAP_UNAVAILABLE;
- - goto out;
- + /* No LDAP servers found in DNS. */
- + rc = LDAP_UNAVAILABLE;
- + goto out;
- }
-
- rc = LDAP_SUCCESS;
- @@ -308,8 +364,12 @@ add_size:;
- if (request != NULL) {
- LDAP_FREE(request);
- }
- + if (hostent_head != NULL) {
- + LDAP_FREE(hostent_head);
- + }
- if (rc != LDAP_SUCCESS && hostlist != NULL) {
- LDAP_FREE(hostlist);
- +
- }
- return rc;
- #else
- --
- 1.7.6
|