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