xref: /netbsd/lib/libc/nameser/ns_name.c (revision 6550d01e)
1 /*	$NetBSD: ns_name.c,v 1.8 2009/04/12 19:43:37 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.11 2009/01/23 19:59:16 each Exp";
24 #else
25 __RCSID("$NetBSD: ns_name.c,v 1.8 2009/04/12 19:43:37 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 int
208 ns_name_pton(const char *src, u_char *dst, size_t dstsiz) {
209 	return (ns_name_pton2(src, dst, dstsiz, NULL));
210 }
211 
212 /*
213  * ns_name_pton2(src, dst, dstsiz, *dstlen)
214  *	Convert a ascii string into an encoded domain name as per RFC1035.
215  * return:
216  *	-1 if it fails
217  *	1 if string was fully qualified
218  *	0 is string was not fully qualified
219  * side effects:
220  *	fills in *dstlen (if non-NULL)
221  * notes:
222  *	Enforces label and domain length limits.
223  */
224 int
225 ns_name_pton2(const char *src, u_char *dst, size_t dstsiz, size_t *dstlen) {
226 	u_char *label, *bp, *eom;
227 	int c, n, escaped, e = 0;
228 	char *cp;
229 
230 	escaped = 0;
231 	bp = dst;
232 	eom = dst + dstsiz;
233 	label = bp++;
234 
235 	while ((c = *src++) != 0) {
236 		if (escaped) {
237 			if (c == '[') { /*%< start a bit string label */
238 				if ((cp = strchr(src, ']')) == NULL) {
239 					errno = EINVAL; /*%< ??? */
240 					return (-1);
241 				}
242 				if ((e = encode_bitsring(&src, cp + 2,
243 							 &label, &bp, eom))
244 				    != 0) {
245 					errno = e;
246 					return (-1);
247 				}
248 				escaped = 0;
249 				label = bp++;
250 				if ((c = *src++) == 0)
251 					goto done;
252 				else if (c != '.') {
253 					errno = EINVAL;
254 					return	(-1);
255 				}
256 				continue;
257 			}
258 			else if ((cp = strchr(digits, c)) != NULL) {
259 				n = (cp - digits) * 100;
260 				if ((c = *src++) == 0 ||
261 				    (cp = strchr(digits, c)) == NULL) {
262 					errno = EMSGSIZE;
263 					return (-1);
264 				}
265 				n += (cp - digits) * 10;
266 				if ((c = *src++) == 0 ||
267 				    (cp = strchr(digits, c)) == NULL) {
268 					errno = EMSGSIZE;
269 					return (-1);
270 				}
271 				n += (cp - digits);
272 				if (n > 255) {
273 					errno = EMSGSIZE;
274 					return (-1);
275 				}
276 				c = n;
277 			}
278 			escaped = 0;
279 		} else if (c == '\\') {
280 			escaped = 1;
281 			continue;
282 		} else if (c == '.') {
283 			c = (bp - label - 1);
284 			if ((c & NS_CMPRSFLGS) != 0) {	/*%< Label too big. */
285 				errno = EMSGSIZE;
286 				return (-1);
287 			}
288 			if (label >= eom) {
289 				errno = EMSGSIZE;
290 				return (-1);
291 			}
292 			*label = c;
293 			/* Fully qualified ? */
294 			if (*src == '\0') {
295 				if (c != 0) {
296 					if (bp >= eom) {
297 						errno = EMSGSIZE;
298 						return (-1);
299 					}
300 					*bp++ = '\0';
301 				}
302 				if ((bp - dst) > MAXCDNAME) {
303 					errno = EMSGSIZE;
304 					return (-1);
305 				}
306 				if (dstlen != NULL)
307 					*dstlen = (bp - dst);
308 				return (1);
309 			}
310 			if (c == 0 || *src == '.') {
311 				errno = EMSGSIZE;
312 				return (-1);
313 			}
314 			label = bp++;
315 			continue;
316 		}
317 		if (bp >= eom) {
318 			errno = EMSGSIZE;
319 			return (-1);
320 		}
321 		*bp++ = (u_char)c;
322 	}
323 	c = (bp - label - 1);
324 	if ((c & NS_CMPRSFLGS) != 0) {		/*%< Label too big. */
325 		errno = EMSGSIZE;
326 		return (-1);
327 	}
328   done:
329 	if (label >= eom) {
330 		errno = EMSGSIZE;
331 		return (-1);
332 	}
333 	*label = c;
334 	if (c != 0) {
335 		if (bp >= eom) {
336 			errno = EMSGSIZE;
337 			return (-1);
338 		}
339 		*bp++ = 0;
340 	}
341 	if ((bp - dst) > MAXCDNAME) {	/*%< src too big */
342 		errno = EMSGSIZE;
343 		return (-1);
344 	}
345 	if (dstlen != NULL)
346 		*dstlen = (bp - dst);
347 	return (0);
348 }
349 
350 /*%
351  *	Convert a network strings labels into all lowercase.
352  *
353  * return:
354  *\li	Number of bytes written to buffer, or -1 (with errno set)
355  *
356  * notes:
357  *\li	Enforces label and domain length limits.
358  */
359 
360 int
361 ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz)
362 {
363 	const u_char *cp;
364 	u_char *dn, *eom;
365 	u_char c;
366 	u_int n;
367 	int l;
368 
369 	cp = src;
370 	dn = dst;
371 	eom = dst + dstsiz;
372 
373 	if (dn >= eom) {
374 		errno = EMSGSIZE;
375 		return (-1);
376 	}
377 	while ((n = *cp++) != 0) {
378 		if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
379 			/* Some kind of compression pointer. */
380 			errno = EMSGSIZE;
381 			return (-1);
382 		}
383 		*dn++ = n;
384 		if ((l = labellen(cp - 1)) < 0) {
385 			errno = EMSGSIZE;
386 			return (-1);
387 		}
388 		if (dn + l >= eom) {
389 			errno = EMSGSIZE;
390 			return (-1);
391 		}
392 		for (; l > 0; l--) {
393 			c = *cp++;
394 			if (isascii(c) && isupper(c))
395 				*dn++ = tolower(c);
396 			else
397 				*dn++ = c;
398 		}
399 	}
400 	*dn++ = '\0';
401 	return (dn - dst);
402 }
403 
404 /*%
405  *	Unpack a domain name from a message, source may be compressed.
406  *
407  * return:
408  *\li	-1 if it fails, or consumed octets if it succeeds.
409  */
410 int
411 ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
412 	       u_char *dst, size_t dstsiz)
413 {
414 	return (ns_name_unpack2(msg, eom, src, dst, dstsiz, NULL));
415 }
416 
417 /*
418  * ns_name_unpack2(msg, eom, src, dst, dstsiz, *dstlen)
419  *	Unpack a domain name from a message, source may be compressed.
420  * return:
421  *	-1 if it fails, or consumed octets if it succeeds.
422  * side effect:
423  *	fills in *dstlen (if non-NULL).
424  */
425 int
426 ns_name_unpack2(const u_char *msg, const u_char *eom, const u_char *src,
427 		u_char *dst, size_t dstsiz, size_t *dstlen)
428 {
429 	const u_char *srcp, *dstlim;
430 	u_char *dstp;
431 	int n, len, checked, l;
432 
433 	len = -1;
434 	checked = 0;
435 	dstp = dst;
436 	srcp = src;
437 	dstlim = dst + dstsiz;
438 	if (srcp < msg || srcp >= eom) {
439 		errno = EMSGSIZE;
440 		return (-1);
441 	}
442 	/* Fetch next label in domain name. */
443 	while ((n = *srcp++) != 0) {
444 		/* Check for indirection. */
445 		switch (n & NS_CMPRSFLGS) {
446 		case 0:
447 		case NS_TYPE_ELT:
448 			/* Limit checks. */
449 			if ((l = labellen(srcp - 1)) < 0) {
450 				errno = EMSGSIZE;
451 				return (-1);
452 			}
453 			if (dstp + l + 1 >= dstlim || srcp + l >= eom) {
454 				errno = EMSGSIZE;
455 				return (-1);
456 			}
457 			checked += l + 1;
458 			*dstp++ = n;
459 			memcpy(dstp, srcp, (size_t)l);
460 			dstp += l;
461 			srcp += l;
462 			break;
463 
464 		case NS_CMPRSFLGS:
465 			if (srcp >= eom) {
466 				errno = EMSGSIZE;
467 				return (-1);
468 			}
469 			if (len < 0)
470 				len = srcp - src + 1;
471 			srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
472 			if (srcp < msg || srcp >= eom) {  /*%< Out of range. */
473 				errno = EMSGSIZE;
474 				return (-1);
475 			}
476 			checked += 2;
477 			/*
478 			 * Check for loops in the compressed name;
479 			 * if we've looked at the whole message,
480 			 * there must be a loop.
481 			 */
482 			if (checked >= eom - msg) {
483 				errno = EMSGSIZE;
484 				return (-1);
485 			}
486 			break;
487 
488 		default:
489 			errno = EMSGSIZE;
490 			return (-1);			/*%< flag error */
491 		}
492 	}
493 	*dstp++ = 0;
494 	if (dstlen != NULL)
495 		*dstlen = dstp - dst;
496 	if (len < 0)
497 		len = srcp - src;
498 	return (len);
499 }
500 
501 /*%
502  *	Pack domain name 'domain' into 'comp_dn'.
503  *
504  * return:
505  *\li	Size of the compressed name, or -1.
506  *
507  * notes:
508  *\li	'dnptrs' is an array of pointers to previous compressed names.
509  *\li	dnptrs[0] is a pointer to the beginning of the message. The array
510  *	ends with NULL.
511  *\li	'lastdnptr' is a pointer to the end of the array pointed to
512  *	by 'dnptrs'.
513  *
514  * Side effects:
515  *\li	The list of pointers in dnptrs is updated for labels inserted into
516  *	the message as we compress the name.  If 'dnptr' is NULL, we don't
517  *	try to compress names. If 'lastdnptr' is NULL, we don't update the
518  *	list.
519  */
520 int
521 ns_name_pack(const u_char *src, u_char *dst, int dstsiz,
522 	     const u_char **dnptrs, const u_char **lastdnptr)
523 {
524 	u_char *dstp;
525 	const u_char **cpp, **lpp, *eob, *msg;
526 	const u_char *srcp;
527 	int n, l, first = 1;
528 
529 	srcp = src;
530 	dstp = dst;
531 	eob = dstp + dstsiz;
532 	lpp = cpp = NULL;
533 	if (dnptrs != NULL) {
534 		if ((msg = *dnptrs++) != NULL) {
535 			for (cpp = dnptrs; *cpp != NULL; cpp++)
536 				continue;
537 			lpp = cpp;	/*%< end of list to search */
538 		}
539 	} else
540 		msg = NULL;
541 
542 	/* make sure the domain we are about to add is legal */
543 	l = 0;
544 	do {
545 		int l0;
546 
547 		n = *srcp;
548 		if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
549 			errno = EMSGSIZE;
550 			return (-1);
551 		}
552 		if ((l0 = labellen(srcp)) < 0) {
553 			errno = EINVAL;
554 			return (-1);
555 		}
556 		l += l0 + 1;
557 		if (l > MAXCDNAME) {
558 			errno = EMSGSIZE;
559 			return (-1);
560 		}
561 		srcp += l0 + 1;
562 	} while (n != 0);
563 
564 	/* from here on we need to reset compression pointer array on error */
565 	srcp = src;
566 	do {
567 		/* Look to see if we can use pointers. */
568 		n = *srcp;
569 		if (n != 0 && msg != NULL) {
570 			l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
571 				    (const u_char * const *)lpp);
572 			if (l >= 0) {
573 				if (dstp + 1 >= eob) {
574 					goto cleanup;
575 				}
576 				*dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS;
577 				*dstp++ = l % 256;
578 				return (dstp - dst);
579 			}
580 			/* Not found, save it. */
581 			if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
582 			    (dstp - msg) < 0x4000 && first) {
583 				*cpp++ = dstp;
584 				*cpp = NULL;
585 				first = 0;
586 			}
587 		}
588 		/* copy label to buffer */
589 		if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
590 			/* Should not happen. */
591 			goto cleanup;
592 		}
593 		n = labellen(srcp);
594 		if (dstp + 1 + n >= eob) {
595 			goto cleanup;
596 		}
597 		memcpy(dstp, srcp, (size_t)(n + 1));
598 		srcp += n + 1;
599 		dstp += n + 1;
600 	} while (n != 0);
601 
602 	if (dstp > eob) {
603 cleanup:
604 		if (msg != NULL)
605 			*lpp = NULL;
606 		errno = EMSGSIZE;
607 		return (-1);
608 	}
609 	return (dstp - dst);
610 }
611 
612 /*%
613  *	Expand compressed domain name to presentation format.
614  *
615  * return:
616  *\li	Number of bytes read out of `src', or -1 (with errno set).
617  *
618  * note:
619  *\li	Root domain returns as "." not "".
620  */
621 int
622 ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
623 		   char *dst, size_t dstsiz)
624 {
625 	u_char tmp[NS_MAXCDNAME];
626 	int n;
627 
628 	if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
629 		return (-1);
630 	if (ns_name_ntop(tmp, dst, dstsiz) == -1)
631 		return (-1);
632 	return (n);
633 }
634 
635 /*%
636  *	Compress a domain name into wire format, using compression pointers.
637  *
638  * return:
639  *\li	Number of bytes consumed in `dst' or -1 (with errno set).
640  *
641  * notes:
642  *\li	'dnptrs' is an array of pointers to previous compressed names.
643  *\li	dnptrs[0] is a pointer to the beginning of the message.
644  *\li	The list ends with NULL.  'lastdnptr' is a pointer to the end of the
645  *	array pointed to by 'dnptrs'. Side effect is to update the list of
646  *	pointers for labels inserted into the message as we compress the name.
647  *\li	If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
648  *	is NULL, we don't update the list.
649  */
650 int
651 ns_name_compress(const char *src, u_char *dst, size_t dstsiz,
652 		 const u_char **dnptrs, const u_char **lastdnptr)
653 {
654 	u_char tmp[NS_MAXCDNAME];
655 
656 	if (ns_name_pton(src, tmp, sizeof tmp) == -1)
657 		return (-1);
658 	return (ns_name_pack(tmp, dst, (int)dstsiz, dnptrs, lastdnptr));
659 }
660 
661 /*%
662  * Reset dnptrs so that there are no active references to pointers at or
663  * after src.
664  */
665 void
666 ns_name_rollback(const u_char *src, const u_char **dnptrs,
667 		 const u_char **lastdnptr)
668 {
669 	while (dnptrs < lastdnptr && *dnptrs != NULL) {
670 		if (*dnptrs >= src) {
671 			*dnptrs = NULL;
672 			break;
673 		}
674 		dnptrs++;
675 	}
676 }
677 
678 /*%
679  *	Advance *ptrptr to skip over the compressed name it points at.
680  *
681  * return:
682  *\li	0 on success, -1 (with errno set) on failure.
683  */
684 int
685 ns_name_skip(const u_char **ptrptr, const u_char *eom)
686 {
687 	const u_char *cp;
688 	u_int n;
689 	int l;
690 
691 	cp = *ptrptr;
692 	while (cp < eom && (n = *cp++) != 0) {
693 		/* Check for indirection. */
694 		switch (n & NS_CMPRSFLGS) {
695 		case 0:			/*%< normal case, n == len */
696 			cp += n;
697 			continue;
698 		case NS_TYPE_ELT: /*%< EDNS0 extended label */
699 			if ((l = labellen(cp - 1)) < 0) {
700 				errno = EMSGSIZE; /*%< XXX */
701 				return (-1);
702 			}
703 			cp += l;
704 			continue;
705 		case NS_CMPRSFLGS:	/*%< indirection */
706 			cp++;
707 			break;
708 		default:		/*%< illegal type */
709 			errno = EMSGSIZE;
710 			return (-1);
711 		}
712 		break;
713 	}
714 	if (cp > eom) {
715 		errno = EMSGSIZE;
716 		return (-1);
717 	}
718 	*ptrptr = cp;
719 	return (0);
720 }
721 
722 /* Find the number of octets an nname takes up, including the root label.
723  * (This is basically ns_name_skip() without compression-pointer support.)
724  * ((NOTE: can only return zero if passed-in namesiz argument is zero.))
725  */
726 ssize_t
727 ns_name_length(ns_nname_ct nname, size_t namesiz) {
728 	ns_nname_ct orig = nname;
729 	u_int n;
730 
731 	while (namesiz-- > 0 && (n = *nname++) != 0) {
732 		if ((n & NS_CMPRSFLGS) != 0) {
733 			errno = EISDIR;
734 			return (-1);
735 		}
736 		if (n > namesiz) {
737 			errno = EMSGSIZE;
738 			return (-1);
739 		}
740 		nname += n;
741 		namesiz -= n;
742 	}
743 	return (nname - orig);
744 }
745 
746 /* Compare two nname's for equality.  Return -1 on error (setting errno).
747  */
748 int
749 ns_name_eq(ns_nname_ct a, size_t as, ns_nname_ct b, size_t bs) {
750 	ns_nname_ct ae = a + as, be = b + bs;
751 	int ac, bc;
752 
753 	while (ac = *a, bc = *b, ac != 0 && bc != 0) {
754 		if ((ac & NS_CMPRSFLGS) != 0 || (bc & NS_CMPRSFLGS) != 0) {
755 			errno = EISDIR;
756 			return (-1);
757 		}
758 		if (a + ac >= ae || b + bc >= be) {
759 			errno = EMSGSIZE;
760 			return (-1);
761 		}
762 		if (ac != bc || strncasecmp((const char *) ++a,
763 					    (const char *) ++b,
764 					    (size_t)ac) != 0)
765 			return (0);
766 		a += ac, b += bc;
767 	}
768 	return (ac == 0 && bc == 0);
769 }
770 
771 /* Is domain "A" owned by (at or below) domain "B"?
772  */
773 int
774 ns_name_owned(ns_namemap_ct a, int an, ns_namemap_ct b, int bn) {
775 	/* If A is shorter, it cannot be owned by B. */
776 	if (an < bn)
777 		return (0);
778 
779 	/* If they are unequal before the length of the shorter, A cannot... */
780 	while (bn > 0) {
781 		if (a->len != b->len ||
782 		    strncasecmp((const char *) a->base,
783 				(const char *) b->base, (size_t)a->len) != 0)
784 			return (0);
785 		a++, an--;
786 		b++, bn--;
787 	}
788 
789 	/* A might be longer or not, but either way, B owns it. */
790 	return (1);
791 }
792 
793 /* Build an array of <base,len> tuples from an nname, top-down order.
794  * Return the number of tuples (labels) thus discovered.
795  */
796 int
797 ns_name_map(ns_nname_ct nname, size_t namelen, ns_namemap_t map, int mapsize) {
798 	u_int n;
799 	int l;
800 
801 	n = *nname++;
802 	namelen--;
803 
804 	/* Root zone? */
805 	if (n == 0) {
806 		/* Extra data follows name? */
807 		if (namelen > 0) {
808 			errno = EMSGSIZE;
809 			return (-1);
810 		}
811 		return (0);
812 	}
813 
814 	/* Compression pointer? */
815 	if ((n & NS_CMPRSFLGS) != 0) {
816 		errno = EISDIR;
817 		return (-1);
818 	}
819 
820 	/* Label too long? */
821 	if (n > namelen) {
822 		errno = EMSGSIZE;
823 		return (-1);
824 	}
825 
826 	/* Recurse to get rest of name done first. */
827 	l = ns_name_map(nname + n, namelen - n, map, mapsize);
828 	if (l < 0)
829 		return (-1);
830 
831 	/* Too many labels? */
832 	if (l >= mapsize) {
833 		errno = ENAMETOOLONG;
834 		return (-1);
835 	}
836 
837 	/* We're on our way back up-stack, store current map data. */
838 	map[l].base = nname;
839 	map[l].len = n;
840 	return (l + 1);
841 }
842 
843 /* Count the labels in a domain name.  Root counts, so COM. has two.  This
844  * is to make the result comparable to the result of ns_name_map().
845  */
846 int
847 ns_name_labels(ns_nname_ct nname, size_t namesiz) {
848 	int ret = 0;
849 	u_int n;
850 
851 	while (namesiz-- > 0 && (n = *nname++) != 0) {
852 		if ((n & NS_CMPRSFLGS) != 0) {
853 			errno = EISDIR;
854 			return (-1);
855 		}
856 		if (n > namesiz) {
857 			errno = EMSGSIZE;
858 			return (-1);
859 		}
860 		nname += n;
861 		namesiz -= n;
862 		ret++;
863 	}
864 	return (ret + 1);
865 }
866 
867 /* Private. */
868 
869 /*%
870  *	Thinking in noninternationalized USASCII (per the DNS spec),
871  *	is this characted special ("in need of quoting") ?
872  *
873  * return:
874  *\li	boolean.
875  */
876 static int
877 special(int ch) {
878 	switch (ch) {
879 	case 0x22: /*%< '"' */
880 	case 0x2E: /*%< '.' */
881 	case 0x3B: /*%< ';' */
882 	case 0x5C: /*%< '\\' */
883 	case 0x28: /*%< '(' */
884 	case 0x29: /*%< ')' */
885 	/* Special modifiers in zone files. */
886 	case 0x40: /*%< '@' */
887 	case 0x24: /*%< '$' */
888 		return (1);
889 	default:
890 		return (0);
891 	}
892 }
893 
894 /*%
895  *	Thinking in noninternationalized USASCII (per the DNS spec),
896  *	is this character visible and not a space when printed ?
897  *
898  * return:
899  *\li	boolean.
900  */
901 static int
902 printable(int ch) {
903 	return (ch > 0x20 && ch < 0x7f);
904 }
905 
906 /*%
907  *	Thinking in noninternationalized USASCII (per the DNS spec),
908  *	convert this character to lower case if it's upper case.
909  */
910 static int
911 mklower(int ch) {
912 	if (ch >= 0x41 && ch <= 0x5A)
913 		return (ch + 0x20);
914 	return (ch);
915 }
916 
917 /*%
918  *	Search for the counted-label name in an array of compressed names.
919  *
920  * return:
921  *\li	offset from msg if found, or -1.
922  *
923  * notes:
924  *\li	dnptrs is the pointer to the first name on the list,
925  *\li	not the pointer to the start of the message.
926  */
927 static int
928 dn_find(const u_char *domain, const u_char *msg,
929 	const u_char * const *dnptrs,
930 	const u_char * const *lastdnptr)
931 {
932 	const u_char *dn, *cp, *sp;
933 	const u_char * const *cpp;
934 	u_int n;
935 
936 	for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
937 		sp = *cpp;
938 		/*
939 		 * terminate search on:
940 		 * root label
941 		 * compression pointer
942 		 * unusable offset
943 		 */
944 		while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
945 		       (sp - msg) < 0x4000) {
946 			dn = domain;
947 			cp = sp;
948 			while ((n = *cp++) != 0) {
949 				/*
950 				 * check for indirection
951 				 */
952 				switch (n & NS_CMPRSFLGS) {
953 				case 0:		/*%< normal case, n == len */
954 					n = labellen(cp - 1); /*%< XXX */
955 					if (n != *dn++)
956 						goto next;
957 
958 					for (; n > 0; n--)
959 						if (mklower(*dn++) !=
960 						    mklower(*cp++))
961 							goto next;
962 					/* Is next root for both ? */
963 					if (*dn == '\0' && *cp == '\0')
964 						return (sp - msg);
965 					if (*dn)
966 						continue;
967 					goto next;
968 				case NS_CMPRSFLGS:	/*%< indirection */
969 					cp = msg + (((n & 0x3f) << 8) | *cp);
970 					break;
971 
972 				default:	/*%< illegal type */
973 					errno = EMSGSIZE;
974 					return (-1);
975 				}
976 			}
977  next: ;
978 			sp += *sp + 1;
979 		}
980 	}
981 	errno = ENOENT;
982 	return (-1);
983 }
984 
985 static int
986 decode_bitstring(const unsigned char **cpp, char *dn, const char *eom)
987 {
988 	const unsigned char *cp = *cpp;
989 	char *beg = dn, tc;
990 	int b, blen, plen, i;
991 
992 	if ((blen = (*cp & 0xff)) == 0)
993 		blen = 256;
994 	plen = (blen + 3) / 4;
995 	plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1);
996 	if (dn + plen >= eom)
997 		return (-1);
998 
999 	cp++;
1000 	i = SPRINTF((dn, "\\[x"));
1001 	if (i < 0)
1002 		return (-1);
1003 	dn += i;
1004 	for (b = blen; b > 7; b -= 8, cp++) {
1005 		i = SPRINTF((dn, "%02x", *cp & 0xff));
1006 		if (i < 0)
1007 			return (-1);
1008 		dn += i;
1009 	}
1010 	if (b > 4) {
1011 		tc = *cp++;
1012 		i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b))));
1013 		if (i < 0)
1014 			return (-1);
1015 		dn += i;
1016 	} else if (b > 0) {
1017 		tc = *cp++;
1018 		i = SPRINTF((dn, "%1x",
1019 			       (((u_int32_t)tc >> 4) & 0x0f) & (0x0f << (4 - b))));
1020 		if (i < 0)
1021 			return (-1);
1022 		dn += i;
1023 	}
1024 	i = SPRINTF((dn, "/%d]", blen));
1025 	if (i < 0)
1026 		return (-1);
1027 	dn += i;
1028 
1029 	*cpp = cp;
1030 	return (dn - beg);
1031 }
1032 
1033 static int
1034 encode_bitsring(const char **bp, const char *end, unsigned char **labelp,
1035 		unsigned char ** dst, unsigned const char *eom)
1036 {
1037 	int afterslash = 0;
1038 	const char *cp = *bp;
1039 	unsigned char *tp;
1040 	char c;
1041 	const char *beg_blen;
1042 	char *end_blen = NULL;
1043 	int value = 0, count = 0, tbcount = 0, blen = 0;
1044 
1045 	beg_blen = end_blen = NULL;
1046 
1047 	/* a bitstring must contain at least 2 characters */
1048 	if (end - cp < 2)
1049 		return (EINVAL);
1050 
1051 	/* XXX: currently, only hex strings are supported */
1052 	if (*cp++ != 'x')
1053 		return (EINVAL);
1054 	if (!isxdigit((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */
1055 		return (EINVAL);
1056 
1057 	for (tp = *dst + 1; cp < end && tp < eom; cp++) {
1058 		switch((c = *cp)) {
1059 		case ']':	/*%< end of the bitstring */
1060 			if (afterslash) {
1061 				if (beg_blen == NULL)
1062 					return (EINVAL);
1063 				blen = (int)strtol(beg_blen, &end_blen, 10);
1064 				if (*end_blen != ']')
1065 					return (EINVAL);
1066 			}
1067 			if (count)
1068 				*tp++ = ((value << 4) & 0xff);
1069 			cp++;	/*%< skip ']' */
1070 			goto done;
1071 		case '/':
1072 			afterslash = 1;
1073 			break;
1074 		default:
1075 			if (afterslash) {
1076 				if (!isdigit(c&0xff))
1077 					return (EINVAL);
1078 				if (beg_blen == NULL) {
1079 
1080 					if (c == '0') {
1081 						/* blen never begings with 0 */
1082 						return (EINVAL);
1083 					}
1084 					beg_blen = cp;
1085 				}
1086 			} else {
1087 				if (!isxdigit(c&0xff))
1088 					return (EINVAL);
1089 				value <<= 4;
1090 				value += digitvalue[(int)c];
1091 				count += 4;
1092 				tbcount += 4;
1093 				if (tbcount > 256)
1094 					return (EINVAL);
1095 				if (count == 8) {
1096 					*tp++ = value;
1097 					count = 0;
1098 				}
1099 			}
1100 			break;
1101 		}
1102 	}
1103   done:
1104 	if (cp >= end || tp >= eom)
1105 		return (EMSGSIZE);
1106 
1107 	/*
1108 	 * bit length validation:
1109 	 * If a <length> is present, the number of digits in the <bit-data>
1110 	 * MUST be just sufficient to contain the number of bits specified
1111 	 * by the <length>. If there are insignificant bits in a final
1112 	 * hexadecimal or octal digit, they MUST be zero.
1113 	 * RFC2673, Section 3.2.
1114 	 */
1115 	if (blen > 0) {
1116 		int traillen;
1117 
1118 		if (((blen + 3) & ~3) != tbcount)
1119 			return (EINVAL);
1120 		traillen = tbcount - blen; /*%< between 0 and 3 */
1121 		if (((value << (8 - traillen)) & 0xff) != 0)
1122 			return (EINVAL);
1123 	}
1124 	else
1125 		blen = tbcount;
1126 	if (blen == 256)
1127 		blen = 0;
1128 
1129 	/* encode the type and the significant bit fields */
1130 	**labelp = DNS_LABELTYPE_BITSTRING;
1131 	**dst = blen;
1132 
1133 	*bp = cp;
1134 	*dst = tp;
1135 
1136 	return (0);
1137 }
1138 
1139 static int
1140 labellen(const u_char *lp)
1141 {
1142 	int bitlen;
1143 	u_char l = *lp;
1144 
1145 	if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
1146 		/* should be avoided by the caller */
1147 		return (-1);
1148 	}
1149 
1150 	if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
1151 		if (l == DNS_LABELTYPE_BITSTRING) {
1152 			if ((bitlen = *(lp + 1)) == 0)
1153 				bitlen = 256;
1154 			return ((bitlen + 7 ) / 8 + 1);
1155 		}
1156 		return (-1);	/*%< unknwon ELT */
1157 	}
1158 	return (l);
1159 }
1160 
1161 /*! \file */
1162