diff options
author | jcopenha <jcopenha@typedef.org> | 2014-07-24 00:51:07 -0300 |
---|---|---|
committer | dequis <dx@dxzone.com.ar> | 2014-07-24 00:51:07 -0300 |
commit | 632627e1ead19fc7dc07effe441b2d543a675229 (patch) | |
tree | 84d8aac19b33ad72e1711a2a88ad6a7958c060ef | |
parent | 59e66ff766cbef04883c1d7477d66c7e9b515833 (diff) |
srv_lookup: Portability fixes, handle compressed responses
srv_lookup works on cygwin and openbsd now.
Provide ns_initparse, friends, and types where they aren't provided by
platform.
Use dn_expandname instead of custom parser so compressed DNS responses
are handled correctly.
-rwxr-xr-x | configure | 113 | ||||
-rw-r--r-- | lib/Makefile | 2 | ||||
-rw-r--r-- | lib/misc.c | 27 | ||||
-rw-r--r-- | lib/misc.h | 81 | ||||
-rw-r--r-- | lib/ns_parse.c | 217 |
5 files changed, 421 insertions, 19 deletions
@@ -340,6 +340,34 @@ RESOLV_TESTCODE=' int main() { + + res_query( NULL, 0, 0, NULL, 0); + dn_expand( NULL, NULL, NULL, NULL, 0); + dn_skipname( NULL, NULL); +} +' +RESOLV_NS_TESTCODE=' +#include <sys/types.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <resolv.h> + +int main() +{ + ns_initparse( NULL, 0, NULL ); + ns_parserr( NULL, ns_s_an, 0, NULL ); +} +' +RESOLV_NS_TYPES_TESTCODE=' +#include <sys/types.h> +#include <netinet/in.h> +#include <arpa/nameser.h> + +int main() +{ + ns_msg nsh; + ns_rr rr; + ns_initparse( NULL, 0, NULL ); ns_parserr( NULL, ns_s_an, 0, NULL ); } @@ -348,8 +376,14 @@ int main() detect_resolv_dynamic() { case "$arch" in + OpenBSD ) + # In FreeBSD res_*/dn_* routines are present in libc.so + LIBRESOLV=;; FreeBSD ) - # In FreeBSD res_* routines are present in libc.so + # In FreeBSD res_*/dn_* routines are present in libc.so + LIBRESOLV=;; + CYGWIN* ) + # In Cygwin res_*/dn_* routines are present in libc.so LIBRESOLV=;; * ) LIBRESOLV=-lresolv;; @@ -384,6 +418,74 @@ detect_resolv_static() return $ret } +detect_resolv_ns_dynamic() +{ + case "$arch" in + FreeBSD ) + # In FreeBSD ns_ routines are present in libc.so + LIBRESOLV=;; + * ) + LIBRESOLV=-lresolv;; + esac + TMPFILE=$(mktemp /tmp/bitlbee-configure.XXXXXX) + ret=1 + echo "$RESOLV_NS_TESTCODE" | $CC -o $TMPFILE -x c - $LIBRESOLV >/dev/null 2>/dev/null + if [ "$?" = "0" ]; then + ret=0 + fi + + rm -f $TMPFILE + return $ret +} + +detect_resolv_ns_static() +{ + TMPFILE=$(mktemp /tmp/bitlbee-configure.XXXXXX) + ret=1 + for i in $systemlibdirs; do + if [ -f $i/libresolv.a ]; then + echo "$RESOLV_NS_TESTCODE" | $CC -o $TMPFILE -x c - -Wl,$i/libresolv.a >/dev/null 2>/dev/null + if [ "$?" = "0" ]; then + ret=0 + fi + fi + done + + rm -f $TMPFILE + return $ret +} + +detect_nameser_has_ns_types() +{ + TMPFILE=$(mktemp /tmp/bitlbee-configure.XXXXXX) + case "$arch" in + FreeBSD ) + # In FreeBSD ns_ routines are present in libc.so + LIBRESOLV=;; + * ) + LIBRESOLV=-lresolv;; + esac + ret=1 + if detect_resolv_ns_dynamic; then + echo "$RESOLV_NS_TYPES_TESTCODE" | $CC -o $TMPFILE -x c $LIBRESOLV - >/dev/null 2>/dev/null + if [ "$?" = "0" ]; then + ret=0 + fi + elif detect_resolv_ns_static; then + for i in $systemlibdirs; do + if [ -f $i/libresolv.a ]; then + echo "$RESOLV_NS_TYPES_TESTCODE" | $CC -o $TMPFILE -x c - >/dev/null 2>/dev/null + if [ "$?" = "0" ]; then + ret=0 + fi + fi + done + fi + + rm -f $TMPFILE + return $ret +} + if [ "$ssl" = "auto" ]; then detect_gnutls if [ "$ret" = "0" ]; then @@ -439,10 +541,19 @@ fi; echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings +if detect_nameser_has_ns_types; then + echo '#define NAMESER_HAS_NS_TYPES' >> config.h +fi if detect_resolv_dynamic || detect_resolv_static; then echo '#define HAVE_RESOLV_A' >> config.h + if detect_resolv_ns_dynamic || detect_resolv_ns_static; then + echo '#define HAVE_RESOLV_A_WITH_NS' >> config.h + fi +else + echo 'Insufficient resolv routines. Jabber server must be set explicitly' fi + STORAGES="xml" for i in $STORAGES; do diff --git a/lib/Makefile b/lib/Makefile index f20b3797..40c03215 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -12,7 +12,7 @@ _SRCDIR_ := $(_SRCDIR_)lib/ endif # [SH] Program variables -objects = arc.o base64.o $(EVENT_HANDLER) ftutil.o http_client.o ini.o json.o json_util.o md5.o misc.o oauth.o oauth2.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o +objects = arc.o base64.o $(EVENT_HANDLER) ftutil.o http_client.o ini.o json.o json_util.o md5.o misc.o oauth.o oauth2.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o ns_parse.o LFLAGS += -r @@ -524,7 +524,7 @@ struct ns_srv_reply **srv_lookup( char *service, char *protocol, char *domain ) const unsigned char *buf; ns_msg nsh; ns_rr rr; - int i, n, len, size; + int n, len, size; g_snprintf( name, sizeof( name ), "_%s._%s.%s", service, protocol, domain ); @@ -537,27 +537,20 @@ struct ns_srv_reply **srv_lookup( char *service, char *protocol, char *domain ) n = 0; while( ns_parserr( &nsh, ns_s_an, n, &rr ) == 0 ) { - size = ns_rr_rdlen( rr ); + char name[NS_MAXDNAME]; + + if( ns_rr_rdlen( rr ) < 7) + break; + 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 ) + if( dn_expand(querybuf, querybuf + size, &buf[6], name, NS_MAXDNAME) == -1 ) break; + + len = strlen(name) + 1; 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; - } + memcpy( reply->name, name, len ); reply->prio = ( buf[0] << 8 ) | buf[1]; reply->weight = ( buf[2] << 8 ) | buf[3]; @@ -37,6 +37,87 @@ struct ns_srv_reply char name[]; }; +#ifndef NAMESER_HAS_NS_TYPES + +#define NS_MAXDNAME 1025 +#define NS_INT16SZ 2 +#define NS_INT32SZ 4 + +#define NS_GET16(s, cp) do { \ + register const unsigned char *t_cp = (const unsigned char*)(cp); \ + (s) = ((guint16)t_cp[0] << 8) \ + | ((guint16)t_cp[1]) \ + ; \ + (cp) += NS_INT16SZ; \ +} while(0) + +#define NS_GET32(s, cp) do { \ + register const unsigned char *t_cp = (const unsigned char*)(cp); \ + (s) = ((guint16)t_cp[0] << 24) \ + | ((guint16)t_cp[1] << 16) \ + | ((guint16)t_cp[2] << 8) \ + | ((guint16)t_cp[3]) \ + ; \ + (cp) += NS_INT32SZ; \ +} while(0) + +#define ns_rr_rdlen(rr) ((rr).rdlength + 0) +#define ns_rr_rdata(rr) ((rr).rdata + 0) + +struct _ns_flagdata { int mask, shift; }; + +typedef struct __ns_rr { + char name[NS_MAXDNAME]; + guint16 type; + guint16 rr_class; + guint32 ttl; + guint16 rdlength; + const unsigned char* rdata; +} ns_rr; + +typedef enum __ns_sect { + ns_s_qd = 0, + ns_s_zn = 0, + ns_s_an = 1, + ns_s_pr = 1, + ns_s_ns = 2, + ns_s_ud = 2, + ns_s_ar = 3, + ns_s_max =4 +} ns_sect; + +typedef struct __ns_msg +{ + const unsigned char* _msg; + const unsigned char* _eom; + guint16 _id; + guint16 _flags; + guint16 _counts[ns_s_max]; + const unsigned char* _sections[ns_s_max]; + ns_sect _sect; + int _rrnum; + const unsigned char* _msg_ptr; +} ns_msg; + +typedef enum __ns_class { + ns_c_invalid = 0, + ns_c_in = 1, + ns_c_2 = 2, + ns_c_chaos = 3, + ns_c_hs = 4, + ns_c_none = 254, + ns_c_any = 255, + ns_c_max = 65536 +} ns_class; + + +/* TODO : fill out the rest */ +typedef enum __ns_type { + ns_t_srv = 33 +} ns_type; + +#endif /* NAMESER_HAS_NS_INITPARSE */ + G_MODULE_EXPORT void strip_linefeed( gchar *text ); G_MODULE_EXPORT char *add_cr( char *text ); G_MODULE_EXPORT char *strip_newlines(char *source); diff --git a/lib/ns_parse.c b/lib/ns_parse.c new file mode 100644 index 00000000..ba45d513 --- /dev/null +++ b/lib/ns_parse.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "bitlbee.h" + +#ifndef lint +static const char rcsid[] = "$Id: ns_parse.c,v 1.10 2009/01/23 19:59:16 each Exp $"; +#endif + +#ifdef HAVE_RESOLV_A +#ifndef HAVE_RESOLV_A_WITH_NS +/* Import. */ + + +#include <sys/types.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> + +#include <errno.h> +#include <resolv.h> +#include <string.h> + + +/* Forward. */ + +static void setsection(ns_msg *msg, ns_sect sect); + +/* Macros. */ + +#if !defined(SOLARIS2) || defined(__COVERITY__) +#define RETERR(err) do { errno = (err); return (-1); } while (0) +#else +#define RETERR(err) \ + do { errno = (err); if (errno == errno) return (-1); } while (0) +#endif + +#define PARSE_FMT_PRESO 0 /* Parse using presentation-format names */ +#define PARSE_FMT_WIRE 1 /* Parse using network-format names */ + +/* Public. */ + +/* These need to be in the same order as the nres.h:ns_flag enum. */ +struct _ns_flagdata _ns_flagdata[16] = { + { 0x8000, 15 }, /*%< qr. */ + { 0x7800, 11 }, /*%< opcode. */ + { 0x0400, 10 }, /*%< aa. */ + { 0x0200, 9 }, /*%< tc. */ + { 0x0100, 8 }, /*%< rd. */ + { 0x0080, 7 }, /*%< ra. */ + { 0x0040, 6 }, /*%< z. */ + { 0x0020, 5 }, /*%< ad. */ + { 0x0010, 4 }, /*%< cd. */ + { 0x000f, 0 }, /*%< rcode. */ + { 0x0000, 0 }, /*%< expansion (1/6). */ + { 0x0000, 0 }, /*%< expansion (2/6). */ + { 0x0000, 0 }, /*%< expansion (3/6). */ + { 0x0000, 0 }, /*%< expansion (4/6). */ + { 0x0000, 0 }, /*%< expansion (5/6). */ + { 0x0000, 0 }, /*%< expansion (6/6). */ +}; + +int ns_msg_getflag(ns_msg handle, int flag) { + return(((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift); +} + +int +ns_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) { + const u_char *optr = ptr; + + for ((void)NULL; count > 0; count--) { + int b, rdlength; + + b = dn_skipname(ptr, eom); + if (b < 0) + RETERR(EMSGSIZE); + ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/; + if (section != ns_s_qd) { + if (ptr + NS_INT32SZ + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + ptr += NS_INT32SZ/*TTL*/; + NS_GET16(rdlength, ptr); + ptr += rdlength/*RData*/; + } + } + if (ptr > eom) + RETERR(EMSGSIZE); + return (ptr - optr); +} + +int +ns_initparse(const u_char *msg, int msglen, ns_msg *handle) { + const u_char *eom = msg + msglen; + int i; + + handle->_msg = msg; + handle->_eom = eom; + if (msg + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + NS_GET16(handle->_id, msg); + if (msg + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + NS_GET16(handle->_flags, msg); + for (i = 0; i < ns_s_max; i++) { + if (msg + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + NS_GET16(handle->_counts[i], msg); + } + for (i = 0; i < ns_s_max; i++) + if (handle->_counts[i] == 0) + handle->_sections[i] = NULL; + else { + int b = ns_skiprr(msg, eom, (ns_sect)i, + handle->_counts[i]); + + if (b < 0) + return (-1); + handle->_sections[i] = msg; + msg += b; + } + if (msg != eom) + RETERR(EMSGSIZE); + setsection(handle, ns_s_max); + return (0); +} + +int +ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) { + int b; + int tmp; + + /* Make section right. */ + tmp = section; + if (tmp < 0 || section >= ns_s_max) + RETERR(ENODEV); + if (section != handle->_sect) + setsection(handle, section); + + /* Make rrnum right. */ + if (rrnum == -1) + rrnum = handle->_rrnum; + if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) + RETERR(ENODEV); + if (rrnum < handle->_rrnum) + setsection(handle, section); + if (rrnum > handle->_rrnum) { + b = ns_skiprr(handle->_msg_ptr, handle->_eom, section, + rrnum - handle->_rrnum); + + if (b < 0) + return (-1); + handle->_msg_ptr += b; + handle->_rrnum = rrnum; + } + + /* Do the parse. */ + b = dn_expand(handle->_msg, handle->_eom, + handle->_msg_ptr, rr->name, NS_MAXDNAME); + if (b < 0) + return (-1); + handle->_msg_ptr += b; + if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) + RETERR(EMSGSIZE); + NS_GET16(rr->type, handle->_msg_ptr); + NS_GET16(rr->rr_class, handle->_msg_ptr); + if (section == ns_s_qd) { + rr->ttl = 0; + rr->rdlength = 0; + rr->rdata = NULL; + } else { + if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) + RETERR(EMSGSIZE); + NS_GET32(rr->ttl, handle->_msg_ptr); + NS_GET16(rr->rdlength, handle->_msg_ptr); + if (handle->_msg_ptr + rr->rdlength > handle->_eom) + RETERR(EMSGSIZE); + rr->rdata = handle->_msg_ptr; + handle->_msg_ptr += rr->rdlength; + } + if (++handle->_rrnum > handle->_counts[(int)section]) + setsection(handle, (ns_sect)((int)section + 1)); + + /* All done. */ + return (0); +} + +/* Private. */ + +static void +setsection(ns_msg *msg, ns_sect sect) { + msg->_sect = sect; + if (sect == ns_s_max) { + msg->_rrnum = -1; + msg->_msg_ptr = NULL; + } else { + msg->_rrnum = 0; + msg->_msg_ptr = msg->_sections[(int)sect]; + } +} + +/*! \file */ +#endif +#endif |