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