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