On Thu, Jul 7, 2011 at 12:04 PM, Daniel Mack <[email protected]> wrote:
> Ok. Would it be an option then to add it? Reading the guidelines of
> this project, I'm not sure whether support for this functions are
> wanted at all because at least the implemenations found in NetBDS's
> libc is not particularily small. What's the verdict here? Can things
> be added as long as they're build conditionally? Are there any
> alternative aproaches to achive support for these functions? I'm sure
> connman is not the only program that fails to link against uClibc due
> to this.

No opinions? So I dare to propose an implementation :)

Attached is patch that is not yet meant for inclusion but for RFC
only. I can split it up into multiple smaller pieces once I know that
it's basically ok.

Some parts of the patch move symbols from libc to libresolv, according
to the header files they're defined in and also to bring it in sync
with what glibc does.

Also, I haven't done a lot of testing yet, and major parts are just
copied over from NetBSD's libc implementation and amended according to
uClibc's internals.

Please let me know what you think.


Thanks,
Daniel
diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in
index 2fa0b07..585d330 100644
--- a/extra/Configs/Config.in
+++ b/extra/Configs/Config.in
@@ -1296,11 +1296,11 @@ config UCLIBC_HAS_EXTRA_COMPAT_RES_STATE
 	  Answer Y if selecting UCLIBC_HAS_COMPAT_RES_STATE is not enough.
 	  As far as I can say, this should never be needed.
 
-config UCLIBC_HAS_LIBRESOLV_STUB
-	bool "Provide libresolv stub"
+config UCLIBC_HAS_LIBRESOLV
+	bool "Provide basic libresolv implementation"
 	default n
 	help
-	  Provide a dummy resolv library.
+	  Provide a resolv library.
 
 config UCLIBC_HAS_LIBNSL_STUB
 	bool "Provide libnsl stub"
diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h
index 917ba19..b621eab 100644
--- a/include/arpa/nameser.h
+++ b/include/arpa/nameser.h
@@ -500,13 +500,20 @@ typedef enum __ns_cert_types {
 
 __BEGIN_DECLS
 u_int		ns_get16 (const u_char *) __THROW;
+libresolv_hidden_proto(ns_get16)
 u_long		ns_get32 (const u_char *) __THROW;
+libresolv_hidden_proto(ns_get32)
 void		ns_put16 (u_int, u_char *) __THROW;
+libresolv_hidden_proto(ns_put16)
 void		ns_put32 (u_long, u_char *) __THROW;
+libresolv_hidden_proto(ns_put32)
 int		ns_initparse (const u_char *, int, ns_msg *) __THROW;
+libresolv_hidden_proto(ns_initparse)
 int		ns_skiprr (const u_char *, const u_char *, ns_sect, int)
      __THROW;
+libresolv_hidden_proto(ns_skiprr)
 int		ns_parserr (ns_msg *, ns_sect, int, ns_rr *) __THROW;
+libresolv_hidden_proto(ns_parserr)
 int		ns_sprintrr (const ns_msg *, const ns_rr *,
 			     const char *, const char *, char *, size_t)
      __THROW;
@@ -519,19 +526,23 @@ int		ns_parse_ttl (const char *, u_long *) __THROW;
 u_int32_t	ns_datetosecs (const char *cp, int *errp) __THROW;
 int		ns_name_ntol (const u_char *, u_char *, size_t) __THROW;
 int		ns_name_ntop (const u_char *, char *, size_t) __THROW;
-libc_hidden_proto(ns_name_ntop)
+libresolv_hidden_proto(ns_name_ntop)
 int		ns_name_pton (const char *, u_char *, size_t) __THROW;
+libresolv_hidden_proto(ns_name_pton)
 int		ns_name_unpack (const u_char *, const u_char *,
 				const u_char *, u_char *, size_t) __THROW;
-libc_hidden_proto(ns_name_unpack)
+libresolv_hidden_proto(ns_name_unpack)
 int		ns_name_pack (const u_char *, u_char *, int,
 			      const u_char **, const u_char **) __THROW;
+libresolv_hidden_proto(ns_name_pack)
 int		ns_name_uncompress (const u_char *, const u_char *,
 				    const u_char *, char *, size_t) __THROW;
-libc_hidden_proto(ns_name_uncompress)
+libresolv_hidden_proto(ns_name_uncompress)
 int		ns_name_compress (const char *, u_char *, size_t,
 				  const u_char **, const u_char **) __THROW;
+libresolv_hidden_proto(ns_name_compress)
 int		ns_name_skip (const u_char **, const u_char *) __THROW;
+libresolv_hidden_proto(ns_name_skip)
 void		ns_name_rollback (const u_char *, const u_char **,
 				  const u_char **) __THROW;
 int		ns_sign (u_char *, int *, int, int, void *,
diff --git a/include/resolv.h b/include/resolv.h
index cba26f0..9a01173 100644
--- a/include/resolv.h
+++ b/include/resolv.h
@@ -292,8 +292,8 @@ __END_DECLS
 #define res_init		__res_init
 #if 0
 #define res_isourserver		__res_isourserver
-#define res_mkquery		__res_mkquery
 #endif
+#define res_mkquery		__res_mkquery
 #define res_query		__res_query
 #define res_querydomain		__res_querydomain
 #define res_search		__res_search
@@ -312,17 +312,18 @@ void		p_query (const u_char *) __THROW;
 void		res_close (void) __THROW;
 #endif
 int		res_init (void) __THROW;
-libc_hidden_proto(res_init)
+libresolv_hidden_proto(res_init)
 #if 0
 int		res_isourserver (const struct sockaddr_in *) __THROW;
+#endif
 int		res_mkquery (int, const char *, int, int, const u_char *,
 			     int, const u_char *, u_char *, int) __THROW;
-#endif
+libresolv_hidden_proto(res_mkquery)
 int		res_query (const char *, int, int, u_char *, int) __THROW;
-libc_hidden_proto(res_query)
+libresolv_hidden_proto(res_query)
 int		res_querydomain (const char *, const char *, int, int,
 				 u_char *, int) __THROW;
-libc_hidden_proto(res_querydomain)
+libresolv_hidden_proto(res_querydomain)
 int		res_search (const char *, int, int, u_char *, int) __THROW;
 #if 0
 int		res_send (const u_char *, int, u_char *, int) __THROW;
@@ -332,12 +333,13 @@ __END_DECLS
 #if 0
 #define b64_ntop		__b64_ntop
 #define b64_pton		__b64_pton
-#define dn_comp			__dn_comp
 #define dn_count_labels		__dn_count_labels
 #endif
+#define dn_comp			__dn_comp
 #define dn_expand		__dn_expand
-#if 0
+#define res_nmkquery		__res_nmkquery
 #define dn_skipname		__dn_skipname
+#if 0
 #define fp_resstat		__fp_resstat
 #define loc_aton		__loc_aton
 #define loc_ntoa		__loc_ntoa
@@ -361,7 +363,6 @@ __END_DECLS
 #define res_nameinquery		__res_nameinquery
 #define res_nclose		__res_nclose
 #define res_ninit		__res_ninit
-#define res_nmkquery		__res_nmkquery
 #define res_npquery		__res_npquery
 #define res_nquery		__res_nquery
 #define res_nquerydomain	__res_nquerydomain
@@ -388,7 +389,6 @@ int		b64_ntop (u_char const *, size_t, char *, size_t) __THROW;
 int		b64_pton (char const *, u_char *, size_t) __THROW;
 int		loc_aton (const char *ascii, u_char *binary) __THROW;
 const char *	loc_ntoa (const u_char *binary, char *ascii) __THROW;
-int		dn_skipname (const u_char *, const u_char *) __THROW;
 void		putlong (u_int32_t, u_char *) __THROW;
 void		putshort (u_int16_t, u_char *) __THROW;
 const char *	p_class (int) __THROW;
@@ -404,11 +404,17 @@ const u_char *	p_fqname (const u_char *, const u_char *, FILE *) __THROW;
 const char *	p_option (u_long option) __THROW;
 char *		p_secstodate (u_long) __THROW;
 int		dn_count_labels (const char *) __THROW;
+#endif
 int		dn_comp (const char *, u_char *, int, u_char **, u_char **)
      __THROW;
-#endif
+libc_hidden_proto(dn_comp)
+int		dn_skipname (const u_char *, const u_char *) __THROW;
+libc_hidden_proto(dn_skipname)
 int		dn_expand (const u_char *, const u_char *, const u_char *,
 			   char *, int) __THROW;
+int		res_nmkquery (res_state, int, const char *, int, int,
+			      const u_char *, int, const u_char *, u_char *,
+			      int) __THROW;
 #if 0
 u_int		res_randomid (void) __THROW;
 int		res_nameinquery (const char *, int, int,
@@ -431,9 +437,6 @@ int		res_nsearch (res_state, const char *, int, int, u_char *, int)
      __THROW;
 int		res_nquerydomain (res_state, const char *, const char *, int,
 				  int, u_char *, int) __THROW;
-int		res_nmkquery (res_state, int, const char *, int, int,
-			      const u_char *, int, const u_char *, u_char *,
-			      int) __THROW;
 int		res_nsend (res_state, const u_char *, int, u_char *, int)
      __THROW;
 void		res_nclose (res_state) __THROW;
diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c
index dc8a752..817bb7c 100644
--- a/libc/inet/resolv.c
+++ b/libc/inet/resolv.c
@@ -2708,7 +2708,7 @@ int ns_name_uncompress(const u_char *msg, const u_char *eom,
 		return -1;
 	return n;
 }
-libc_hidden_def(ns_name_uncompress)
+libresolv_hidden_def(ns_name_uncompress)
 
 /*
  * ns_name_ntop(src, dst, dstsiz)
@@ -2790,7 +2790,7 @@ int ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
 	*dn++ = '\0';
 	return (dn - dst);
 }
-libc_hidden_def(ns_name_ntop)
+libresolv_hidden_def(ns_name_ntop)
 
 /*
  * ns_name_unpack(msg, eom, src, dst, dstsiz)
@@ -2865,7 +2865,7 @@ int ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
 		len = srcp - src;
 	return len;
 }
-libc_hidden_def(ns_name_unpack)
+libresolv_hidden_def(ns_name_unpack)
 #endif /* L_ns_name */
 
 
@@ -2995,7 +2995,7 @@ int res_init(void)
 	__UCLIBC_MUTEX_UNLOCK(__resolv_lock);
 	return 0;
 }
-libc_hidden_def(res_init)
+libresolv_hidden_def(res_init)
 
 #ifdef __UCLIBC_HAS_BSD_RES_CLOSE__
 void res_close(void)
@@ -3107,7 +3107,7 @@ int res_query(const char *dname, int class, int type,
 	free(packet);
 	return i;
 }
-libc_hidden_def(res_query)
+libresolv_hidden_def(res_query)
 
 /*
  * Formulate a normal query, send, and retrieve answer in supplied buffer.
@@ -3323,10 +3323,665 @@ int res_querydomain(const char *name, const char *domain, int class, int type,
 	}
 	return res_query(longname, class, type, answer, anslen);
 }
-libc_hidden_def(res_querydomain)
+libresolv_hidden_def(res_querydomain)
+
+
+#define NS_TYPE_ELT					0x40 /*%< EDNS0 extended label type */
+#define DNS_LABELTYPE_BITSTRING		0x41
+
+static int labellen(const unsigned char *lp)
+{
+	int bitlen;
+	unsigned char l = *lp;
+
+	if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+		/* should be avoided by the caller */
+		return -1;
+	}
+
+	if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
+		if (l == DNS_LABELTYPE_BITSTRING) {
+			if ((bitlen = *(lp + 1)) == 0)
+				bitlen = 256;
+			return ((bitlen + 7 ) / 8 + 1);
+		}
+
+		return -1;    /*%< unknwon ELT */
+	}
+
+	return l;
+}
+
+static int mklower(int ch) {
+	if (ch >= 0x41 && ch <= 0x5A)
+		return (ch + 0x20);
+
+	return (ch);
+}
+
+static int dn_find(const unsigned char *domain,
+				   const unsigned char *msg,
+				   const unsigned char * const *dnptrs,
+				   const unsigned char * const *lastdnptr)
+{
+	const unsigned char *dn, *cp, *sp;
+	const unsigned char * const *cpp;
+	u_int n;
+
+	for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
+		sp = *cpp;
+		/*
+		 * terminate search on:
+		 * root label
+		 * compression pointer
+		 * unusable offset
+		 */
+		while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
+				(sp - msg) < 0x4000) {
+			dn = domain;
+			cp = sp;
+
+			while ((n = *cp++) != 0) {
+				/*
+				 * check for indirection
+				 */
+				switch (n & NS_CMPRSFLGS) {
+				case 0:	 /*%< normal case, n == len */
+					n = labellen(cp - 1); /*%< XXX */
+					if (n != *dn++)
+						goto next;
+
+					for (; n > 0; n--)
+						if (mklower(*dn++) !=
+						    mklower(*cp++))
+							goto next;
+					/* Is next root for both ? */
+					if (*dn == '\0' && *cp == '\0')
+						return (sp - msg);
+					if (*dn)
+						continue;
+					goto next;
+				case NS_CMPRSFLGS:      /*%< indirection */
+					cp = msg + (((n & 0x3f) << 8) | *cp);
+					break;
+
+				default:	/*%< illegal type */
+					errno = EMSGSIZE;
+					return -1;
+				}
+			}
+next:
+			sp += *sp + 1;
+		}
+	}
+
+	errno = ENOENT;
+	return -1;
+}
+
+static const char       digits[] = "0123456789";
+
+static const char digitvalue[256] = {
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
+	 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1, /*64*/
+	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
+	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
+};
+
+static int encode_bitsring(const char **bp, const char *end,
+						   unsigned char **labelp,
+						   unsigned char ** dst,
+						   unsigned const char *eom)
+{
+	int afterslash = 0;
+	const char *cp = *bp;
+	unsigned char *tp;
+	char c;
+	const char *beg_blen;
+	char *end_blen = NULL;
+	int value = 0, count = 0, tbcount = 0, blen = 0;
+
+	beg_blen = end_blen = NULL;
+
+	/* a bitstring must contain at least 2 characters */
+	if (end - cp < 2)
+		return (EINVAL);
+
+	/* XXX: currently, only hex strings are supported */
+	if (*cp++ != 'x')
+		return (EINVAL);
+	if (!isxdigit((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */
+		return (EINVAL);
+
+	for (tp = *dst + 1; cp < end && tp < eom; cp++) {
+		switch((c = *cp)) {
+		case ']':       /*%< end of the bitstring */
+			if (afterslash) {
+				if (beg_blen == NULL)
+					return (EINVAL);
+				blen = (int)strtol(beg_blen, &end_blen, 10);
+				if (*end_blen != ']')
+					return (EINVAL);
+			}
+			if (count)
+				*tp++ = ((value << 4) & 0xff);
+			cp++;   /*%< skip ']' */
+			goto done;
+		case '/':
+			afterslash = 1;
+			break;
+		default:
+			if (afterslash) {
+				if (!isdigit(c&0xff))
+					return (EINVAL);
+				if (beg_blen == NULL) {
+
+					if (c == '0') {
+						/* blen never begings with 0 */
+						return (EINVAL);
+					}
+					beg_blen = cp;
+				}
+			} else {
+				if (!isxdigit(c&0xff))
+					return (EINVAL);
+				value <<= 4;
+				value += digitvalue[(int)c];
+				count += 4;
+				tbcount += 4;
+				if (tbcount > 256)
+					return (EINVAL);
+				if (count == 8) {
+					*tp++ = value;
+					count = 0;
+				}
+			}
+			break;
+		}
+	}
+  done:
+	if (cp >= end || tp >= eom)
+		return (EMSGSIZE);
+
+	/*
+	 * bit length validation:
+	 * If a <length> is present, the number of digits in the <bit-data>
+	 * MUST be just sufficient to contain the number of bits specified
+	 * by the <length>. If there are insignificant bits in a final
+	 * hexadecimal or octal digit, they MUST be zero.
+	 * RFC2673, Section 3.2.
+	 */
+	if (blen > 0) {
+		int traillen;
+
+		if (((blen + 3) & ~3) != tbcount)
+			return (EINVAL);
+		traillen = tbcount - blen; /*%< between 0 and 3 */
+		if (((value << (8 - traillen)) & 0xff) != 0)
+			return (EINVAL);
+	}
+	else
+		blen = tbcount;
+	if (blen == 256)
+		blen = 0;
+
+	/* encode the type and the significant bit fields */
+	**labelp = DNS_LABELTYPE_BITSTRING;
+	**dst = blen;
+
+	*bp = cp;
+	*dst = tp;
+
+	return (0);
+}
+
+int ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
+{
+	u_char *label, *bp, *eom;
+	int c, n, escaped, e = 0;
+	char *cp;
+
+	escaped = 0;
+	bp = dst;
+	eom = dst + dstsiz;
+	label = bp++;
+
+	while ((c = *src++) != 0) {
+		if (escaped) {
+			if (c == '[') { /*%< start a bit string label */
+				if ((cp = strchr(src, ']')) == NULL) {
+					errno = EINVAL; /*%< ??? */
+					return (-1);
+				}
+				if ((e = encode_bitsring(&src, cp + 2,
+							 &label, &bp, eom))
+				    != 0) {
+					errno = e;
+					return (-1);
+				}
+				escaped = 0;
+				label = bp++;
+				if ((c = *src++) == 0)
+					goto done;
+				else if (c != '.') {
+					errno = EINVAL;
+					return  (-1);
+				}
+				continue;
+			}
+			else if ((cp = strchr(digits, c)) != NULL) {
+				n = (cp - digits) * 100;
+				if ((c = *src++) == 0 ||
+				    (cp = strchr(digits, c)) == NULL) {
+					errno = EMSGSIZE;
+					return (-1);
+				}
+				n += (cp - digits) * 10;
+				if ((c = *src++) == 0 ||
+				    (cp = strchr(digits, c)) == NULL) {
+					errno = EMSGSIZE;
+					return (-1);
+				}
+				n += (cp - digits);
+				if (n > 255) {
+					errno = EMSGSIZE;
+					return (-1);
+				}
+				c = n;
+			}
+			escaped = 0;
+		} else if (c == '\\') {
+			escaped = 1;
+			continue;
+		} else if (c == '.') {
+			c = (bp - label - 1);
+			if ((c & NS_CMPRSFLGS) != 0) {  /*%< Label too big. */
+				errno = EMSGSIZE;
+				return (-1);
+			}
+			if (label >= eom) {
+				errno = EMSGSIZE;
+				return (-1);
+			}
+		       *label = c;
+			/* Fully qualified ? */
+			if (*src == '\0') {
+				if (c != 0) {
+					if (bp >= eom) {
+						errno = EMSGSIZE;
+						return (-1);
+					}
+					*bp++ = '\0';
+				}
+				if ((bp - dst) > MAXCDNAME) {
+					errno = EMSGSIZE;
+					return (-1);
+				}
+
+				return (1);
+			}
+			if (c == 0 || *src == '.') {
+				errno = EMSGSIZE;
+				return (-1);
+			}
+			label = bp++;
+			continue;
+		}
+		if (bp >= eom) {
+			errno = EMSGSIZE;
+			return (-1);
+		}
+		*bp++ = (u_char)c;
+	}
+	c = (bp - label - 1);
+	if ((c & NS_CMPRSFLGS) != 0) {	  /*%< Label too big. */
+		errno = EMSGSIZE;
+		return (-1);
+	}
+  done:
+	if (label >= eom) {
+		errno = EMSGSIZE;
+		return (-1);
+	}
+	*label = c;
+	if (c != 0) {
+		if (bp >= eom) {
+			errno = EMSGSIZE;
+			return (-1);
+		}
+		*bp++ = 0;
+	}
+	if ((bp - dst) > MAXCDNAME) {   /*%< src too big */
+		errno = EMSGSIZE;
+		return (-1);
+	}
+
+	return (0);
+}
+
+int res_mkquery(int op, const char *dname, int class, int type,
+				const unsigned char *data, int datalen,
+				const unsigned char *newrr_in,
+				unsigned char *buf, int buflen)
+{
+	HEADER *hp;
+	unsigned char *cp, *ep;
+	unsigned char *dnptrs[20], **dpp, **lastdnptr;
+	int n;
+#ifdef DEBUG
+	uint32_t _res_options;
+#endif
+
+	if (!buf || buflen < HFIXEDSZ) {
+		h_errno = NETDB_INTERNAL;
+		return -1;
+	}
+
+#ifdef DEBUG
+ again:
+	__UCLIBC_MUTEX_LOCK(__resolv_lock);
+	_res_options = _res.options;
+	__UCLIBC_MUTEX_UNLOCK(__resolv_lock);
+	if (!(_res_options & RES_INIT)) {
+		res_init(); /* our res_init never fails */
+		goto again;
+	}
+	if (_res_options & RES_DEBUG)
+		printf(";; res_mkquery(%d, %s, %s, %d, %d)\n",
+			   name, (op, dname ? dname : "<Nil>"), class, type);
 #endif
 
-/* Unimplemented: */
-/* res_mkquery */
-/* res_send */
-/* dn_comp */
+	memset(buf, 0, HFIXEDSZ);
+	hp = (HEADER *) buf;
+	hp->opcode = op;
+	hp->rd = (_res.options & RES_RECURSE) != 0U;
+	hp->rcode = NOERROR;
+
+	cp = buf + HFIXEDSZ;
+	ep = buf + buflen;
+	dpp = dnptrs;
+	*dpp++ = buf;
+	*dpp++ = NULL;
+	lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
+
+	/*
+	 * perform opcode specific processing
+	 */
+	switch (op) {
+	case QUERY:
+	case NS_NOTIFY_OP:
+		if (ep - cp < QFIXEDSZ)
+			return -1;
+
+		if ((n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs, lastdnptr)) < 0)
+			return -1;
+
+		cp += n;
+		NS_PUT16(type, cp);
+		cp += INT16SZ;
+		NS_PUT16(class, cp);
+		cp += INT16SZ;
+		hp->qdcount = htons(1);
+
+		if (op == QUERY || data == NULL)
+			break;
+
+		/*
+		 * Make an additional record for completion domain.
+		 */
+		if ((ep - cp) < RRFIXEDSZ)
+			return -1;
+
+		n = dn_comp((const char *)data, cp, ep - cp - RRFIXEDSZ,
+					 dnptrs, lastdnptr);
+		if (n < 0)
+			return -1;
+
+		cp += n;
+		NS_PUT16(T_NULL, cp);
+		cp += INT16SZ;
+		NS_PUT16(class, cp);
+		cp += INT16SZ;
+		NS_PUT32(0, cp);
+		cp += INT32SZ;
+		NS_PUT16(0, cp);
+		cp += INT16SZ;
+		hp->arcount = htons(1);
+
+		break;
+
+	case IQUERY:
+		/*
+		 * Initialize answer section
+		 */
+		if (ep - cp < 1 + RRFIXEDSZ + datalen)
+			return -1;
+
+		*cp++ = '\0';   /*%< no domain name */
+		NS_PUT16(type, cp);
+		cp += INT16SZ;
+		NS_PUT16(class, cp);
+		cp += INT16SZ;
+		NS_PUT32(0, cp);
+		cp += INT32SZ;
+		NS_PUT16(datalen, cp);
+		cp += INT16SZ;
+
+		if (datalen) {
+			memcpy(cp, data, (size_t)datalen);
+			cp += datalen;
+		}
+
+		hp->ancount = htons(1);
+		break;
+
+	default:
+		return -1;
+	}
+
+	return (cp - buf);
+}
+libresolv_hidden_def(res_mkquery)
+
+int ns_name_pack(const unsigned char *src,
+				 unsigned char *dst, int dstsiz,
+				 const unsigned char **dnptrs,
+				 const unsigned char **lastdnptr)
+{
+	unsigned char *dstp;
+	const unsigned char **cpp, **lpp, *eob, *msg;
+	const unsigned char *srcp;
+	int n, l, first = 1;
+
+	srcp = src;
+	dstp = dst;
+	eob = dstp + dstsiz;
+	lpp = cpp = NULL;
+
+	if (dnptrs != NULL) {
+		if ((msg = *dnptrs++) != NULL) {
+			for (cpp = dnptrs; *cpp != NULL; cpp++)
+				continue;
+
+			lpp = cpp;      /*%< end of list to search */
+		}
+	} else {
+		msg = NULL;
+	}
+
+	/* make sure the domain we are about to add is legal */
+	l = 0;
+	do {
+		int l0;
+
+		n = *srcp;
+		if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+			errno = EMSGSIZE;
+			return -1;
+		}
+
+		if ((l0 = labellen(srcp)) < 0) {
+			errno = EINVAL;
+			return -1;
+		}
+
+		l += l0 + 1;
+		if (l > MAXCDNAME) {
+			errno = EMSGSIZE;
+			return -1;
+		}
+
+		srcp += l0 + 1;
+	} while (n != 0);
+
+	/* from here on we need to reset compression pointer array on error */
+	srcp = src;
+
+	do {
+		/* Look to see if we can use pointers. */
+		n = *srcp;
+
+		if (n != 0 && msg != NULL) {
+			l = dn_find(srcp, msg, (const unsigned char * const *) dnptrs,
+						(const unsigned char * const *) lpp);
+			if (l >= 0) {
+				if (dstp + 1 >= eob) {
+					goto cleanup;
+				}
+
+				*dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS;
+				*dstp++ = l % 256;
+				return (dstp - dst);
+			}
+
+			/* Not found, save it. */
+			if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
+				(dstp - msg) < 0x4000 && first) {
+				*cpp++ = dstp;
+				*cpp = NULL;
+				first = 0;
+			}
+		}
+
+		/* copy label to buffer */
+		if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+			/* Should not happen. */
+			goto cleanup;
+		}
+
+		n = labellen(srcp);
+		if (dstp + 1 + n >= eob) {
+			goto cleanup;
+		}
+
+		memcpy(dstp, srcp, (size_t)(n + 1));
+		srcp += n + 1;
+		dstp += n + 1;
+	} while (n != 0);
+
+	if (dstp > eob) {
+cleanup:
+		if (msg != NULL)
+			*lpp = NULL;
+
+			errno = EMSGSIZE;
+			return -1;
+	}
+
+	return dstp - dst;
+}
+libresolv_hidden_def(ns_name_pack)
+
+int ns_name_compress(const char *src,
+					 unsigned char *dst, size_t dstsiz,
+					 const unsigned char **dnptrs,
+					 const unsigned char **lastdnptr)
+{
+	unsigned char tmp[NS_MAXCDNAME];
+
+	if (ns_name_pton(src, tmp, sizeof(tmp)) == -1)
+		return -1;
+
+	return ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr);
+}
+libresolv_hidden_def(ns_name_compress)
+
+int dn_comp(const char *src,
+			unsigned char *dst, int dstsiz,
+			unsigned char **dnptrs,
+			unsigned char **lastdnptr)
+{
+	return ns_name_compress(src, dst, dstsiz,
+							(const unsigned char **) dnptrs,
+							(const unsigned char **) lastdnptr);
+}
+libresolv_hidden_def(dn_comp)
+
+int ns_name_skip(const unsigned char **ptrptr,
+				 const unsigned char *eom)
+{
+	const unsigned char *cp;
+	u_int n;
+	int l;
+
+	cp = *ptrptr;
+	while (cp < eom && (n = *cp++) != 0) {
+		/* Check for indirection. */
+		switch (n & NS_CMPRSFLGS) {
+		case 0:		 /*%< normal case, n == len */
+			cp += n;
+			continue;
+		case NS_TYPE_ELT: /*%< EDNS0 extended label */
+			if ((l = labellen(cp - 1)) < 0) {
+				errno = EMSGSIZE; /*%< XXX */
+				return -1;
+			}
+			cp += l;
+			continue;
+		case NS_CMPRSFLGS:      /*%< indirection */
+			cp++;
+			break;
+		default:		/*%< illegal type */
+			errno = EMSGSIZE;
+			return -1;
+		}
+
+		break;
+	}
+
+	if (cp > eom) {
+		errno = EMSGSIZE;
+		return -1;
+	}
+
+	*ptrptr = cp;
+
+	return 0;
+}
+libresolv_hidden_def(ns_name_skip)
+
+
+int dn_skipname(const unsigned char *ptr, const unsigned char *eom)
+{
+	const unsigned char *saveptr = ptr;
+
+	if (ns_name_skip(&ptr, eom) == -1)
+		return -1;
+
+	return (ptr - saveptr);
+}
+libc_hidden_def(dn_skipname)
+
+#endif
diff --git a/libresolv/Makefile.in b/libresolv/Makefile.in
index fa3c341..0809ba3 100644
--- a/libresolv/Makefile.in
+++ b/libresolv/Makefile.in
@@ -19,7 +19,11 @@ libresolv_FULL_NAME := libresolv-$(VERSION).so
 libresolv_DIR := $(top_srcdir)libresolv
 libresolv_OUT := $(top_builddir)libresolv
 
-libresolv_SRC := $(libresolv_DIR)/resolv.c
+libresolv_SRC := $(libresolv_DIR)/resolv.c \
+		 $(libresolv_DIR)/ns_netint.c \
+		 $(libresolv_DIR)/ns_parse.c \
+		 $(libresolv_DIR)/ns_name.c
+
 libresolv_OBJ := $(patsubst $(libresolv_DIR)/%.c,$(libresolv_OUT)/%.o,$(libresolv_SRC))
 
 ifeq ($(DOPIC),y)
@@ -29,8 +33,8 @@ libresolv-a-y := $(libresolv_OBJ)
 endif
 libresolv-so-y := $(libresolv_OBJ:.o=.os)
 
-lib-a-$(UCLIBC_HAS_LIBRESOLV_STUB)  += $(top_builddir)lib/libresolv.a
-lib-so-$(UCLIBC_HAS_LIBRESOLV_STUB) += $(top_builddir)lib/libresolv.so
+lib-a-$(UCLIBC_HAS_LIBRESOLV)  += $(top_builddir)lib/libresolv.a
+lib-so-$(UCLIBC_HAS_LIBRESOLV) += $(top_builddir)lib/libresolv.so
 objclean-y += CLEAN_libresolv
 
 ifeq ($(DOPIC),y)
diff --git a/libresolv/ns_name.c b/libresolv/ns_name.c
new file mode 100644
index 0000000..24e8895
--- /dev/null
+++ b/libresolv/ns_name.c
@@ -0,0 +1,15 @@
+/* vi: set sw=4 ts=4: */
+/*
+* libresolv for uClibc
+*
+* Copyright (C) 2011 Daniel Mack <[email protected]>
+*
+* Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+*/
+
+#include <features.h>
+
+#include <errno.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
diff --git a/libresolv/ns_netint.c b/libresolv/ns_netint.c
new file mode 100644
index 0000000..3a6f248
--- /dev/null
+++ b/libresolv/ns_netint.c
@@ -0,0 +1,41 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * libresolv for uClibc
+ *
+ * Copyright (C) 2011 Daniel Mack <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <features.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+unsigned int ns_get16(const unsigned char *src)
+{
+	unsigned int dst;
+	NS_GET16(dst, src);
+	return dst;
+}
+libresolv_hidden_def(ns_get16)
+
+unsigned long ns_get32(const unsigned char *src)
+{
+	unsigned long dst;
+	NS_GET32(dst, src);
+	return dst;
+}
+libresolv_hidden_def(ns_get32)
+
+void ns_put16(unsigned int src, unsigned char *dst)
+{
+	NS_PUT16(src, dst);
+}
+libresolv_hidden_def(ns_put16)
+
+void ns_put32(unsigned long src, unsigned char *dst)
+{
+	NS_PUT32(src, dst);
+}
+libresolv_hidden_def(ns_put32)
+
diff --git a/libresolv/ns_parse.c b/libresolv/ns_parse.c
new file mode 100644
index 0000000..e04d98b
--- /dev/null
+++ b/libresolv/ns_parse.c
@@ -0,0 +1,187 @@
+/* vi: set sw=4 ts=4: */
+/*
+* libresolv for uClibc
+*
+* Copyright (C) 2011 Daniel Mack <[email protected]>
+*
+* Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+*/
+
+#include <features.h>
+
+#include <errno.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+static void setsection(ns_msg *msg, ns_sect sect)
+{
+	msg->_sect = sect;
+	if (sect == ns_s_max) {
+		msg->_rrnum = -1;
+		msg->_ptr = NULL;
+	} else {
+		msg->_rrnum = 0;
+		msg->_ptr = msg->_sections[(int)sect];
+	}
+}
+
+int ns_skiprr(const unsigned char *ptr,
+			  const unsigned char *eom,
+			  ns_sect section, int count)
+{
+	const u_char *optr = ptr;
+
+	for (; count > 0; count--) {
+		int b, rdlength;
+
+		b = dn_skipname(ptr, eom);
+		if (b < 0) {
+			errno = EMSGSIZE;
+			return -1;
+		}
+
+		ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/;
+		if (section != ns_s_qd) {
+			if (ptr + NS_INT32SZ + NS_INT16SZ > eom) {
+				errno = EMSGSIZE;
+				return -1;
+			}
+
+			ptr += NS_INT32SZ/*TTL*/;
+			NS_GET16(rdlength, ptr);
+			ptr += rdlength/*RData*/;
+		}
+	}
+
+	if (ptr > eom) {
+		errno = EMSGSIZE;
+		return -1;
+	}
+
+	return ptr - optr;
+}
+libresolv_hidden_def(ns_skiprr)
+
+int
+ns_initparse(const unsigned 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) {
+		errno = EMSGSIZE;
+		return -1;
+	}
+
+	NS_GET16(handle->_id, msg);
+	if (msg + NS_INT16SZ > eom) {
+		errno = EMSGSIZE;
+		return -1;
+	}
+
+	NS_GET16(handle->_flags, msg);
+	for (i = 0; i < ns_s_max; i++) {
+		if (msg + NS_INT16SZ > eom) {
+			errno = EMSGSIZE;
+			return -1;
+		}
+
+		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) {
+		errno = EMSGSIZE;
+		return -1;
+	}
+
+	setsection(handle, ns_s_max);
+	return (0);
+}
+libresolv_hidden_def(ns_initparse)
+
+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) {
+		errno = ENODEV;
+		return -1;
+	}
+
+	if (section != handle->_sect)
+		setsection(handle, section);
+
+	/* Make rrnum right. */
+	if (rrnum == -1)
+		rrnum = handle->_rrnum;
+	if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) {
+		errno = ENODEV;
+		return -1;
+	}
+	if (rrnum < handle->_rrnum)
+		setsection(handle, section);
+	if (rrnum > handle->_rrnum) {
+		b = ns_skiprr(handle->_ptr, handle->_eom, section,
+			      rrnum - handle->_rrnum);
+
+		if (b < 0)
+			return (-1);
+		handle->_ptr += b;
+		handle->_rrnum = rrnum;
+	}
+
+	/* Do the parse. */
+	b = dn_expand(handle->_msg, handle->_eom,
+		      handle->_ptr, rr->name, NS_MAXDNAME);
+	if (b < 0)
+		return (-1);
+	handle->_ptr += b;
+	if (handle->_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) {
+		errno = EMSGSIZE;
+		return -1;
+	}
+	NS_GET16(rr->type, handle->_ptr);
+	NS_GET16(rr->rr_class, handle->_ptr);
+	if (section == ns_s_qd) {
+		rr->ttl = 0;
+		rr->rdlength = 0;
+		rr->rdata = NULL;
+	} else {
+		if (handle->_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) {
+			errno = EMSGSIZE;
+			return -1;
+		}
+		NS_GET32(rr->ttl, handle->_ptr);
+		NS_GET16(rr->rdlength, handle->_ptr);
+		if (handle->_ptr + rr->rdlength > handle->_eom) {
+			errno = EMSGSIZE;
+			return -1;
+		}
+		rr->rdata = handle->_ptr;
+		handle->_ptr += rr->rdlength;
+	}
+	if (++handle->_rrnum > handle->_counts[(int)section])
+		setsection(handle, (ns_sect)((int)section + 1));
+
+	return 0;
+}
+libresolv_hidden_def(ns_parserr)
+
_______________________________________________
uClibc mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/uclibc

Reply via email to