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..cf2083f 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,121 @@ 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); + + 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 ) { @@ -728,3 +793,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 */