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