5003895
Patch by Matěj Cepl <mcepl@redhat.com> for bitlbee >= 3.2 to avoid static linking
566011b
to a private glibc function, that is normally visible as libc.so.6(GLIBC_PRIVATE)
566011b
in the binary RPM package. Glibc >= 2.9 allows dynamic linking using -lresolv for
566011b
ns_initparse()/ns_parserr(), but Red Hat Enterprise Linux 5 (including derivates)
566011b
is shipping glibc 2.5. A few more information and details regarding this patch in
566011b
Red Hat Bugzilla ID #439047: https://bugzilla.redhat.com/show_bug.cgi?id=439047
566011b
5003895
--- bitlbee-3.2.1/configure			2013-11-27 23:54:54.000000000 +0100
5003895
+++ bitlbee-3.2.1/configure.libresolv		2013-12-18 21:56:14.000000000 +0100
5003895
@@ -364,10 +364,10 @@
4b3d380
 	TMPFILE=$(mktemp /tmp/bitlbee-configure.XXXXXX)
4b3d380
 	ret=1
f03c519
 	for i in $systemlibdirs; do
f03c519
-		if [ -f $i/libresolv.a ]; then
f03c519
+		if [ -f $i/libresolv.so ]; then
4b3d380
 			echo "$RESOLV_TESTCODE" | $CC -o $TMPFILE -x c - -Wl,$i/libresolv.a >/dev/null 2>/dev/null
f03c519
 			if [ "$?" = "0" ]; then
f03c519
-				echo 'EFLAGS+='$i'/libresolv.a' >> Makefile.settings
f03c519
+				echo 'EFLAGS+=-lresolv' >> Makefile.settings
4b3d380
 				ret=0
f03c519
 			fi
f03c519
 		fi
5003895
--- bitlbee-3.2.1/lib/misc.c			2013-11-27 23:54:54.000000000 +0100
5003895
+++ bitlbee-3.2.1/lib/misc.c.libresolv		2013-12-18 22:10:45.000000000 +0100
5003895
--- bitlbee-3.2.1/lib/misc.c	2013-11-27 23:54:54.000000000 +0100
5003895
+++ bitlbee-3.2.1/lib/misc.c.libresolv.c	2013-12-18 22:18:29.000000000 +0100
d4fdeea
@@ -30,6 +30,12 @@
d4fdeea
   Suite 330, Boston, MA  02111-1307  USA
d4fdeea
 */
4ce68a1
 
d4fdeea
+#undef TEST
d4fdeea
+
d4fdeea
+#ifdef TEST
d4fdeea
+#define HAVE_RESOLV_A
d4fdeea
+#endif
d4fdeea
+
d4fdeea
 #define BITLBEE_CORE
d4fdeea
 #include "nogaim.h"
d4fdeea
 #include "base64.h"
d4fdeea
@@ -42,13 +48,17 @@
d4fdeea
 #include <time.h>
72ecaea
 
4ce68a1
 #ifdef HAVE_RESOLV_A
d4fdeea
-#include <arpa/nameser.h>
4ce68a1
 #include <resolv.h>
4ce68a1
 #endif
4ce68a1
 
4b3d380
 #include "md5.h"
d4fdeea
 #include "ssl_client.h"
d4fdeea
 
5003895
+/* Not every installation has gotten around to supporting SRVs yet... */
d4fdeea
+#ifndef T_SRV
d4fdeea
+#define T_SRV 33
d4fdeea
+#endif
d4fdeea
+
d4fdeea
 void strip_linefeed(gchar *text)
d4fdeea
 {
d4fdeea
 	int i, j;
5003895
@@ -514,66 +524,6 @@
4ce68a1
 	return 0;
4ce68a1
 }
4ce68a1
 
72ecaea
-struct ns_srv_reply **srv_lookup( char *service, char *protocol, char *domain )
4ce68a1
-{	
72ecaea
-	struct ns_srv_reply **replies = NULL;
4ce68a1
-#ifdef HAVE_RESOLV_A
72ecaea
-	struct ns_srv_reply *reply = NULL;
4ce68a1
-	char name[1024];
4ce68a1
-	unsigned char querybuf[1024];
4ce68a1
-	const unsigned char *buf;
4ce68a1
-	ns_msg nsh;
4ce68a1
-	ns_rr rr;
72ecaea
-	int i, n, len, size;
4ce68a1
-	
4ce68a1
-	g_snprintf( name, sizeof( name ), "_%s._%s.%s", service, protocol, domain );
4ce68a1
-	
4ce68a1
-	if( ( size = res_query( name, ns_c_in, ns_t_srv, querybuf, sizeof( querybuf ) ) ) <= 0 )
4ce68a1
-		return NULL;
4ce68a1
-	
4ce68a1
-	if( ns_initparse( querybuf, size, &nsh ) != 0 )
4ce68a1
-		return NULL;
4ce68a1
-	
72ecaea
-	n = 0;
72ecaea
-	while( ns_parserr( &nsh, ns_s_an, n, &rr ) == 0 )
4ce68a1
-	{
72ecaea
-		size = ns_rr_rdlen( rr );
72ecaea
-		buf = ns_rr_rdata( rr );
72ecaea
-		
72ecaea
-		len = 0;
72ecaea
-		for( i = 6; i < size && buf[i]; i += buf[i] + 1 )
72ecaea
-			len += buf[i] + 1;
72ecaea
-		
72ecaea
-		if( i > size )
72ecaea
-			break;
72ecaea
-		
72ecaea
-		reply = g_malloc( sizeof( struct ns_srv_reply ) + len );
72ecaea
-		memcpy( reply->name, buf + 7, len );
72ecaea
-		
72ecaea
-		for( i = buf[6]; i < len && buf[7+i]; i += buf[7+i] + 1 )
72ecaea
-			reply->name[i] = '.';
72ecaea
-		
72ecaea
-		if( i > len )
72ecaea
-		{
72ecaea
-			g_free( reply );
72ecaea
-			break;
72ecaea
-		}
72ecaea
-		
72ecaea
-		reply->prio = ( buf[0] << 8 ) | buf[1];
72ecaea
-		reply->weight = ( buf[2] << 8 ) | buf[3];
72ecaea
-		reply->port = ( buf[4] << 8 ) | buf[5];
72ecaea
-		
72ecaea
-		n ++;
72ecaea
-		replies = g_renew( struct ns_srv_reply *, replies, n + 1 );
72ecaea
-		replies[n-1] = reply;
4ce68a1
-	}
72ecaea
-	if( replies )
72ecaea
-		replies[n] = NULL;
4ce68a1
-#endif
4ce68a1
-	
72ecaea
-	return replies;
4ce68a1
-}
4ce68a1
-
72ecaea
 void srv_free( struct ns_srv_reply **srv )
4ce68a1
 {
72ecaea
 	int i;
5003895
@@ -586,6 +536,136 @@
d4fdeea
 	g_free( srv );
d4fdeea
 }
72ecaea
 
5003895
+static int srv_compare( const void *a, const void *b )
5003895
+{
5003895
+	int prio;
5003895
+	const struct ns_srv_reply *sa = *(struct ns_srv_reply **) a;
5003895
+	const struct ns_srv_reply *sb = *(struct ns_srv_reply **) b;
d4fdeea
+
5003895
+	prio = sa->prio - sb->prio;
5003895
+	if( prio == 0 )
5003895
+	{
5003895
+		/* Place weight 0 entries first. */
5003895
+		if( sa->weight == 0 )
5003895
+			return -1;
5003895
+		if( sb->weight == 0 )
5003895
+			return 1;
5003895
+	}
d4fdeea
+
5003895
+	return prio;
4ce68a1
+}
4ce68a1
+
5003895
+struct ns_srv_reply **srv_lookup( char *service, char *protocol, char *domain )
5003895
+{
5003895
+	struct ns_srv_reply **results = NULL;
5003895
+	struct ns_srv_reply *reply = NULL;
5003895
+	char name[1024];
d4fdeea
+
5003895
+	/* PACKETSZ is a maximum packet size and
5003895
+	   defined in arpa/nameser_compat.h as 512 */
5003895
+	unsigned char answer[PACKETSZ];
5003895
+	int len;
5003895
+	HEADER *header;
5003895
+	unsigned char *p;
5003895
+	unsigned char *end;
5003895
+	unsigned int count;
5003895
+	size_t n;
d4fdeea
+
5003895
+	uint16_t type;
5003895
+	uint16_t class;
5003895
+	uint32_t ttl;
5003895
+	uint16_t rdlength;
d4fdeea
+
5003895
+	g_snprintf( name, sizeof( name ), "_%s._%s.%s", service, protocol, domain );
d4fdeea
+
5003895
+	len = res_query( name, C_IN, T_SRV, answer, PACKETSZ );
5003895
+	if( len == -1 )
5003895
+	{
5003895
+		goto fail;
5003895
+	}
d4fdeea
+
5003895
+	header = (HEADER *) answer;
5003895
+	p = answer + sizeof( HEADER );
5003895
+	end = answer + len;
d4fdeea
+
5003895
+	if( header->rcode != NOERROR )
5003895
+	{
5003895
+		goto fail;
5003895
+	}
d4fdeea
+
5003895
+	len = dn_skipname( p, end );
5003895
+	if( len == -1 )
5003895
+	{
5003895
+		goto fail;
5003895
+	}
5003895
+	p += len + QFIXEDSZ;
d4fdeea
+
5003895
+	count = ntohs( header->ancount );
d4fdeea
+
5003895
+	n = 0;
5003895
+	while( count-- > 0 && p < end )
5003895
+	{
5003895
+		len = dn_skipname( p, end );
5003895
+		if( len == -1 )
5003895
+		{
5003895
+			goto fail;
5003895
+		}
5003895
+		p += len;
d4fdeea
+
5003895
+		GETSHORT( type, p );
5003895
+		GETSHORT( class, p );
5003895
+		GETLONG( ttl, p );
5003895
+		GETSHORT( rdlength, p );
d4fdeea
+
5003895
+		if( type != T_SRV || class != C_IN )
5003895
+		{
5003895
+			p += rdlength;
5003895
+			continue;
5003895
+		}
d4fdeea
+
5003895
+		/* This is an overestimate of the needed size. */
5003895
+		reply = g_malloc( sizeof( struct ns_srv_reply ) + rdlength + 1 );
d4fdeea
+
5003895
+		GETSHORT( reply->prio, p );
5003895
+		GETSHORT( reply->weight, p );
5003895
+		GETSHORT( reply->port, p );
d4fdeea
+
5003895
+		len = dn_expand( answer, end, p, reply->name, rdlength + 1 );
5003895
+		if( len == -1 )
5003895
+		{
5003895
+			g_free( reply );
5003895
+			goto fail;
5003895
+		}
5003895
+		p += len;
d4fdeea
+
5003895
+		/* n + 2 includes an entry for the terminating NULL. */
5003895
+		results = g_renew( struct ns_srv_reply *, results, n + 2 );
5003895
+		results[n++] = reply;
5003895
+	}
d4fdeea
+
5003895
+	if( results != NULL )
5003895
+	{
5003895
+		results[n] = NULL;
d4fdeea
+
5003895
+		/* Order by priority. */
5003895
+		qsort( results, n, sizeof( struct ns_srv_reply * ), srv_compare );
5003895
+	}
d4fdeea
+
5003895
+	return results;
d4fdeea
+
d4fdeea
+fail:
5003895
+	if( results )
5003895
+	{
5003895
+		while( n-- > 0 )
5003895
+		{
5003895
+			g_free( results[n] );
5003895
+		}
5003895
+		g_free( results );
5003895
+	}
d4fdeea
+
5003895
+	return NULL;
4ce68a1
+}
4ce68a1
+
d4fdeea
 /* Word wrapping. Yes, I know this isn't UTF-8 clean. I'm willing to take the risk. */
d4fdeea
 char *word_wrap( const char *msg, int line_len )
d4fdeea
 {
5003895
@@ -783,3 +863,24 @@
d4fdeea
 	
5003895
 	return NULL;
d4fdeea
 }
4ce68a1
+
d4fdeea
+#ifdef TEST
5003895
+int main()
5003895
+{
5003895
+	struct ns_srv_reply **srv;
5003895
+	int i;
d4fdeea
+
5003895
+	srv = srv_lookup( "xmpp-client", "tcp", "jabber.org" );
5003895
+	for( i = 0; srv[i]; ++i )
5003895
+	{
5003895
+		printf( "priority=%hu\n", srv[i]->prio );
5003895
+		printf( "weight=%hu\n", srv[i]->weight );
5003895
+		printf( "port=%hu\n", srv[i]->port );
5003895
+		printf( "target=%s\n", srv[i]->name );
5003895
+		printf( "\n" );
5003895
+	}
5003895
+	srv_free( srv );
d4fdeea
+
5003895
+	return 0;
4ce68a1
+}
4ce68a1
+#endif /* TEST */