Home | History | Annotate | Download | only in nameser
      1 /*	$NetBSD: ns_name.c,v 1.3 2004/11/07 02:19:49 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
      5  * Copyright (c) 1996,1999 by Internet Software Consortium.
      6  *
      7  * Permission to use, copy, modify, and distribute this software for any
      8  * purpose with or without fee is hereby granted, provided that the above
      9  * copyright notice and this permission notice appear in all copies.
     10  *
     11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
     12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
     14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     17  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18  */
     19 
     20 #include <sys/cdefs.h>
     21 #ifndef lint
     22 #ifdef notdef
     23 static const char rcsid[] = "Id: ns_name.c,v 1.3.2.4.4.2 2004/05/04 03:27:47 marka Exp";
     24 #else
     25 __RCSID("$NetBSD: ns_name.c,v 1.3 2004/11/07 02:19:49 christos Exp $");
     26 #endif
     27 #endif
     28 
     29 #include <sys/types.h>
     30 
     31 #include <netinet/in.h>
     32 #include "arpa_nameser.h"
     33 
     34 #include <errno.h>
     35 #ifdef ANDROID_CHANGES
     36 #include "resolv_private.h"
     37 #else
     38 #include <resolv.h>
     39 #endif
     40 #include <string.h>
     41 #include <ctype.h>
     42 #include <stdlib.h>
     43 #include <limits.h>
     44 
     45 #ifdef SPRINTF_CHAR
     46 # define SPRINTF(x) strlen(sprintf/**/x)
     47 #else
     48 # define SPRINTF(x) ((size_t)sprintf x)
     49 #endif
     50 
     51 #define NS_TYPE_ELT			0x40 /* EDNS0 extended label type */
     52 #define DNS_LABELTYPE_BITSTRING		0x41
     53 
     54 /* Data. */
     55 
     56 static const char	digits[] = "0123456789";
     57 
     58 static const char digitvalue[256] = {
     59 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	/*16*/
     60 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
     61 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
     62 	 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1, /*64*/
     63 	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
     64 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
     65 	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
     66 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
     67 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     68 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     69 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     70 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     71 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     72 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     73 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     74 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
     75 };
     76 
     77 /* Forward. */
     78 
     79 static int		special(int);
     80 static int		printable(int);
     81 static int		dn_find(const u_char *, const u_char *,
     82 				const u_char * const *,
     83 				const u_char * const *);
     84 static int		encode_bitsring(const char **, const char *,
     85 					unsigned char **, unsigned char **,
     86 					unsigned const char *);
     87 static int		labellen(const u_char *);
     88 static int		decode_bitstring(const unsigned char **,
     89 					 char *, const char *);
     90 
     91 /* Public. */
     92 
     93 /*
     94  * ns_name_ntop(src, dst, dstsiz)
     95  *	Convert an encoded domain name to printable ascii as per RFC1035.
     96  * return:
     97  *	Number of bytes written to buffer, or -1 (with errno set)
     98  * notes:
     99  *	The root is returned as "."
    100  *	All other domains are returned in non absolute form
    101  */
    102 int
    103 ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
    104 {
    105 	const u_char *cp;
    106 	char *dn, *eom;
    107 	u_char c;
    108 	u_int n;
    109 	int l;
    110 
    111 	cp = src;
    112 	dn = dst;
    113 	eom = dst + dstsiz;
    114 
    115 	while ((n = *cp++) != 0) {
    116 		if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
    117 			/* Some kind of compression pointer. */
    118 			errno = EMSGSIZE;
    119 			return (-1);
    120 		}
    121 		if (dn != dst) {
    122 			if (dn >= eom) {
    123 				errno = EMSGSIZE;
    124 				return (-1);
    125 			}
    126 			*dn++ = '.';
    127 		}
    128 		if ((l = labellen(cp - 1)) < 0) {
    129 			errno = EMSGSIZE; /* XXX */
    130 			return(-1);
    131 		}
    132 		if (dn + l >= eom) {
    133 			errno = EMSGSIZE;
    134 			return (-1);
    135 		}
    136 		if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) {
    137 			int m;
    138 
    139 			if (n != DNS_LABELTYPE_BITSTRING) {
    140 				/* XXX: labellen should reject this case */
    141 				errno = EINVAL;
    142 				return(-1);
    143 			}
    144 			if ((m = decode_bitstring(&cp, dn, eom)) < 0)
    145 			{
    146 				errno = EMSGSIZE;
    147 				return(-1);
    148 			}
    149 			dn += m;
    150 			continue;
    151 		}
    152 		for (; l > 0; l--) {
    153 			c = *cp++;
    154 			if (special(c)) {
    155 				if (dn + 1 >= eom) {
    156 					errno = EMSGSIZE;
    157 					return (-1);
    158 				}
    159 				*dn++ = '\\';
    160 				*dn++ = (char)c;
    161 			} else if (!printable(c)) {
    162 				if (dn + 3 >= eom) {
    163 					errno = EMSGSIZE;
    164 					return (-1);
    165 				}
    166 				*dn++ = '\\';
    167 				*dn++ = digits[c / 100];
    168 				*dn++ = digits[(c % 100) / 10];
    169 				*dn++ = digits[c % 10];
    170 			} else {
    171 				if (dn >= eom) {
    172 					errno = EMSGSIZE;
    173 					return (-1);
    174 				}
    175 				*dn++ = (char)c;
    176 			}
    177 		}
    178 	}
    179 	if (dn == dst) {
    180 		if (dn >= eom) {
    181 			errno = EMSGSIZE;
    182 			return (-1);
    183 		}
    184 		*dn++ = '.';
    185 	}
    186 	if (dn >= eom) {
    187 		errno = EMSGSIZE;
    188 		return (-1);
    189 	}
    190 	*dn++ = '\0';
    191 	return (dn - dst);
    192 }
    193 
    194 /*
    195  * ns_name_pton(src, dst, dstsiz)
    196  *	Convert a ascii string into an encoded domain name as per RFC1035.
    197  * return:
    198  *	-1 if it fails
    199  *	1 if string was fully qualified
    200  *	0 is string was not fully qualified
    201  * notes:
    202  *	Enforces label and domain length limits.
    203  */
    204 
    205 int
    206 ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
    207 {
    208 	u_char *label, *bp, *eom;
    209 	int c, n, escaped, e = 0;
    210 	char *cp;
    211 
    212 	escaped = 0;
    213 	bp = dst;
    214 	eom = dst + dstsiz;
    215 	label = bp++;
    216 
    217 	while ((c = *src++) != 0) {
    218 		if (escaped) {
    219 			if (c == '[') { /* start a bit string label */
    220 				if ((cp = strchr(src, ']')) == NULL) {
    221 					errno = EINVAL; /* ??? */
    222 					return(-1);
    223 				}
    224 				if ((e = encode_bitsring(&src, cp + 2,
    225 							 &label, &bp, eom))
    226 				    != 0) {
    227 					errno = e;
    228 					return(-1);
    229 				}
    230 				escaped = 0;
    231 				label = bp++;
    232 				if ((c = *src++) == 0)
    233 					goto done;
    234 				else if (c != '.') {
    235 					errno = EINVAL;
    236 					return(-1);
    237 				}
    238 				continue;
    239 			}
    240 			else if ((cp = strchr(digits, c)) != NULL) {
    241 				n = (cp - digits) * 100;
    242 				if ((c = *src++) == 0 ||
    243 				    (cp = strchr(digits, c)) == NULL) {
    244 					errno = EMSGSIZE;
    245 					return (-1);
    246 				}
    247 				n += (cp - digits) * 10;
    248 				if ((c = *src++) == 0 ||
    249 				    (cp = strchr(digits, c)) == NULL) {
    250 					errno = EMSGSIZE;
    251 					return (-1);
    252 				}
    253 				n += (cp - digits);
    254 				if (n > 255) {
    255 					errno = EMSGSIZE;
    256 					return (-1);
    257 				}
    258 				c = n;
    259 			}
    260 			escaped = 0;
    261 		} else if (c == '\\') {
    262 			escaped = 1;
    263 			continue;
    264 		} else if (c == '.') {
    265 			c = (bp - label - 1);
    266 			if ((c & NS_CMPRSFLGS) != 0) {	/* Label too big. */
    267 				errno = EMSGSIZE;
    268 				return (-1);
    269 			}
    270 			if (label >= eom) {
    271 				errno = EMSGSIZE;
    272 				return (-1);
    273 			}
    274 			*label = c;
    275 			/* Fully qualified ? */
    276 			if (*src == '\0') {
    277 				if (c != 0) {
    278 					if (bp >= eom) {
    279 						errno = EMSGSIZE;
    280 						return (-1);
    281 					}
    282 					*bp++ = '\0';
    283 				}
    284 				if ((bp - dst) > MAXCDNAME) {
    285 					errno = EMSGSIZE;
    286 					return (-1);
    287 				}
    288 				return (1);
    289 			}
    290 			if (c == 0 || *src == '.') {
    291 				errno = EMSGSIZE;
    292 				return (-1);
    293 			}
    294 			label = bp++;
    295 			continue;
    296 		}
    297 		if (bp >= eom) {
    298 			errno = EMSGSIZE;
    299 			return (-1);
    300 		}
    301 		*bp++ = (u_char)c;
    302 	}
    303 	c = (bp - label - 1);
    304 	if ((c & NS_CMPRSFLGS) != 0) {		/* Label too big. */
    305 		errno = EMSGSIZE;
    306 		return (-1);
    307 	}
    308   done:
    309 	if (label >= eom) {
    310 		errno = EMSGSIZE;
    311 		return (-1);
    312 	}
    313 	*label = c;
    314 	if (c != 0) {
    315 		if (bp >= eom) {
    316 			errno = EMSGSIZE;
    317 			return (-1);
    318 		}
    319 		*bp++ = 0;
    320 	}
    321 	if ((bp - dst) > MAXCDNAME) {	/* src too big */
    322 		errno = EMSGSIZE;
    323 		return (-1);
    324 	}
    325 	return (0);
    326 }
    327 
    328 /*
    329  * ns_name_ntol(src, dst, dstsiz)
    330  *	Convert a network strings labels into all lowercase.
    331  * return:
    332  *	Number of bytes written to buffer, or -1 (with errno set)
    333  * notes:
    334  *	Enforces label and domain length limits.
    335  */
    336 
    337 int
    338 ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz)
    339 {
    340 	const u_char *cp;
    341 	u_char *dn, *eom;
    342 	u_char c;
    343 	u_int n;
    344 	int l;
    345 
    346 	cp = src;
    347 	dn = dst;
    348 	eom = dst + dstsiz;
    349 
    350 	if (dn >= eom) {
    351 		errno = EMSGSIZE;
    352 		return (-1);
    353 	}
    354 	while ((n = *cp++) != 0) {
    355 		if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
    356 			/* Some kind of compression pointer. */
    357 			errno = EMSGSIZE;
    358 			return (-1);
    359 		}
    360 		*dn++ = n;
    361 		if ((l = labellen(cp - 1)) < 0) {
    362 			errno = EMSGSIZE;
    363 			return (-1);
    364 		}
    365 		if (dn + l >= eom) {
    366 			errno = EMSGSIZE;
    367 			return (-1);
    368 		}
    369 		for (; l > 0; l--) {
    370 			c = *cp++;
    371 			if (isupper(c))
    372 				*dn++ = tolower(c);
    373 			else
    374 				*dn++ = c;
    375 		}
    376 	}
    377 	*dn++ = '\0';
    378 	return (dn - dst);
    379 }
    380 
    381 /*
    382  * ns_name_unpack(msg, eom, src, dst, dstsiz)
    383  *	Unpack a domain name from a message, source may be compressed.
    384  * return:
    385  *	-1 if it fails, or consumed octets if it succeeds.
    386  */
    387 int
    388 ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
    389 	       u_char *dst, size_t dstsiz)
    390 {
    391 	const u_char *srcp, *dstlim;
    392 	u_char *dstp;
    393 	int n, len, checked, l;
    394 
    395 	len = -1;
    396 	checked = 0;
    397 	dstp = dst;
    398 	srcp = src;
    399 	dstlim = dst + dstsiz;
    400 	if (srcp < msg || srcp >= eom) {
    401 		errno = EMSGSIZE;
    402 		return (-1);
    403 	}
    404 	/* Fetch next label in domain name. */
    405 	while ((n = *srcp++) != 0) {
    406 		/* Check for indirection. */
    407 		switch (n & NS_CMPRSFLGS) {
    408 		case 0:
    409 		case NS_TYPE_ELT:
    410 			/* Limit checks. */
    411 			if ((l = labellen(srcp - 1)) < 0) {
    412 				errno = EMSGSIZE;
    413 				return(-1);
    414 			}
    415 			if (dstp + l + 1 >= dstlim || srcp + l >= eom) {
    416 				errno = EMSGSIZE;
    417 				return (-1);
    418 			}
    419 			checked += l + 1;
    420 			*dstp++ = n;
    421 			memcpy(dstp, srcp, (size_t)l);
    422 			dstp += l;
    423 			srcp += l;
    424 			break;
    425 
    426 		case NS_CMPRSFLGS:
    427 			if (srcp >= eom) {
    428 				errno = EMSGSIZE;
    429 				return (-1);
    430 			}
    431 			if (len < 0)
    432 				len = srcp - src + 1;
    433 			srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
    434 			if (srcp < msg || srcp >= eom) {  /* Out of range. */
    435 				errno = EMSGSIZE;
    436 				return (-1);
    437 			}
    438 			checked += 2;
    439 			/*
    440 			 * Check for loops in the compressed name;
    441 			 * if we've looked at the whole message,
    442 			 * there must be a loop.
    443 			 */
    444 			if (checked >= eom - msg) {
    445 				errno = EMSGSIZE;
    446 				return (-1);
    447 			}
    448 			break;
    449 
    450 		default:
    451 			errno = EMSGSIZE;
    452 			return (-1);			/* flag error */
    453 		}
    454 	}
    455 	*dstp = '\0';
    456 	if (len < 0)
    457 		len = srcp - src;
    458 	return (len);
    459 }
    460 
    461 /*
    462  * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr)
    463  *	Pack domain name 'domain' into 'comp_dn'.
    464  * return:
    465  *	Size of the compressed name, or -1.
    466  * notes:
    467  *	'dnptrs' is an array of pointers to previous compressed names.
    468  *	dnptrs[0] is a pointer to the beginning of the message. The array
    469  *	ends with NULL.
    470  *	'lastdnptr' is a pointer to the end of the array pointed to
    471  *	by 'dnptrs'.
    472  * Side effects:
    473  *	The list of pointers in dnptrs is updated for labels inserted into
    474  *	the message as we compress the name.  If 'dnptr' is NULL, we don't
    475  *	try to compress names. If 'lastdnptr' is NULL, we don't update the
    476  *	list.
    477  */
    478 int
    479 ns_name_pack(const u_char *src, u_char *dst, int dstsiz,
    480 	     const u_char **dnptrs, const u_char **lastdnptr)
    481 {
    482 	u_char *dstp;
    483 	const u_char **cpp, **lpp, *eob, *msg;
    484 	const u_char *srcp;
    485 	int n, l, first = 1;
    486 
    487 	srcp = src;
    488 	dstp = dst;
    489 	eob = dstp + dstsiz;
    490 	lpp = cpp = NULL;
    491 	if (dnptrs != NULL) {
    492 		if ((msg = *dnptrs++) != NULL) {
    493 			for (cpp = dnptrs; *cpp != NULL; cpp++)
    494 				;
    495 			lpp = cpp;	/* end of list to search */
    496 		}
    497 	} else
    498 		msg = NULL;
    499 
    500 	/* make sure the domain we are about to add is legal */
    501 	l = 0;
    502 	do {
    503 		int l0;
    504 
    505 		n = *srcp;
    506 		if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
    507 			errno = EMSGSIZE;
    508 			return (-1);
    509 		}
    510 		if ((l0 = labellen(srcp)) < 0) {
    511 			errno = EINVAL;
    512 			return(-1);
    513 		}
    514 		l += l0 + 1;
    515 		if (l > MAXCDNAME) {
    516 			errno = EMSGSIZE;
    517 			return (-1);
    518 		}
    519 		srcp += l0 + 1;
    520 	} while (n != 0);
    521 
    522 	/* from here on we need to reset compression pointer array on error */
    523 	srcp = src;
    524 	do {
    525 		/* Look to see if we can use pointers. */
    526 		n = *srcp;
    527 		if (n != 0 && msg != NULL) {
    528 			l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
    529 				    (const u_char * const *)lpp);
    530 			if (l >= 0) {
    531 				if (dstp + 1 >= eob) {
    532 					goto cleanup;
    533 				}
    534 				*dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS;
    535 				*dstp++ = l % 256;
    536 				return (dstp - dst);
    537 			}
    538 			/* Not found, save it. */
    539 			if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
    540 			    (dstp - msg) < 0x4000 && first) {
    541 				*cpp++ = dstp;
    542 				*cpp = NULL;
    543 				first = 0;
    544 			}
    545 		}
    546 		/* copy label to buffer */
    547 		if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
    548 			/* Should not happen. */
    549 			goto cleanup;
    550 		}
    551 		n = labellen(srcp);
    552 		if (dstp + 1 + n >= eob) {
    553 			goto cleanup;
    554 		}
    555 		memcpy(dstp, srcp, (size_t)(n + 1));
    556 		srcp += n + 1;
    557 		dstp += n + 1;
    558 	} while (n != 0);
    559 
    560 	if (dstp > eob) {
    561 cleanup:
    562 		if (msg != NULL)
    563 			*lpp = NULL;
    564 		errno = EMSGSIZE;
    565 		return (-1);
    566 	}
    567 	return (dstp - dst);
    568 }
    569 
    570 /*
    571  * ns_name_uncompress(msg, eom, src, dst, dstsiz)
    572  *	Expand compressed domain name to presentation format.
    573  * return:
    574  *	Number of bytes read out of `src', or -1 (with errno set).
    575  * note:
    576  *	Root domain returns as "." not "".
    577  */
    578 int
    579 ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
    580 		   char *dst, size_t dstsiz)
    581 {
    582 	u_char tmp[NS_MAXCDNAME];
    583 	int n;
    584 
    585 	if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
    586 		return (-1);
    587 	if (ns_name_ntop(tmp, dst, dstsiz) == -1)
    588 		return (-1);
    589 	return (n);
    590 }
    591 
    592 /*
    593  * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr)
    594  *	Compress a domain name into wire format, using compression pointers.
    595  * return:
    596  *	Number of bytes consumed in `dst' or -1 (with errno set).
    597  * notes:
    598  *	'dnptrs' is an array of pointers to previous compressed names.
    599  *	dnptrs[0] is a pointer to the beginning of the message.
    600  *	The list ends with NULL.  'lastdnptr' is a pointer to the end of the
    601  *	array pointed to by 'dnptrs'. Side effect is to update the list of
    602  *	pointers for labels inserted into the message as we compress the name.
    603  *	If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
    604  *	is NULL, we don't update the list.
    605  */
    606 int
    607 ns_name_compress(const char *src, u_char *dst, size_t dstsiz,
    608 		 const u_char **dnptrs, const u_char **lastdnptr)
    609 {
    610 	u_char tmp[NS_MAXCDNAME];
    611 
    612 	if (ns_name_pton(src, tmp, sizeof tmp) == -1)
    613 		return (-1);
    614 	return (ns_name_pack(tmp, dst, (int)dstsiz, dnptrs, lastdnptr));
    615 }
    616 
    617 /*
    618  * Reset dnptrs so that there are no active references to pointers at or
    619  * after src.
    620  */
    621 void
    622 ns_name_rollback(const u_char *src, const u_char **dnptrs,
    623 		 const u_char **lastdnptr)
    624 {
    625 	while (dnptrs < lastdnptr && *dnptrs != NULL) {
    626 		if (*dnptrs >= src) {
    627 			*dnptrs = NULL;
    628 			break;
    629 		}
    630 		dnptrs++;
    631 	}
    632 }
    633 
    634 /*
    635  * ns_name_skip(ptrptr, eom)
    636  *	Advance *ptrptr to skip over the compressed name it points at.
    637  * return:
    638  *	0 on success, -1 (with errno set) on failure.
    639  */
    640 int
    641 ns_name_skip(const u_char **ptrptr, const u_char *eom)
    642 {
    643 	const u_char *cp;
    644 	u_int n;
    645 	int l;
    646 
    647 	cp = *ptrptr;
    648 	while (cp < eom && (n = *cp++) != 0) {
    649 		/* Check for indirection. */
    650 		switch (n & NS_CMPRSFLGS) {
    651 		case 0:			/* normal case, n == len */
    652 			cp += n;
    653 			continue;
    654 		case NS_TYPE_ELT: /* EDNS0 extended label */
    655 			if ((l = labellen(cp - 1)) < 0) {
    656 				errno = EMSGSIZE; /* XXX */
    657 				return(-1);
    658 			}
    659 			cp += l;
    660 			continue;
    661 		case NS_CMPRSFLGS:	/* indirection */
    662 			cp++;
    663 			break;
    664 		default:		/* illegal type */
    665 			errno = EMSGSIZE;
    666 			return (-1);
    667 		}
    668 		break;
    669 	}
    670 	if (cp > eom) {
    671 		errno = EMSGSIZE;
    672 		return (-1);
    673 	}
    674 	*ptrptr = cp;
    675 	return (0);
    676 }
    677 
    678 /* Private. */
    679 
    680 /*
    681  * special(ch)
    682  *	Thinking in noninternationalized USASCII (per the DNS spec),
    683  *	is this characted special ("in need of quoting") ?
    684  * return:
    685  *	boolean.
    686  */
    687 static int
    688 special(int ch) {
    689 	switch (ch) {
    690 	case 0x22: /* '"' */
    691 	case 0x2E: /* '.' */
    692 	case 0x3B: /* ';' */
    693 	case 0x5C: /* '\\' */
    694 	case 0x28: /* '(' */
    695 	case 0x29: /* ')' */
    696 	/* Special modifiers in zone files. */
    697 	case 0x40: /* '@' */
    698 	case 0x24: /* '$' */
    699 		return (1);
    700 	default:
    701 		return (0);
    702 	}
    703 }
    704 
    705 /*
    706  * printable(ch)
    707  *	Thinking in noninternationalized USASCII (per the DNS spec),
    708  *	is this character visible and not a space when printed ?
    709  * return:
    710  *	boolean.
    711  */
    712 static int
    713 printable(int ch) {
    714 	return (ch > 0x20 && ch < 0x7f);
    715 }
    716 
    717 /*
    718  *	Thinking in noninternationalized USASCII (per the DNS spec),
    719  *	convert this character to lower case if it's upper case.
    720  */
    721 static int
    722 mklower(int ch) {
    723 	if (ch >= 0x41 && ch <= 0x5A)
    724 		return (ch + 0x20);
    725 	return (ch);
    726 }
    727 
    728 /*
    729  * dn_find(domain, msg, dnptrs, lastdnptr)
    730  *	Search for the counted-label name in an array of compressed names.
    731  * return:
    732  *	offset from msg if found, or -1.
    733  * notes:
    734  *	dnptrs is the pointer to the first name on the list,
    735  *	not the pointer to the start of the message.
    736  */
    737 static int
    738 dn_find(const u_char *domain, const u_char *msg,
    739 	const u_char * const *dnptrs,
    740 	const u_char * const *lastdnptr)
    741 {
    742 	const u_char *dn, *cp, *sp;
    743 	const u_char * const *cpp;
    744 	u_int n;
    745 
    746 	for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
    747 		sp = *cpp;
    748 		/*
    749 		 * terminate search on:
    750 		 * root label
    751 		 * compression pointer
    752 		 * unusable offset
    753 		 */
    754 		while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
    755 		       (sp - msg) < 0x4000) {
    756 			dn = domain;
    757 			cp = sp;
    758 			while ((n = *cp++) != 0) {
    759 				/*
    760 				 * check for indirection
    761 				 */
    762 				switch (n & NS_CMPRSFLGS) {
    763 				case 0:		/* normal case, n == len */
    764 					n = labellen(cp - 1); /* XXX */
    765 
    766 					if (n != *dn++)
    767 						goto next;
    768 
    769 					for (; n > 0; n--)
    770 						if (mklower(*dn++) !=
    771 						    mklower(*cp++))
    772 							goto next;
    773 					/* Is next root for both ? */
    774 					if (*dn == '\0' && *cp == '\0')
    775 						return (sp - msg);
    776 					if (*dn)
    777 						continue;
    778 					goto next;
    779 				case NS_CMPRSFLGS:	/* indirection */
    780 					cp = msg + (((n & 0x3f) << 8) | *cp);
    781 					break;
    782 
    783 				default:	/* illegal type */
    784 					errno = EMSGSIZE;
    785 					return (-1);
    786 				}
    787 			}
    788  next: ;
    789 			sp += *sp + 1;
    790 		}
    791 	}
    792 	errno = ENOENT;
    793 	return (-1);
    794 }
    795 
    796 static int
    797 decode_bitstring(const unsigned char **cpp, char *dn, const char *eom)
    798 {
    799 	const unsigned char *cp = *cpp;
    800 	char *beg = dn, tc;
    801 	int b, blen, plen, i;
    802 
    803 	if ((blen = (*cp & 0xff)) == 0)
    804 		blen = 256;
    805 	plen = (blen + 3) / 4;
    806 	plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1);
    807 	if (dn + plen >= eom)
    808 		return(-1);
    809 
    810 	cp++;
    811 	i = SPRINTF((dn, "\\[x"));
    812 	if (i < 0)
    813 		return (-1);
    814 	dn += i;
    815 	for (b = blen; b > 7; b -= 8, cp++) {
    816 		i = SPRINTF((dn, "%02x", *cp & 0xff));
    817 		if (i < 0)
    818 			return (-1);
    819 		dn += i;
    820 	}
    821 	if (b > 4) {
    822 		tc = *cp++;
    823 		i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b))));
    824 		if (i < 0)
    825 			return (-1);
    826 		dn += i;
    827 	} else if (b > 0) {
    828 		tc = *cp++;
    829 		i = SPRINTF((dn, "%1x",
    830 			       (((u_int32_t)tc >> 4) & 0x0f) & (0x0f << (4 - b))));
    831 		if (i < 0)
    832 			return (-1);
    833 		dn += i;
    834 	}
    835 	i = SPRINTF((dn, "/%d]", blen));
    836 	if (i < 0)
    837 		return (-1);
    838 	dn += i;
    839 
    840 	*cpp = cp;
    841 	return(dn - beg);
    842 }
    843 
    844 static int
    845 encode_bitsring(const char **bp, const char *end, unsigned char **labelp,
    846 	        unsigned char ** dst, unsigned const char *eom)
    847 {
    848 	int afterslash = 0;
    849 	const char *cp = *bp;
    850 	unsigned char *tp;
    851 	char c;
    852 	const char *beg_blen;
    853 	char *end_blen = NULL;
    854 	int value = 0, count = 0, tbcount = 0, blen = 0;
    855 
    856 	beg_blen = end_blen = NULL;
    857 
    858 	/* a bitstring must contain at least 2 characters */
    859 	if (end - cp < 2)
    860 		return(EINVAL);
    861 
    862 	/* XXX: currently, only hex strings are supported */
    863 	if (*cp++ != 'x')
    864 		return(EINVAL);
    865 	if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */
    866 		return(EINVAL);
    867 
    868 	for (tp = *dst + 1; cp < end && tp < eom; cp++) {
    869 		switch((c = *cp)) {
    870 		case ']':	/* end of the bitstring */
    871 			if (afterslash) {
    872 				if (beg_blen == NULL)
    873 					return(EINVAL);
    874 				blen = (int)strtol(beg_blen, &end_blen, 10);
    875 				if (*end_blen != ']')
    876 					return(EINVAL);
    877 			}
    878 			if (count)
    879 				*tp++ = ((value << 4) & 0xff);
    880 			cp++;	/* skip ']' */
    881 			goto done;
    882 		case '/':
    883 			afterslash = 1;
    884 			break;
    885 		default:
    886 			if (afterslash) {
    887 				if (!isdigit(c&0xff))
    888 					return(EINVAL);
    889 				if (beg_blen == NULL) {
    890 
    891 					if (c == '0') {
    892 						/* blen never begings with 0 */
    893 						return(EINVAL);
    894 					}
    895 					beg_blen = cp;
    896 				}
    897 			} else {
    898 				if (!isxdigit(c&0xff))
    899 					return(EINVAL);
    900 				value <<= 4;
    901 				value += digitvalue[(int)c];
    902 				count += 4;
    903 				tbcount += 4;
    904 				if (tbcount > 256)
    905 					return(EINVAL);
    906 				if (count == 8) {
    907 					*tp++ = value;
    908 					count = 0;
    909 				}
    910 			}
    911 			break;
    912 		}
    913 	}
    914   done:
    915 	if (cp >= end || tp >= eom)
    916 		return(EMSGSIZE);
    917 
    918 	/*
    919 	 * bit length validation:
    920 	 * If a <length> is present, the number of digits in the <bit-data>
    921 	 * MUST be just sufficient to contain the number of bits specified
    922 	 * by the <length>. If there are insignificant bits in a final
    923 	 * hexadecimal or octal digit, they MUST be zero.
    924 	 * RFC 2673, Section 3.2.
    925 	 */
    926 	if (blen > 0) {
    927 		int traillen;
    928 
    929 		if (((blen + 3) & ~3) != tbcount)
    930 			return(EINVAL);
    931 		traillen = tbcount - blen; /* between 0 and 3 */
    932 		if (((value << (8 - traillen)) & 0xff) != 0)
    933 			return(EINVAL);
    934 	}
    935 	else
    936 		blen = tbcount;
    937 	if (blen == 256)
    938 		blen = 0;
    939 
    940 	/* encode the type and the significant bit fields */
    941 	**labelp = DNS_LABELTYPE_BITSTRING;
    942 	**dst = blen;
    943 
    944 	*bp = cp;
    945 	*dst = tp;
    946 
    947 	return(0);
    948 }
    949 
    950 static int
    951 labellen(const u_char *lp)
    952 {
    953 	int bitlen;
    954 	u_char l = *lp;
    955 
    956 	if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
    957 		/* should be avoided by the caller */
    958 		return(-1);
    959 	}
    960 
    961 	if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
    962 		if (l == DNS_LABELTYPE_BITSTRING) {
    963 			if ((bitlen = *(lp + 1)) == 0)
    964 				bitlen = 256;
    965 			return((bitlen + 7 ) / 8 + 1);
    966 		}
    967 		return(-1);	/* unknwon ELT */
    968 	}
    969 	return(l);
    970 }
    971