1/*
2 * Copyright (c) 1996,1999 by Internet Software Consortium.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15 * SOFTWARE.
16 */
17
18#ifndef __APPLE__
19#ifndef lint
20static const char rcsid[] = "$Id: ns_name.c,v 1.1 2006/03/01 19:01:36 majka Exp $";
21#endif
22#endif
23
24#ifndef __APPLE__
25#include "port_before.h"
26#endif
27
28#include <sys/types.h>
29
30#include <netinet/in.h>
31#include <arpa/nameser.h>
32
33#include <errno.h>
34#include <resolv.h>
35#include <string.h>
36#include <ctype.h>
37#include <stdlib.h>
38#include <limits.h>
39
40#ifndef __APPLE__
41#include "port_after.h"
42#endif
43
44#ifdef SPRINTF_CHAR
45# define SPRINTF(x) strlen(sprintf/**/x)
46#else
47# define SPRINTF(x) ((size_t)sprintf x)
48#endif
49
50#define NS_TYPE_ELT			0x40 /* EDNS0 extended label type */
51#define DNS_LABELTYPE_BITSTRING		0x41
52
53/* Data. */
54
55static const char	digits[] = "0123456789";
56
57static const char digitvalue[256] = {
58	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	/*16*/
59	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
60	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
61	 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1, /*64*/
62	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
63	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
64	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
65	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
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,
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, /*256*/
74};
75
76/* Forward. */
77
78static int		special(int);
79static int		printable(int);
80static int		dn_find(const u_char *, const u_char *,
81				const u_char * const *,
82				const u_char * const *);
83static int		encode_bitsring(const char **, const char *,
84					char **, char **, const char *);
85static int		labellen(const u_char *);
86static int		decode_bitstring(const char **, char *, const char *);
87
88/* Public. */
89
90/*
91 * ns_name_ntop(src, dst, dstsiz)
92 *	Convert an encoded domain name to printable ascii as per RFC1035.
93 * return:
94 *	Number of bytes written to buffer, or -1 (with errno set)
95 * notes:
96 *	The root is returned as "."
97 *	All other domains are returned in non absolute form
98 */
99int
100ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
101{
102	const u_char *cp;
103	char *dn, *eom;
104	u_char c;
105	u_int n;
106	int l;
107
108	cp = src;
109	dn = dst;
110	eom = dst + dstsiz;
111
112	while ((n = *cp++) != 0) {
113		if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
114			/* Some kind of compression pointer. */
115			errno = EMSGSIZE;
116			return (-1);
117		}
118		if (dn != dst) {
119			if (dn >= eom) {
120				errno = EMSGSIZE;
121				return (-1);
122			}
123			*dn++ = '.';
124		}
125		if ((l = labellen(cp - 1)) < 0) {
126			errno = EMSGSIZE; /* XXX */
127			return(-1);
128		}
129		if (dn + l >= eom) {
130			errno = EMSGSIZE;
131			return (-1);
132		}
133		if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) {
134			int m;
135
136			if (n != DNS_LABELTYPE_BITSTRING) {
137				/* XXX: labellen should reject this case */
138				errno = EINVAL;
139				return(-1);
140			}
141			if ((m = decode_bitstring((const char **)&cp, dn, eom)) < 0)
142			{
143				errno = EMSGSIZE;
144				return(-1);
145			}
146			dn += m;
147			continue;
148		}
149		for ((void)NULL; l > 0; l--) {
150			c = *cp++;
151			if (special(c)) {
152				if (dn + 1 >= eom) {
153					errno = EMSGSIZE;
154					return (-1);
155				}
156				*dn++ = '\\';
157				*dn++ = (char)c;
158			} else if (!printable(c)) {
159				if (dn + 3 >= eom) {
160					errno = EMSGSIZE;
161					return (-1);
162				}
163				*dn++ = '\\';
164				*dn++ = digits[c / 100];
165				*dn++ = digits[(c % 100) / 10];
166				*dn++ = digits[c % 10];
167			} else {
168				if (dn >= eom) {
169					errno = EMSGSIZE;
170					return (-1);
171				}
172				*dn++ = (char)c;
173			}
174		}
175	}
176	if (dn == dst) {
177		if (dn >= eom) {
178			errno = EMSGSIZE;
179			return (-1);
180		}
181		*dn++ = '.';
182	}
183	if (dn >= eom) {
184		errno = EMSGSIZE;
185		return (-1);
186	}
187	*dn++ = '\0';
188	return (dn - dst);
189}
190
191/*
192 * ns_name_pton(src, dst, dstsiz)
193 *	Convert a ascii string into an encoded domain name as per RFC1035.
194 * return:
195 *	-1 if it fails
196 *	1 if string was fully qualified
197 *	0 is string was not fully qualified
198 * notes:
199 *	Enforces label and domain length limits.
200 */
201
202int
203ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
204{
205	u_char *label, *bp, *eom;
206	int c, n, escaped, e = 0;
207	char *cp;
208
209	escaped = 0;
210	bp = dst;
211	eom = dst + dstsiz;
212	label = bp++;
213
214	while ((c = *src++) != 0) {
215		if (escaped) {
216			if (c == '[') { /* start a bit string label */
217				if ((cp = strchr(src, ']')) == NULL) {
218					errno = EINVAL; /* ??? */
219					return(-1);
220				}
221				if ((e = encode_bitsring(&src,
222							 cp + 2,
223							 (char **)&label,
224							 (char **)&bp,
225							 (const char *)eom))
226				    != 0) {
227					errno = e;
228					return(-1);
229				}
230				escaped = 0;
231				label = bp++;
232				if ((c = *src++) == 0)
233					goto done;
234				else if (c != '.') {
235					errno = EINVAL;
236					return(-1);
237				}
238				continue;
239			}
240			else if ((cp = strchr(digits, c)) != NULL) {
241				n = (cp - digits) * 100;
242				if ((c = *src++) == 0 ||
243				    (cp = strchr(digits, c)) == NULL) {
244					errno = EMSGSIZE;
245					return (-1);
246				}
247				n += (cp - digits) * 10;
248				if ((c = *src++) == 0 ||
249				    (cp = strchr(digits, c)) == NULL) {
250					errno = EMSGSIZE;
251					return (-1);
252				}
253				n += (cp - digits);
254				if (n > 255) {
255					errno = EMSGSIZE;
256					return (-1);
257				}
258				c = n;
259			}
260			escaped = 0;
261		} else if (c == '\\') {
262			escaped = 1;
263			continue;
264		} else if (c == '.') {
265			c = (bp - label - 1);
266			if ((c & NS_CMPRSFLGS) != 0) {	/* Label too big. */
267				errno = EMSGSIZE;
268				return (-1);
269			}
270			if (label >= eom) {
271				errno = EMSGSIZE;
272				return (-1);
273			}
274			*label = c;
275			/* Fully qualified ? */
276			if (*src == '\0') {
277				if (c != 0) {
278					if (bp >= eom) {
279						errno = EMSGSIZE;
280						return (-1);
281					}
282					*bp++ = '\0';
283				}
284				if ((bp - dst) > NS_MAXCDNAME) {
285					errno = EMSGSIZE;
286					return (-1);
287				}
288				return (1);
289			}
290			if (c == 0 || *src == '.') {
291				errno = EMSGSIZE;
292				return (-1);
293			}
294			label = bp++;
295			continue;
296		}
297		if (bp >= eom) {
298			errno = EMSGSIZE;
299			return (-1);
300		}
301		*bp++ = (u_char)c;
302	}
303	c = (bp - label - 1);
304	if ((c & NS_CMPRSFLGS) != 0) {		/* Label too big. */
305		errno = EMSGSIZE;
306		return (-1);
307	}
308  done:
309	if (label >= eom) {
310		errno = EMSGSIZE;
311		return (-1);
312	}
313	*label = c;
314	if (c != 0) {
315		if (bp >= eom) {
316			errno = EMSGSIZE;
317			return (-1);
318		}
319		*bp++ = 0;
320	}
321	if ((bp - dst) > NS_MAXCDNAME) {	/* src too big */
322		errno = EMSGSIZE;
323		return (-1);
324	}
325	return (0);
326}
327
328/*
329 * ns_name_ntol(src, dst, dstsiz)
330 *	Convert a network strings labels into all lowercase.
331 * return:
332 *	Number of bytes written to buffer, or -1 (with errno set)
333 * notes:
334 *	Enforces label and domain length limits.
335 */
336
337int
338ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz)
339{
340	const u_char *cp;
341	u_char *dn, *eom;
342	u_char c;
343	u_int n;
344	int l;
345
346	cp = src;
347	dn = dst;
348	eom = dst + dstsiz;
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 */
383int
384ns_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 */
474int
475ns_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 > NS_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) {
557cleanup:
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 */
574int
575ns_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 */
602int
603ns_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 */
617void
618ns_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 */
636int
637ns_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 */
683static int
684special(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 */
708static int
709printable(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 */
717static int
718mklower(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 */
733static int
734dn_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
792static int
793decode_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;
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	dn += SPRINTF((dn, "\\[x"));
808	for (b = blen; b > 7; b -= 8, cp++)
809		dn += SPRINTF((dn, "%02x", *cp & 0xff));
810	if (b > 4) {
811		tc = *cp++;
812		dn += SPRINTF((dn, "%02x", tc & (0xff << (8 - b))));
813	} else if (b > 0) {
814		tc = *cp++;
815		dn += SPRINTF((dn, "%1x",
816			       ((tc >> 4) & 0x0f) & (0x0f << (4 - b))));
817	}
818	dn += SPRINTF((dn, "/%d]", blen));
819
820	*cpp = cp;
821	return(dn - beg);
822}
823
824static int
825encode_bitsring(const char **bp, const char *end, char **labelp,
826	        char ** dst, const char *eom)
827{
828	int afterslash = 0;
829	const char *cp = *bp;
830	char *tp, c;
831	const char *beg_blen;
832	char *end_blen = NULL;
833	int value = 0, count = 0, tbcount = 0, blen = 0;
834
835	beg_blen = end_blen = NULL;
836
837	/* a bitstring must contain at least 2 characters */
838	if (end - cp < 2)
839		return(EINVAL);
840
841	/* XXX: currently, only hex strings are supported */
842	if (*cp++ != 'x')
843		return(EINVAL);
844	if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */
845		return(EINVAL);
846
847	for (tp = *dst + 1; cp < end && tp < eom; cp++) {
848		switch((c = *cp)) {
849		case ']':	/* end of the bitstring */
850			if (afterslash) {
851				if (beg_blen == NULL)
852					return(EINVAL);
853				blen = (int)strtol(beg_blen, &end_blen, 10);
854				if (*end_blen != ']')
855					return(EINVAL);
856			}
857			if (count)
858				*tp++ = ((value << 4) & 0xff);
859			cp++;	/* skip ']' */
860			goto done;
861		case '/':
862			afterslash = 1;
863			break;
864		default:
865			if (afterslash) {
866				if (!isdigit(c&0xff))
867					return(EINVAL);
868				if (beg_blen == NULL) {
869
870					if (c == '0') {
871						/* blen never begings with 0 */
872						return(EINVAL);
873					}
874					beg_blen = cp;
875				}
876			} else {
877				if (!isxdigit(c&0xff))
878					return(EINVAL);
879				value <<= 4;
880				value += digitvalue[(int)c];
881				count += 4;
882				tbcount += 4;
883				if (tbcount > 256)
884					return(EINVAL);
885				if (count == 8) {
886					*tp++ = value;
887					count = 0;
888				}
889			}
890			break;
891		}
892	}
893  done:
894	if (cp >= end || tp >= eom)
895		return(EMSGSIZE);
896
897	/*
898	 * bit length validation:
899	 * If a <length> is present, the number of digits in the <bit-data>
900	 * MUST be just sufficient to contain the number of bits specified
901	 * by the <length>. If there are insignificant bits in a final
902	 * hexadecimal or octal digit, they MUST be zero.
903	 * RFC 2673, Section 3.2.
904	 */
905	if (blen > 0) {
906		int traillen;
907
908		if (((blen + 3) & ~3) != tbcount)
909			return(EINVAL);
910		traillen = tbcount - blen; /* between 0 and 3 */
911		if (((value << (8 - traillen)) & 0xff) != 0)
912			return(EINVAL);
913	}
914	else
915		blen = tbcount;
916	if (blen == 256)
917		blen = 0;
918
919	/* encode the type and the significant bit fields */
920	**labelp = DNS_LABELTYPE_BITSTRING;
921	**dst = blen;
922
923	*bp = cp;
924	*dst = tp;
925
926	return(0);
927}
928
929static int
930labellen(const u_char *lp)
931{
932	int bitlen;
933	u_char l = *lp;
934
935	if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
936		/* should be avoided by the caller */
937		return(-1);
938	}
939
940	if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
941		if (l == DNS_LABELTYPE_BITSTRING) {
942			if ((bitlen = *(lp + 1)) == 0)
943				bitlen = 256;
944			return((bitlen + 7 ) / 8 + 1);
945		}
946		return(-1);	/* unknwon ELT */
947	}
948	return(l);
949}
950