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