Annotation of src/lib/libc/nameser/ns_name.c, Revision 1.6
1.6 ! christos 1: /* $NetBSD: ns_name.c,v 1.5 2007/03/30 20:23:03 ghen 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 ! christos 23: static const char rcsid[] = "Id: ns_name.c,v 1.10 2005/04/27 04:56:40 sra Exp";
1.2 christos 24: #else
1.6 ! christos 25: __RCSID("$NetBSD: ns_name.c,v 1.5 2007/03/30 20:23:03 ghen 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.1 christos 131: return(-1);
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;
143: return(-1);
144: }
1.3 christos 145: if ((m = decode_bitstring(&cp, dn, eom)) < 0)
1.1 christos 146: {
147: errno = EMSGSIZE;
148: return(-1);
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: */
207:
208: int
209: ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
210: {
211: u_char *label, *bp, *eom;
212: int c, n, escaped, e = 0;
213: char *cp;
214:
215: escaped = 0;
216: bp = dst;
217: eom = dst + dstsiz;
218: label = bp++;
219:
220: while ((c = *src++) != 0) {
221: if (escaped) {
1.4 christos 222: if (c == '[') { /*%< start a bit string label */
1.1 christos 223: if ((cp = strchr(src, ']')) == NULL) {
1.4 christos 224: errno = EINVAL; /*%< ??? */
1.1 christos 225: return(-1);
226: }
1.3 christos 227: if ((e = encode_bitsring(&src, cp + 2,
228: &label, &bp, eom))
1.1 christos 229: != 0) {
230: errno = e;
231: return(-1);
232: }
233: escaped = 0;
234: label = bp++;
235: if ((c = *src++) == 0)
236: goto done;
237: else if (c != '.') {
238: errno = EINVAL;
239: return(-1);
240: }
241: continue;
242: }
243: else if ((cp = strchr(digits, c)) != NULL) {
244: n = (cp - digits) * 100;
245: if ((c = *src++) == 0 ||
246: (cp = strchr(digits, c)) == NULL) {
247: errno = EMSGSIZE;
248: return (-1);
249: }
250: n += (cp - digits) * 10;
251: if ((c = *src++) == 0 ||
252: (cp = strchr(digits, c)) == NULL) {
253: errno = EMSGSIZE;
254: return (-1);
255: }
256: n += (cp - digits);
257: if (n > 255) {
258: errno = EMSGSIZE;
259: return (-1);
260: }
261: c = n;
262: }
263: escaped = 0;
264: } else if (c == '\\') {
265: escaped = 1;
266: continue;
267: } else if (c == '.') {
268: c = (bp - label - 1);
1.4 christos 269: if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
1.1 christos 270: errno = EMSGSIZE;
271: return (-1);
272: }
273: if (label >= eom) {
274: errno = EMSGSIZE;
275: return (-1);
276: }
277: *label = c;
278: /* Fully qualified ? */
279: if (*src == '\0') {
280: if (c != 0) {
281: if (bp >= eom) {
282: errno = EMSGSIZE;
283: return (-1);
284: }
285: *bp++ = '\0';
286: }
287: if ((bp - dst) > MAXCDNAME) {
288: errno = EMSGSIZE;
289: return (-1);
290: }
291: return (1);
292: }
293: if (c == 0 || *src == '.') {
294: errno = EMSGSIZE;
295: return (-1);
296: }
297: label = bp++;
298: continue;
299: }
300: if (bp >= eom) {
301: errno = EMSGSIZE;
302: return (-1);
303: }
304: *bp++ = (u_char)c;
305: }
306: c = (bp - label - 1);
1.4 christos 307: if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
1.1 christos 308: errno = EMSGSIZE;
309: return (-1);
310: }
311: done:
312: if (label >= eom) {
313: errno = EMSGSIZE;
314: return (-1);
315: }
316: *label = c;
317: if (c != 0) {
318: if (bp >= eom) {
319: errno = EMSGSIZE;
320: return (-1);
321: }
322: *bp++ = 0;
323: }
1.4 christos 324: if ((bp - dst) > MAXCDNAME) { /*%< src too big */
1.1 christos 325: errno = EMSGSIZE;
326: return (-1);
327: }
328: return (0);
329: }
330:
1.4 christos 331: /*%
1.1 christos 332: * Convert a network strings labels into all lowercase.
1.4 christos 333: *
1.1 christos 334: * return:
1.4 christos 335: *\li Number of bytes written to buffer, or -1 (with errno set)
336: *
1.1 christos 337: * notes:
1.4 christos 338: *\li Enforces label and domain length limits.
1.1 christos 339: */
340:
341: int
342: ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz)
343: {
344: const u_char *cp;
345: u_char *dn, *eom;
346: u_char c;
347: u_int n;
348: int l;
349:
350: cp = src;
351: dn = dst;
352: eom = dst + dstsiz;
353:
354: if (dn >= eom) {
355: errno = EMSGSIZE;
356: return (-1);
357: }
358: while ((n = *cp++) != 0) {
359: if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
360: /* Some kind of compression pointer. */
361: errno = EMSGSIZE;
362: return (-1);
363: }
364: *dn++ = n;
365: if ((l = labellen(cp - 1)) < 0) {
366: errno = EMSGSIZE;
367: return (-1);
368: }
369: if (dn + l >= eom) {
370: errno = EMSGSIZE;
371: return (-1);
372: }
1.2 christos 373: for (; l > 0; l--) {
1.1 christos 374: c = *cp++;
375: if (isupper(c))
376: *dn++ = tolower(c);
377: else
378: *dn++ = c;
379: }
380: }
381: *dn++ = '\0';
382: return (dn - dst);
383: }
384:
1.4 christos 385: /*%
1.1 christos 386: * Unpack a domain name from a message, source may be compressed.
1.4 christos 387: *
1.1 christos 388: * return:
1.4 christos 389: *\li -1 if it fails, or consumed octets if it succeeds.
1.1 christos 390: */
391: int
392: ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
393: u_char *dst, size_t dstsiz)
394: {
395: const u_char *srcp, *dstlim;
396: u_char *dstp;
397: int n, len, checked, l;
398:
399: len = -1;
400: checked = 0;
401: dstp = dst;
402: srcp = src;
403: dstlim = dst + dstsiz;
404: if (srcp < msg || srcp >= eom) {
405: errno = EMSGSIZE;
406: return (-1);
407: }
408: /* Fetch next label in domain name. */
409: while ((n = *srcp++) != 0) {
410: /* Check for indirection. */
411: switch (n & NS_CMPRSFLGS) {
412: case 0:
413: case NS_TYPE_ELT:
414: /* Limit checks. */
415: if ((l = labellen(srcp - 1)) < 0) {
416: errno = EMSGSIZE;
417: return(-1);
418: }
419: if (dstp + l + 1 >= dstlim || srcp + l >= eom) {
420: errno = EMSGSIZE;
421: return (-1);
422: }
423: checked += l + 1;
424: *dstp++ = n;
1.2 christos 425: memcpy(dstp, srcp, (size_t)l);
1.1 christos 426: dstp += l;
427: srcp += l;
428: break;
429:
430: case NS_CMPRSFLGS:
431: if (srcp >= eom) {
432: errno = EMSGSIZE;
433: return (-1);
434: }
435: if (len < 0)
436: len = srcp - src + 1;
437: srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
1.4 christos 438: if (srcp < msg || srcp >= eom) { /*%< Out of range. */
1.1 christos 439: errno = EMSGSIZE;
440: return (-1);
441: }
442: checked += 2;
443: /*
444: * Check for loops in the compressed name;
445: * if we've looked at the whole message,
446: * there must be a loop.
447: */
448: if (checked >= eom - msg) {
449: errno = EMSGSIZE;
450: return (-1);
451: }
452: break;
453:
454: default:
455: errno = EMSGSIZE;
1.4 christos 456: return (-1); /*%< flag error */
1.1 christos 457: }
458: }
459: *dstp = '\0';
460: if (len < 0)
461: len = srcp - src;
462: return (len);
463: }
464:
1.4 christos 465: /*%
1.1 christos 466: * Pack domain name 'domain' into 'comp_dn'.
1.4 christos 467: *
1.1 christos 468: * return:
1.4 christos 469: *\li Size of the compressed name, or -1.
470: *
1.1 christos 471: * notes:
1.4 christos 472: *\li 'dnptrs' is an array of pointers to previous compressed names.
473: *\li dnptrs[0] is a pointer to the beginning of the message. The array
1.1 christos 474: * ends with NULL.
1.4 christos 475: *\li 'lastdnptr' is a pointer to the end of the array pointed to
1.1 christos 476: * by 'dnptrs'.
1.4 christos 477: *
1.1 christos 478: * Side effects:
1.4 christos 479: *\li The list of pointers in dnptrs is updated for labels inserted into
1.1 christos 480: * the message as we compress the name. If 'dnptr' is NULL, we don't
481: * try to compress names. If 'lastdnptr' is NULL, we don't update the
482: * list.
483: */
484: int
485: ns_name_pack(const u_char *src, u_char *dst, int dstsiz,
486: const u_char **dnptrs, const u_char **lastdnptr)
487: {
488: u_char *dstp;
489: const u_char **cpp, **lpp, *eob, *msg;
490: const u_char *srcp;
491: int n, l, first = 1;
492:
493: srcp = src;
494: dstp = dst;
495: eob = dstp + dstsiz;
496: lpp = cpp = NULL;
497: if (dnptrs != NULL) {
498: if ((msg = *dnptrs++) != NULL) {
499: for (cpp = dnptrs; *cpp != NULL; cpp++)
1.4 christos 500: continue;
501: lpp = cpp; /*%< end of list to search */
1.1 christos 502: }
503: } else
504: msg = NULL;
505:
506: /* make sure the domain we are about to add is legal */
507: l = 0;
508: do {
509: int l0;
510:
511: n = *srcp;
512: if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
513: errno = EMSGSIZE;
514: return (-1);
515: }
516: if ((l0 = labellen(srcp)) < 0) {
517: errno = EINVAL;
518: return(-1);
519: }
520: l += l0 + 1;
521: if (l > MAXCDNAME) {
522: errno = EMSGSIZE;
523: return (-1);
524: }
525: srcp += l0 + 1;
526: } while (n != 0);
527:
528: /* from here on we need to reset compression pointer array on error */
529: srcp = src;
530: do {
531: /* Look to see if we can use pointers. */
532: n = *srcp;
533: if (n != 0 && msg != NULL) {
534: l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
535: (const u_char * const *)lpp);
536: if (l >= 0) {
537: if (dstp + 1 >= eob) {
538: goto cleanup;
539: }
1.2 christos 540: *dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS;
1.1 christos 541: *dstp++ = l % 256;
542: return (dstp - dst);
543: }
544: /* Not found, save it. */
545: if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
546: (dstp - msg) < 0x4000 && first) {
547: *cpp++ = dstp;
548: *cpp = NULL;
549: first = 0;
550: }
551: }
552: /* copy label to buffer */
553: if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
554: /* Should not happen. */
555: goto cleanup;
556: }
557: n = labellen(srcp);
558: if (dstp + 1 + n >= eob) {
559: goto cleanup;
560: }
1.2 christos 561: memcpy(dstp, srcp, (size_t)(n + 1));
1.1 christos 562: srcp += n + 1;
563: dstp += n + 1;
564: } while (n != 0);
565:
566: if (dstp > eob) {
567: cleanup:
568: if (msg != NULL)
569: *lpp = NULL;
570: errno = EMSGSIZE;
571: return (-1);
572: }
573: return (dstp - dst);
574: }
575:
1.4 christos 576: /*%
1.1 christos 577: * Expand compressed domain name to presentation format.
1.4 christos 578: *
1.1 christos 579: * return:
1.4 christos 580: *\li Number of bytes read out of `src', or -1 (with errno set).
581: *
1.1 christos 582: * note:
1.4 christos 583: *\li Root domain returns as "." not "".
1.1 christos 584: */
585: int
586: ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
587: char *dst, size_t dstsiz)
588: {
589: u_char tmp[NS_MAXCDNAME];
590: int n;
591:
592: if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
593: return (-1);
594: if (ns_name_ntop(tmp, dst, dstsiz) == -1)
595: return (-1);
596: return (n);
597: }
598:
1.4 christos 599: /*%
1.1 christos 600: * Compress a domain name into wire format, using compression pointers.
1.4 christos 601: *
1.1 christos 602: * return:
1.4 christos 603: *\li Number of bytes consumed in `dst' or -1 (with errno set).
604: *
1.1 christos 605: * notes:
1.4 christos 606: *\li 'dnptrs' is an array of pointers to previous compressed names.
607: *\li dnptrs[0] is a pointer to the beginning of the message.
608: *\li The list ends with NULL. 'lastdnptr' is a pointer to the end of the
1.1 christos 609: * array pointed to by 'dnptrs'. Side effect is to update the list of
610: * pointers for labels inserted into the message as we compress the name.
1.4 christos 611: *\li If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
1.1 christos 612: * is NULL, we don't update the list.
613: */
614: int
615: ns_name_compress(const char *src, u_char *dst, size_t dstsiz,
616: const u_char **dnptrs, const u_char **lastdnptr)
617: {
618: u_char tmp[NS_MAXCDNAME];
619:
620: if (ns_name_pton(src, tmp, sizeof tmp) == -1)
621: return (-1);
1.2 christos 622: return (ns_name_pack(tmp, dst, (int)dstsiz, dnptrs, lastdnptr));
1.1 christos 623: }
624:
1.4 christos 625: /*%
1.1 christos 626: * Reset dnptrs so that there are no active references to pointers at or
627: * after src.
628: */
629: void
630: ns_name_rollback(const u_char *src, const u_char **dnptrs,
631: const u_char **lastdnptr)
632: {
633: while (dnptrs < lastdnptr && *dnptrs != NULL) {
634: if (*dnptrs >= src) {
635: *dnptrs = NULL;
636: break;
637: }
638: dnptrs++;
639: }
640: }
641:
1.4 christos 642: /*%
1.1 christos 643: * Advance *ptrptr to skip over the compressed name it points at.
1.4 christos 644: *
1.1 christos 645: * return:
1.4 christos 646: *\li 0 on success, -1 (with errno set) on failure.
1.1 christos 647: */
648: int
649: ns_name_skip(const u_char **ptrptr, const u_char *eom)
650: {
651: const u_char *cp;
652: u_int n;
653: int l;
654:
655: cp = *ptrptr;
656: while (cp < eom && (n = *cp++) != 0) {
657: /* Check for indirection. */
658: switch (n & NS_CMPRSFLGS) {
1.4 christos 659: case 0: /*%< normal case, n == len */
1.1 christos 660: cp += n;
661: continue;
1.4 christos 662: case NS_TYPE_ELT: /*%< EDNS0 extended label */
1.1 christos 663: if ((l = labellen(cp - 1)) < 0) {
1.4 christos 664: errno = EMSGSIZE; /*%< XXX */
1.1 christos 665: return(-1);
666: }
667: cp += l;
668: continue;
1.4 christos 669: case NS_CMPRSFLGS: /*%< indirection */
1.1 christos 670: cp++;
671: break;
1.4 christos 672: default: /*%< illegal type */
1.1 christos 673: errno = EMSGSIZE;
674: return (-1);
675: }
676: break;
677: }
678: if (cp > eom) {
679: errno = EMSGSIZE;
680: return (-1);
681: }
682: *ptrptr = cp;
683: return (0);
684: }
685:
686: /* Private. */
687:
1.4 christos 688: /*%
1.1 christos 689: * Thinking in noninternationalized USASCII (per the DNS spec),
690: * is this characted special ("in need of quoting") ?
1.4 christos 691: *
1.1 christos 692: * return:
1.4 christos 693: *\li boolean.
1.1 christos 694: */
695: static int
696: special(int ch) {
697: switch (ch) {
1.4 christos 698: case 0x22: /*%< '"' */
699: case 0x2E: /*%< '.' */
700: case 0x3B: /*%< ';' */
701: case 0x5C: /*%< '\\' */
702: case 0x28: /*%< '(' */
703: case 0x29: /*%< ')' */
1.1 christos 704: /* Special modifiers in zone files. */
1.4 christos 705: case 0x40: /*%< '@' */
706: case 0x24: /*%< '$' */
1.1 christos 707: return (1);
708: default:
709: return (0);
710: }
711: }
712:
1.4 christos 713: /*%
1.1 christos 714: * Thinking in noninternationalized USASCII (per the DNS spec),
715: * is this character visible and not a space when printed ?
1.4 christos 716: *
1.1 christos 717: * return:
1.4 christos 718: *\li boolean.
1.1 christos 719: */
720: static int
721: printable(int ch) {
722: return (ch > 0x20 && ch < 0x7f);
723: }
724:
1.4 christos 725: /*%
1.1 christos 726: * Thinking in noninternationalized USASCII (per the DNS spec),
727: * convert this character to lower case if it's upper case.
728: */
729: static int
730: mklower(int ch) {
731: if (ch >= 0x41 && ch <= 0x5A)
732: return (ch + 0x20);
733: return (ch);
734: }
735:
1.4 christos 736: /*%
1.1 christos 737: * Search for the counted-label name in an array of compressed names.
1.4 christos 738: *
1.1 christos 739: * return:
1.4 christos 740: *\li offset from msg if found, or -1.
741: *
1.1 christos 742: * notes:
1.4 christos 743: *\li dnptrs is the pointer to the first name on the list,
744: *\li not the pointer to the start of the message.
1.1 christos 745: */
746: static int
747: dn_find(const u_char *domain, const u_char *msg,
748: const u_char * const *dnptrs,
749: const u_char * const *lastdnptr)
750: {
751: const u_char *dn, *cp, *sp;
752: const u_char * const *cpp;
753: u_int n;
754:
755: for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
756: sp = *cpp;
757: /*
758: * terminate search on:
759: * root label
760: * compression pointer
761: * unusable offset
762: */
763: while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
764: (sp - msg) < 0x4000) {
765: dn = domain;
766: cp = sp;
767: while ((n = *cp++) != 0) {
768: /*
769: * check for indirection
770: */
771: switch (n & NS_CMPRSFLGS) {
1.4 christos 772: case 0: /*%< normal case, n == len */
773: n = labellen(cp - 1); /*%< XXX */
1.1 christos 774: if (n != *dn++)
775: goto next;
776:
1.2 christos 777: for (; n > 0; n--)
1.1 christos 778: if (mklower(*dn++) !=
779: mklower(*cp++))
780: goto next;
781: /* Is next root for both ? */
782: if (*dn == '\0' && *cp == '\0')
783: return (sp - msg);
784: if (*dn)
785: continue;
786: goto next;
1.4 christos 787: case NS_CMPRSFLGS: /*%< indirection */
1.1 christos 788: cp = msg + (((n & 0x3f) << 8) | *cp);
789: break;
790:
1.4 christos 791: default: /*%< illegal type */
1.1 christos 792: errno = EMSGSIZE;
793: return (-1);
794: }
795: }
796: next: ;
797: sp += *sp + 1;
798: }
799: }
800: errno = ENOENT;
801: return (-1);
802: }
803:
804: static int
1.3 christos 805: decode_bitstring(const unsigned char **cpp, char *dn, const char *eom)
1.1 christos 806: {
1.3 christos 807: const unsigned char *cp = *cpp;
1.1 christos 808: char *beg = dn, tc;
809: int b, blen, plen, i;
810:
811: if ((blen = (*cp & 0xff)) == 0)
812: blen = 256;
813: plen = (blen + 3) / 4;
814: plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1);
815: if (dn + plen >= eom)
816: return(-1);
817:
818: cp++;
819: i = SPRINTF((dn, "\\[x"));
820: if (i < 0)
821: return (-1);
822: dn += i;
823: for (b = blen; b > 7; b -= 8, cp++) {
824: i = SPRINTF((dn, "%02x", *cp & 0xff));
825: if (i < 0)
826: return (-1);
827: dn += i;
828: }
829: if (b > 4) {
830: tc = *cp++;
831: i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b))));
832: if (i < 0)
833: return (-1);
834: dn += i;
835: } else if (b > 0) {
836: tc = *cp++;
837: i = SPRINTF((dn, "%1x",
1.2 christos 838: (((u_int32_t)tc >> 4) & 0x0f) & (0x0f << (4 - b))));
1.1 christos 839: if (i < 0)
840: return (-1);
841: dn += i;
842: }
843: i = SPRINTF((dn, "/%d]", blen));
844: if (i < 0)
845: return (-1);
846: dn += i;
847:
848: *cpp = cp;
849: return(dn - beg);
850: }
851:
852: static int
1.3 christos 853: encode_bitsring(const char **bp, const char *end, unsigned char **labelp,
854: unsigned char ** dst, unsigned const char *eom)
1.1 christos 855: {
856: int afterslash = 0;
857: const char *cp = *bp;
1.3 christos 858: unsigned char *tp;
859: char c;
1.1 christos 860: const char *beg_blen;
861: char *end_blen = NULL;
862: int value = 0, count = 0, tbcount = 0, blen = 0;
863:
864: beg_blen = end_blen = NULL;
865:
866: /* a bitstring must contain at least 2 characters */
867: if (end - cp < 2)
868: return(EINVAL);
869:
870: /* XXX: currently, only hex strings are supported */
871: if (*cp++ != 'x')
872: return(EINVAL);
1.4 christos 873: if (!isxdigit((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */
1.1 christos 874: return(EINVAL);
875:
876: for (tp = *dst + 1; cp < end && tp < eom; cp++) {
877: switch((c = *cp)) {
1.4 christos 878: case ']': /*%< end of the bitstring */
1.1 christos 879: if (afterslash) {
880: if (beg_blen == NULL)
881: return(EINVAL);
882: blen = (int)strtol(beg_blen, &end_blen, 10);
883: if (*end_blen != ']')
884: return(EINVAL);
885: }
886: if (count)
887: *tp++ = ((value << 4) & 0xff);
1.4 christos 888: cp++; /*%< skip ']' */
1.1 christos 889: goto done;
890: case '/':
891: afterslash = 1;
892: break;
893: default:
894: if (afterslash) {
895: if (!isdigit(c&0xff))
896: return(EINVAL);
897: if (beg_blen == NULL) {
898:
899: if (c == '0') {
900: /* blen never begings with 0 */
901: return(EINVAL);
902: }
903: beg_blen = cp;
904: }
905: } else {
906: if (!isxdigit(c&0xff))
907: return(EINVAL);
908: value <<= 4;
909: value += digitvalue[(int)c];
910: count += 4;
911: tbcount += 4;
912: if (tbcount > 256)
913: return(EINVAL);
914: if (count == 8) {
915: *tp++ = value;
916: count = 0;
917: }
918: }
919: break;
920: }
921: }
922: done:
923: if (cp >= end || tp >= eom)
924: return(EMSGSIZE);
925:
926: /*
927: * bit length validation:
928: * If a <length> is present, the number of digits in the <bit-data>
929: * MUST be just sufficient to contain the number of bits specified
930: * by the <length>. If there are insignificant bits in a final
931: * hexadecimal or octal digit, they MUST be zero.
1.4 christos 932: * RFC2673, Section 3.2.
1.1 christos 933: */
934: if (blen > 0) {
935: int traillen;
936:
937: if (((blen + 3) & ~3) != tbcount)
938: return(EINVAL);
1.4 christos 939: traillen = tbcount - blen; /*%< between 0 and 3 */
1.1 christos 940: if (((value << (8 - traillen)) & 0xff) != 0)
941: return(EINVAL);
942: }
943: else
944: blen = tbcount;
945: if (blen == 256)
946: blen = 0;
947:
948: /* encode the type and the significant bit fields */
949: **labelp = DNS_LABELTYPE_BITSTRING;
950: **dst = blen;
951:
952: *bp = cp;
953: *dst = tp;
954:
955: return(0);
956: }
957:
958: static int
959: labellen(const u_char *lp)
960: {
961: int bitlen;
962: u_char l = *lp;
963:
964: if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
965: /* should be avoided by the caller */
966: return(-1);
967: }
968:
969: if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
970: if (l == DNS_LABELTYPE_BITSTRING) {
971: if ((bitlen = *(lp + 1)) == 0)
972: bitlen = 256;
973: return((bitlen + 7 ) / 8 + 1);
974: }
1.4 christos 975: return(-1); /*%< unknwon ELT */
1.1 christos 976: }
977: return(l);
978: }
1.4 christos 979:
980: /*! \file */
CVSweb <webmaster@jp.NetBSD.org>