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