Patch by Matěj Cepl for bitlbee >= 3.2 to avoid static linking to a private glibc function, that is 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 5 (including derivates) is shipping glibc 2.5. A few more information and details regarding this patch in Red Hat Bugzilla ID #439047: https://bugzilla.redhat.com/show_bug.cgi?id=439047 --- bitlbee-3.2.1/configure 2013-11-27 23:54:54.000000000 +0100 +++ bitlbee-3.2.1/configure.libresolv 2013-12-18 21:56:14.000000000 +0100 @@ -364,10 +364,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-3.2.1/lib/misc.c 2013-11-27 23:54:54.000000000 +0100 +++ bitlbee-3.2.1/lib/misc.c.libresolv 2013-12-18 22:10:45.000000000 +0100 --- bitlbee-3.2.1/lib/misc.c 2013-11-27 23:54:54.000000000 +0100 +++ bitlbee-3.2.1/lib/misc.c.libresolv.c 2013-12-18 22:18:29.000000000 +0100 @@ -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 #ifdef HAVE_RESOLV_A -#include #include #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 @@ 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,136 @@ 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 ); + + 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; + + /* n + 2 includes an entry for the terminating NULL. */ + results = g_renew( struct ns_srv_reply *, results, n + 2 ); + results[n++] = reply; + } + + if( results != NULL ) + { + 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 ) { @@ -783,3 +863,24 @@ return NULL; } + +#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 */