[git commit] inet/resolv: add ns_name_pton, ns_name_pack and ns_name_compress

Daniel Mack zonque at gmail.com
Fri Aug 26 07:49:55 UTC 2011


commit: http://git.uclibc.org/uClibc/commit/?id=e5153a77782bf7042f50b97959536f3f181bad99
branch: http://git.uclibc.org/uClibc/commit/?id=refs/heads/master

These are built '#ifdef L_ns_name'

Signed-off-by: Daniel Mack <zonque at gmail.com>
---
 include/arpa/nameser.h |    1 +
 libc/inet/resolv.c     |  468 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 469 insertions(+), 0 deletions(-)

diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h
index 917ba19..cdc3df5 100644
--- a/include/arpa/nameser.h
+++ b/include/arpa/nameser.h
@@ -521,6 +521,7 @@ 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)
 int		ns_name_pton (const char *, u_char *, size_t) __THROW;
+libc_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)
diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c
index a347ca5..64e99ba 100644
--- a/libc/inet/resolv.c
+++ b/libc/inet/resolv.c
@@ -339,6 +339,9 @@ Domain name in a message can be represented as either:
 #define BUFSZ       (80) /* one line */
 #define SBUFSIZE    (BUFSZ + 1 + (sizeof(char *) * MAXALIASES))
 
+#define NS_TYPE_ELT					0x40 /*%< EDNS0 extended label type */
+#define DNS_LABELTYPE_BITSTRING		0x41
+
 #undef DEBUG
 /* #define DEBUG */
 
@@ -2792,6 +2795,259 @@ int ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
 }
 libc_hidden_def(ns_name_ntop)
 
+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_bitstring(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_bitstring(&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);
+}
+libc_hidden_def(ns_name_pton)
+
 /*
  * ns_name_unpack(msg, eom, src, dst, dstsiz)
  *      Unpack a domain name from a message, source may be compressed.
@@ -2866,6 +3122,218 @@ int ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
 	return len;
 }
 libc_hidden_def(ns_name_unpack)
+
+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;
+}
+
+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;
+}
+
+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);
+}
 #endif /* L_ns_name */
 
 
-- 
1.7.3.4



More information about the uClibc-cvs mailing list