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