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