Blob Blame History Raw
diff --git a/configure b/configure
index edc4adb..1b1336d 100755
--- a/configure
+++ b/configure
@@ -349,10 +349,10 @@ detect_resolv_static()
 	TMPFILE=$(mktemp /tmp/bitlbee-configure.XXXXXX)
 	ret=1
 	for i in $systemlibdirs; do
-		if [ -f $i/libresolv.a ]; then
+		if [ -f $i/libresolv.so ]; then
 			echo "$RESOLV_TESTCODE" | $CC -o $TMPFILE -x c - -Wl,$i/libresolv.a >/dev/null 2>/dev/null
 			if [ "$?" = "0" ]; then
-				echo 'EFLAGS+='$i'/libresolv.a' >> Makefile.settings
+				echo 'EFLAGS+=-lresolv' >> Makefile.settings
 				ret=0
 			fi
 		fi
diff --git a/lib/misc.c b/lib/misc.c
index 05192d9..556fe1a 100644
--- a/lib/misc.c
+++ b/lib/misc.c
@@ -1,8 +1,8 @@
-  /********************************************************************\
-  * BitlBee -- An IRC to other IM-networks gateway                     *
-  *                                                                    *
-  * Copyright 2002-2006 Wilmer van der Gaast and others                *
-  \********************************************************************/
+/********************************************************************\
+* BitlBee -- An IRC to other IM-networks gateway                     *
+*                                                                    *
+* Copyright 2002-2006 Wilmer van der Gaast and others                *
+\********************************************************************/
 
 /*
  * Various utility functions. Some are copied from Gaim to support the
@@ -30,6 +30,12 @@
   Suite 330, Boston, MA  02111-1307  USA
 */
 
+#undef TEST
+
+#ifdef TEST
+#define HAVE_RESOLV_A
+#endif
+
 #define BITLBEE_CORE
 #include "nogaim.h"
 #include "base64.h"
@@ -42,13 +48,17 @@
 #include <time.h>
 
 #ifdef HAVE_RESOLV_A
-#include <arpa/nameser.h>
 #include <resolv.h>
 #endif
 
 #include "md5.h"
 #include "ssl_client.h"
 
+/* Not every installation has gotten around to supporting SRVs yet...*/
+#ifndef T_SRV
+#define T_SRV 33
+#endif
+
 void strip_linefeed(gchar *text)
 {
 	int i, j;
@@ -514,66 +524,6 @@ int bool2int( char *value )
 	return 0;
 }
 
-struct ns_srv_reply **srv_lookup( char *service, char *protocol, char *domain )
-{	
-	struct ns_srv_reply **replies = NULL;
-#ifdef HAVE_RESOLV_A
-	struct ns_srv_reply *reply = NULL;
-	char name[1024];
-	unsigned char querybuf[1024];
-	const unsigned char *buf;
-	ns_msg nsh;
-	ns_rr rr;
-	int i, n, len, size;
-	
-	g_snprintf( name, sizeof( name ), "_%s._%s.%s", service, protocol, domain );
-	
-	if( ( size = res_query( name, ns_c_in, ns_t_srv, querybuf, sizeof( querybuf ) ) ) <= 0 )
-		return NULL;
-	
-	if( ns_initparse( querybuf, size, &nsh ) != 0 )
-		return NULL;
-	
-	n = 0;
-	while( ns_parserr( &nsh, ns_s_an, n, &rr ) == 0 )
-	{
-		size = ns_rr_rdlen( rr );
-		buf = ns_rr_rdata( rr );
-		
-		len = 0;
-		for( i = 6; i < size && buf[i]; i += buf[i] + 1 )
-			len += buf[i] + 1;
-		
-		if( i > size )
-			break;
-		
-		reply = g_malloc( sizeof( struct ns_srv_reply ) + len );
-		memcpy( reply->name, buf + 7, len );
-		
-		for( i = buf[6]; i < len && buf[7+i]; i += buf[7+i] + 1 )
-			reply->name[i] = '.';
-		
-		if( i > len )
-		{
-			g_free( reply );
-			break;
-		}
-		
-		reply->prio = ( buf[0] << 8 ) | buf[1];
-		reply->weight = ( buf[2] << 8 ) | buf[3];
-		reply->port = ( buf[4] << 8 ) | buf[5];
-		
-		n ++;
-		replies = g_renew( struct ns_srv_reply *, replies, n + 1 );
-		replies[n-1] = reply;
-	}
-	if( replies )
-		replies[n] = NULL;
-#endif
-	
-	return replies;
-}
-
 void srv_free( struct ns_srv_reply **srv )
 {
 	int i;
@@ -586,6 +536,119 @@ void srv_free( struct ns_srv_reply **srv )
 	g_free( srv );
 }
 
+static int srv_compare(const void *a, const void *b) {
+    int prio;
+    const struct ns_srv_reply *sa = *(struct ns_srv_reply **) a;
+    const struct ns_srv_reply *sb = *(struct ns_srv_reply **) b;
+
+    prio = sa->prio - sb->prio;
+    if (prio == 0) {
+        /* Place weight 0 entries first. */
+        if (sa->weight == 0) return -1;
+        if (sb->weight == 0) return 1;
+    }
+
+    return prio;
+}
+
+struct ns_srv_reply **srv_lookup(char *service, char *protocol, char *domain) {
+    struct ns_srv_reply **results = NULL;
+    struct ns_srv_reply *reply = NULL;
+    char name[1024];
+
+    /* PACKETSZ is a maximum packet size and
+       defined in arpa/nameser_compat.h as 512 */
+    unsigned char answer[PACKETSZ];
+    int len;
+    HEADER *header;
+    unsigned char *p;
+    unsigned char *end;
+    unsigned int count;
+    size_t n;
+
+    uint16_t type;
+    uint16_t class;
+    uint32_t ttl;
+    uint16_t rdlength;
+
+    g_snprintf(name, sizeof(name), "_%s._%s.%s", service, protocol, domain);
+
+    len = res_query(name, C_IN, T_SRV, answer, PACKETSZ);
+    if (len == -1) {
+        goto fail;
+    }
+
+    header = (HEADER *) answer;
+    p = answer + sizeof(HEADER);
+    end = answer + len;
+
+    if (header->rcode != NOERROR) {
+        goto fail;
+    }
+
+    len = dn_skipname(p, end);
+    if (len == -1) {
+        goto fail;
+    }
+    p += len + QFIXEDSZ;
+
+    count = ntohs(header->ancount);
+
+    results = g_new(struct ns_srv_reply *, count + 1);
+
+    n = 0;
+    while (count-- > 0 && p < end) {
+        len = dn_skipname(p, end);
+        if (len == -1) {
+            goto fail;
+        }
+        p += len;
+
+        GETSHORT(type, p);
+        GETSHORT(class, p);
+        GETLONG(ttl, p);
+        GETSHORT(rdlength, p);
+
+        if (type != T_SRV || class != C_IN) {
+            p += rdlength;
+            continue;
+        }
+
+        /* This is an overestimate of the needed size. */
+        reply = g_malloc(sizeof(struct ns_srv_reply) + rdlength + 1);
+
+        GETSHORT(reply->prio, p);
+        GETSHORT(reply->weight, p);
+        GETSHORT(reply->port, p);
+
+        len = dn_expand(answer, end, p, reply->name, rdlength + 1);
+        if (len == -1) {
+            g_free(reply);
+            goto fail;
+        }
+        p += len;
+
+        results[n++] = reply;
+    }
+
+    results[n] = NULL;
+
+    /* Order by priority. */
+    qsort(results, n, sizeof(struct ns_srv_reply *), srv_compare);
+
+    return results;
+
+fail:
+    if (results) {
+        while (n-- > 0) {
+            g_free(results[n]);
+        }
+        g_free(results);
+    }
+
+    return NULL;
+}
+
 /* Word wrapping. Yes, I know this isn't UTF-8 clean. I'm willing to take the risk. */
 char *word_wrap( const char *msg, int line_len )
 {
@@ -728,3 +791,22 @@ char **split_command_parts( char *command )
 	
 	return cmd;
 }
+
+#ifdef TEST
+int main() {
+    struct ns_srv_reply **srv;
+    int i;
+
+    srv = srv_lookup("xmpp-client", "tcp", "jabber.org");
+    for (i = 0; srv[i]; ++i) {
+        printf("priority=%hu\n", srv[i]->prio);
+        printf("weight=%hu\n", srv[i]->weight);
+        printf("port=%hu\n", srv[i]->port);
+        printf("target=%s\n", srv[i]->name);
+        printf("\n");
+    }
+    srv_free(srv);
+
+    return 0;
+}
+#endif /* TEST */