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