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