Blob Blame History Raw
Patch by Robert Scheck <robert@fedoraproject.org>, based on a patch by Matěj Cepl
<mcepl@redhat.com> for bitlbee >= 1.2, to avoid static linking to a private glibc
function, normally visible as libc.so.6(GLIBC_PRIVATE) in the binary RPM package.
Glibc >= 2.9 allows dynamic linking using -lresolv for ns_initparse()/ns_parserr(),
but Red Hat Enterprise Linux 4 and 5 (including derivates) are shipping older glibc
versions. A few more information and details regarding this patch are mentioned in
Red Hat Bugzilla ID #439047: https://bugzilla.redhat.com/show_bug.cgi?id=439047

--- bitlbee-1.2.7/configure			2010-04-19 15:10:03.000000000 +0200
+++ bitlbee-1.2.7/configure.libresolv		2010-04-25 14:52:00.000000000 +0200
@@ -19,7 +19,7 @@
 pidfile='/var/run/bitlbee.pid'
 ipcsocket='/var/run/bitlbee.sock'
 pcdir='$prefix/lib/pkgconfig'
-systemlibdirs="/lib /lib64 /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64"
+systemlibdirs="/lib64 /usr/lib64 /usr/local/lib64 /lib /usr/lib /usr/local/lib"
 
 msn=1
 jabber=1
@@ -313,10 +313,10 @@
 	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
--- bitlbee-1.2.7/lib/Makefile			2010-04-19 15:10:03.000000000 +0200
+++ bitlbee-1.2.7/lib/Makefile.libresolv	2010-04-25 14:52:00.000000000 +0200
@@ -9,7 +9,7 @@
 -include ../Makefile.settings
 
 # [SH] Program variables
-objects = arc.o base64.o $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o oauth.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o
+objects = arc.o base64.o $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o oauth.o proxy.o sha1.o srv.o $(SSL_CLIENT) url.o xmltree.o
 
 CFLAGS += -Wall
 LFLAGS += -r
--- bitlbee-1.2.7/lib/misc.c			2010-04-19 15:10:03.000000000 +0200
+++ bitlbee-1.2.7/lib/misc.c.libresolv		2010-04-25 14:58:57.000000000 +0200
@@ -44,6 +44,7 @@
 #ifdef HAVE_RESOLV_A
 #include <arpa/nameser.h>
 #include <resolv.h>
+#include <netinet/in.h>
 #endif
 
 #include "md5.h"
@@ -505,58 +506,6 @@
 	return 0;
 }
 
-struct ns_srv_reply *srv_lookup( char *service, char *protocol, char *domain )
-{	
-	struct ns_srv_reply *reply = NULL;
-#ifdef HAVE_RESOLV_A
-	char name[1024];
-	unsigned char querybuf[1024];
-	const unsigned char *buf;
-	ns_msg nsh;
-	ns_rr rr;
-	int i, 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;
-	
-	if( ns_parserr( &nsh, ns_s_an, 0, &rr ) != 0 )
-		return NULL;
-	
-	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 )
-		return NULL;
-	
-	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 );
-		return NULL;
-	}
-	
-	reply->prio = ( buf[0] << 8 ) | buf[1];
-	reply->weight = ( buf[2] << 8 ) | buf[3];
-	reply->port = ( buf[4] << 8 ) | buf[5];
-#endif
-	
-	return reply;
-}
-
 /* 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 )
 {
--- bitlbee-1.2.7/lib/misc.h			2010-04-19 15:10:03.000000000 +0200
+++ bitlbee-1.2.7/lib/misc.h.libresolv		2010-04-25 14:56:02.000000000 +0200
@@ -28,14 +28,7 @@
 
 #include <gmodule.h>
 #include <time.h>
-
-struct ns_srv_reply
-{
-	int prio;
-	int weight;
-	int port;
-	char name[];
-};
+#include "srv.h"
 
 G_MODULE_EXPORT void strip_linefeed( gchar *text );
 G_MODULE_EXPORT char *add_cr( char *text );
--- bitlbee-1.2.7/lib/srv.c			1970-01-01 01:00:00.000000000 +0100
+++ bitlbee-1.2.7/lib/srv.c.libresolv		2010-04-25 14:58:24.000000000 +0200
@@ -0,0 +1,249 @@
+/* srv.c - DNS SRV code
+ * Copyright (C) 2003 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUPG.
+ *
+ * GNUPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#undef TEST
+
+#ifdef TEST
+#define HAVE_RESOLV_A
+#endif
+
+#include <config.h>
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef HAVE_RESOLV_A
+# ifdef _WIN32
+#  include <windows.h>
+# else
+#  include <netinet/in.h>
+#  include <arpa/nameser.h>
+#  include <resolv.h>
+# endif /* !_WIN32 */
+#endif /* USE_DNS_SRV */
+
+#include "srv.h"
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <glib/gutils.h>
+
+/* Not every installation has gotten around to supporting SRVs yet...*/
+#ifndef T_SRV
+#define T_SRV 33
+#endif
+
+static int priosort(const void *a, const void *b) {
+	const struct ns_srv_reply *sa=a, *sb=b;
+	if (sa->prio>sb->prio)
+		return 1;
+	else if (sa->prio<sb->prio)
+		return -1;
+	else
+		return 0;
+}
+
+struct ns_srv_reply *srv_lookup(char *service, char *protocol, char *domain) {
+	struct ns_srv_reply *reply = NULL;
+	struct ns_srv_reply *list = NULL;
+	char name[1024];
+#ifdef HAVE_RESOLV_A
+	unsigned char answer[PACKETSZ];
+	int r, srvcount=0;
+	unsigned char *pt, *emsg;
+	int count, dlen;
+
+	g_snprintf(name, sizeof(name ), "_%s._%s.%s", service, protocol, domain);
+
+	_res.options |= RES_DEBUG;
+	
+	if ( res_init() != 0 ) 
+		return NULL;
+	
+	r=res_query(name, C_IN, T_SRV, answer, PACKETSZ);
+	
+	if (r<sizeof(HEADER) || r>PACKETSZ)
+		return NULL;
+
+	if ((((HEADER *)answer)->rcode)==NOERROR && (count=ntohs(((HEADER *)answer)->ancount))) {
+		int i, rc;
+
+		emsg=&answer[r]; /* end of message ??? */
+		pt=&answer[sizeof(HEADER)];
+
+		/* Skip over the query */
+		rc=dn_skipname(pt, emsg);
+		if (rc==-1)
+			goto fail;
+
+		pt+=rc+QFIXEDSZ;
+
+		while (count-->0 && pt<emsg) {
+			struct ns_srv_reply *srv=NULL;
+			int type, class;
+
+			list=g_realloc(list, (srvcount+1)*sizeof(struct ns_srv_reply));
+			memset(&list[srvcount], 0, sizeof(struct ns_srv_reply));
+			srv=&list[srvcount];
+			srvcount++;
+
+			rc=dn_skipname(pt, emsg); /* the name we just queried for */
+			if (rc==-1)
+				goto fail;
+			pt+=rc;
+
+			/* Truncated message? */
+			if ((emsg-pt)<16)
+				goto fail;
+
+			type=*pt++ << 8;
+			type|=*pt++;
+			/* We asked for SRV and got something else !? */
+			if (type!=T_SRV)
+				goto fail;
+
+			class=*pt++ << 8;
+			class|=*pt++;
+			/* We asked for IN and got something else !? */
+			if (class!=C_IN)
+				goto fail;
+
+			pt+=4; /* ttl */
+			dlen=*pt++ << 8;
+			dlen|=*pt++;
+			srv->prio=*pt++ << 8;
+			srv->prio|=*pt++;
+			srv->weight=*pt++ << 8;
+			srv->weight|=*pt++;
+			srv->port=*pt++ << 8;
+			srv->port|=*pt++;
+
+			/* Get the name.  2782 doesn't allow name compression, but
+			 dn_expand still works to pull the name out of the
+			 packet. */
+			rc=dn_expand(answer, emsg, pt, srv->name, MAXDNAME);
+			if (rc==1 && srv->name[0]==0) /* "." */
+				goto noanswer;
+			if (rc==-1)
+				goto fail;
+			pt+=rc;
+			/* Corrupt packet? */
+			if (dlen!=rc+6)
+				goto fail;
+		}
+
+		/* Now we have an array of all the srv records. */
+
+		/* Order by priority */
+		qsort(list, srvcount, sizeof(struct ns_srv_reply), priosort);
+
+		/* For each priority, move the zero-weighted items first. */
+		for (i=0; i<srvcount; i++) {
+			int j;
+
+			for (j=i; j<srvcount && list[i].prio==list[j].prio; j++) {
+				if (list[j].weight==0) {
+					/* Swap j with i */
+					if (j!=i) {
+						struct ns_srv_reply temp;
+
+						memcpy(&temp, &list[j], sizeof(struct ns_srv_reply));
+						memcpy(&list[j], &list[i], sizeof(struct ns_srv_reply));
+						memcpy(&list[i], &temp, sizeof(struct ns_srv_reply));
+					}
+
+					break;
+				}
+			}
+		}
+
+		/* Run the RFC-2782 weighting algorithm.  We don't need very
+		 high quality randomness for this, so regular libc srand/rand
+		 is sufficient. */
+		srand(time(NULL)*getpid());
+
+		for (i=0; i<srvcount; i++) {
+			int j;
+			float prio_count=0, chose;
+
+			for (j=i; j<srvcount && list[i].prio==list[j].prio; j++) {
+				prio_count+=list[j].weight;
+				list[j].run_count=prio_count;
+			}
+
+			chose=prio_count*rand()/RAND_MAX;
+
+			for (j=i; j<srvcount && list[i].prio==list[j].prio; j++) {
+				if (chose<=list[j].run_count) {
+					/* Swap j with i */
+					if (j!=i) {
+						struct ns_srv_reply temp;
+
+						memcpy(&temp, &list[j], sizeof(struct ns_srv_reply));
+						memcpy(&list[j], &list[i], sizeof(struct ns_srv_reply));
+						memcpy(&list[i], &temp, sizeof(struct ns_srv_reply));
+					}
+					break;
+				}
+			}
+		}
+	}
+
+	if (list == NULL)
+		return NULL;
+
+	/* TODO: bitlbee should expect a situation when more than one server
+	 * is available for the given SRV record.
+	 */
+	reply = g_malloc(sizeof(struct ns_srv_reply));
+	*reply = *list;
+	g_free(list);
+	/* list=NULL; */
+#endif /* HAVE_RESOLV_A */
+	return reply;
+
+	noanswer: g_free(list);
+	list=NULL;
+	return NULL;
+
+	fail: g_free(list);
+	list=NULL;
+	return NULL;
+}
+
+#ifdef TEST
+int main(int argc, char *argv[]) {
+	struct ns_srv_reply *srv;
+	/*int rc,i;*/
+
+	srv=srv_lookup("xmpp-client", "tcp", "jabber.org");
+	if (srv != NULL) {
+		printf("priority=%hu\n", srv->prio);
+		printf("weight=%hu\n", srv->weight);
+		printf("port=%hu\n", srv->port);
+		printf("target=%s\n", srv->name);
+		printf("\n");
+		g_free(srv);
+	}
+
+	return 0;
+}
+#endif /* TEST */
--- bitlbee-1.2.7/lib/srv.h			1970-01-01 01:00:00.000000000 +0100
+++ bitlbee-1.2.7/lib/srv.h.libresolv		2010-04-25 14:58:44.000000000 +0200
@@ -0,0 +1,38 @@
+/* srv.h
+ * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUPG.
+ *
+ * GNUPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_SRV_H
+#define GNUPG_COMMON_SRV_H
+
+#ifndef MAXDNAME
+#define MAXDNAME 1025
+#endif
+
+struct ns_srv_reply
+{
+	int prio; /* priority */
+	int weight; /* weight */
+	int port; /* port */
+	int run_count; /* from struct srventry at gnupg's common/srv.h */
+	char name[MAXDNAME]; /* target */
+};
+
+struct ns_srv_reply *srv_lookup(char *service, char *protocol, char *domain);
+
+#endif /*GNUPG_COMMON_SRV_H*/
--- bitlbee-1.2.7/Makefile			2010-04-19 15:10:03.000000000 +0200
+++ bitlbee-1.2.7/Makefile.libresolv		2010-04-25 14:52:00.000000000 +0200
@@ -10,7 +10,7 @@
 
 # Program variables
 objects = account.o bitlbee.o chat.o crypting.o help.o ipc.o irc.o irc_commands.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) user.o
-headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h user.h lib/events.h lib/http_client.h lib/ini.h lib/md5.h lib/misc.h lib/proxy.h lib/sha1.h lib/ssl_client.h lib/url.h protocols/nogaim.h
+headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h user.h lib/events.h lib/http_client.h lib/ini.h lib/md5.h lib/misc.h lib/proxy.h lib/sha1.h lib/srv.h lib/ssl_client.h lib/url.h protocols/nogaim.h
 subdirs = lib protocols
 
 ifeq ($(TARGET),i586-mingw32msvc)