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